도커
마이그레이션 명령어 : npm run prisma:migrate
이미 있어서 안된다고 하면 npx prisma migrate reset
도커
마이그레이션 명령어 : npm run prisma:migrate
이미 있어서 안된다고 하면 npx prisma migrate reset
1. 개인정보의 처리 목적 ‘SLGCompany' 은(는) 다음의 목적을 위하여 개인정보를 처리하고 있으며, 다음의 목적 이외의 용도로는 이용하지 않습니다.
- 고객 가입의사 확인, 고객에 대한 서비스 제공에 따른 본인 식별.인증, 회원자격 유지.관리, 물품 또는 서비스 공급에 따른 금액 결제, 물품 또는 서비스의 공급.배송 등
2. 개인정보의 처리 및 보유 기간① ‘SLGCompany' 은(는) 정보주체로부터 개인정보를 수집할 때 동의 받은 개인정보 보유․이용기간 또는 법령에 따른 개인정보 보유․이용기간 내에서 개인정보를 처리․보유합니다.② 구체적인 개인정보 처리 및 보유 기간은 다음과 같습니다.☞ 아래 예시를 참고하여 개인정보 처리업무와 개인정보 처리업무에 대한 보유기간 및 관련 법령, 근거 등을 기재합니다.(예시)- 고객 가입 및 관리 : 서비스 이용계약 또는 회원가입 해지시까지, 다만 채권․채무관계 잔존시에는 해당 채권․채무관계 정산시까지- 전자상거래에서의 계약․청약철회, 대금결제, 재화 등 공급기록 : 5년
3. 정보주체와 법정대리인의 권리·의무 및 그 행사방법 이용자는 개인정보주체로써 다음과 같은 권리를 행사할 수 있습니다.① 정보주체는 ‘SLGCompany' 에 대해 언제든지 다음 각 호의 개인정보 보호 관련 권리를 행사할 수 있습니다.1. 개인정보 열람요구2. 오류 등이 있을 경우 정정 요구3. 삭제요구
4. 처리정지 요구4. 처리하는 개인정보의 항목 작성① ‘ SLGCompany ' 은(는) 다음의 개인정보 항목을 처리하고 있습니다.1<없음>필수항목 : 없음- 선택항목 : 없음
5. 개인정보의 파기 ‘ SLGCompany ' 원칙적으로 개인정보 처리목적이 달성된 경우에는 지체없이 해당 개인정보를 파기합니다. 파기의 절차, 기한 및 방법은 다음과 같습니다.-파기절차이용자가 입력한 정보는 목적 달성 후 별도의 DB에 옮겨져(종이의 경우 별도의 서류) 내부 방침 및 기타 관련 법령에 따라 일정기간 저장된 후 혹은 즉시 파기됩니다. 이 때, DB로 옮겨진 개인정보는 법률에 의한 경우가 아니고서는 다른 목적으로 이용되지 않습니다.-파기기한이용자의 개인정보는 개인정보의 보유기간이 경과된 경우에는 보유기간의 종료일로부터 5일 이내에, 개인정보의 처리 목적 달성, 해당 서비스의 폐지, 사업의 종료 등 그 개인정보가 불필요하게 되었을 때에는 개인정보의 처리가 불필요한 것으로 인정되는 날로부터 5일 이내에 그 개인정보를 파기합니다.
6. 개인정보 자동 수집 장치의 설치•운영 및 거부에 관한 사항 ‘ SLGCompany ' 은 정보주체의 이용정보를 저장하고 수시로 불러오는 ‘쿠키’를 사용하지 않습니다.
7. 개인정보 보호책임자 작성① ‘ SLGCompany ' 은(는) 개인정보 처리에 관한 업무를 총괄해서 책임지고, 개인정보 처리와 관련한 정보주체의 불만처리 및 피해구제 등을 위하여 아래와 같이 개인정보 보호책임자를 지정하고 있습니다.▶ 개인정보 보호책임자성명 : SLGCompany 직책 :대표직급 :대표연락처 : handock879@gmail.com※ 개인정보 보호 담당부서로 연결됩니다.▶ 개인정보 보호 담당부서부서명 : 보안팀담당자 : 대표연락처 : ② 정보주체께서는 SLGCompany 의 서비스(또는 사업)을 이용하시면서 발생한 모든 개인정보 보호 관련 문의, 불만처리, 피해구제 등에 관한 사항을 개인정보 보호책임자 및 담당부서로 문의하실 수 있습니다. SLGCompany 은(는) 정보주체의 문의에 대해 지체 없이 답변 및 처리해드릴 것입니다.
8. 개인정보 처리방침 변경①이 개인정보처리방침은 시행일로부터 적용되며, 법령 및 방침에 따른 변경내용의 추가, 삭제 및 정정이 있는 경우에는 변경사항의 시행 7일 전부터 공지사항을 통하여 고지할 것입니다.
9. 개인정보의 안전성 확보 조치 SLGCompany 은(는) 개인정보보호법 제29조에 따라 다음과 같이 안전성 확보에 필요한 기술적/관리적 및 물리적 조치를 하고 있습니다.
10. 개인정보 취급 직원의 최소화 및 교육개인정보를 취급하는 직원을 지정하고 담당자에 한정시켜 최소화 하여 개인정보를 관리하는 대책을 시행하고 있습니다.
11. 문서보안을 위한 잠금장치 사용개인정보가 포함된 서류, 보조저장매체 등을 잠금장치가 있는 안전한 장소에 보관하고 있습니다.
12. 비인가자에 대한 출입 통제개인정보를 보관하고 있는 물리적 보관 장소를 별도로 두고 이에 대해 출입통제 절차를 수립, 운영하고 있습니다.
Unity 프로젝트에 에셋을 임포트 할 때, Built-In 환경에서 작업된 에셋들이 URP 환경에서는 쉐이더가 깨지는 문제를 종종 겪게 됩니다. 이 글에서는 이러한 문제를 해결하는 방법을 정리하였습니다.

에셋을 임포트한 후, 프로젝트 내에서 쉐이더가 깨진 모습을 볼 수 있습니다. 이는 주로 핑크빛 에러로 나타나며, 이는 쉐이더가 올바르게 작동하지 않는다는 것을 의미합니다.



각 프리팹의 깨진 쉐이더를 URP 쉐이더로 변경하는 방법입니다.



쉐이더 변경 후에도 텍스처가 빠져 있는 경우가 발생할 수 있습니다. 이 경우, 텍스처를 다시 적용해 줍니다.




모든 프리팹에 대해 위 작업을 수동으로 하기에는 무리가 있습니다. 이를 해결하기 위해 일본분이 정리해주신 자동으로 쉐이더를 변환하는 방법을 소개합니다.
[Unity]3Dオブジェクトがピンク色になった時の解決方法 #URP - Qiita
[Unity]3Dオブジェクトがピンク色になった時の解決方法 - Qiita
概要3DオブジェクトのAssetがピンク色になってしまう事、よくあると思います。ここで説明するのは、URP環境のアプリを作ろうとしている方を対象にしています。2022年10月2日 操作説明をわ
qiita.com


.


이 과정을 통해 Unity가 다시 임포팅을 시작하며, 모든 프리팹의 쉐이더가 URP 쉐이더로 자동 변환됩니다. 변환 후에는 정상적으로 프리팹이 보이게 됩니다.


| [Unity Error - 해결] 빌드 에러 Android SDK is missing required plaform API (0) | 2024.04.03 |
|---|---|
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #2 (MySQL) (0) | 2023.12.01 |
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #1 (MySQL) (2) | 2023.11.30 |
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
Win32Exception: ApplicationName='powershell', CommandLine='-ExecutionPolicy Bypass -File "C:/Program Files/Unity/Hub/Editor/2022.3.8f1/Editor/Data/PlaybackEngines/AndroidPlayer/Tools\RunElevatedCommand.ps1" -ArgumentList Ignored "C:\Program Files\Unity\Hub\Editor\2022.3.8f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\cmdline-tools\6.0\bin\sdkmanager.bat" "C:\Program Files\Unity\Hub\Editor\2022.3.8f1\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK" ""platforms;android-33"" "I:\SampleProject\Temp\AndroidSDKTool"', CurrentDirectory='', Native error= 지정된 파일을 찾을 수 없습니다.
System.Diagnostics.Process.StartWithCreateProcess (System.Diagnostics.ProcessStartInfo startInfo) (at <f7bfd758b02a4936b0078adb4cb60396>:0)
Systehttp://m.Diagnostics.Process.Start () (at <f7bfd758b02a4936b0078adb4cb60396>:0)
(wrapper remoting-invoke-with-check) Systehttp://m.Diagnostics.Process.Start()
UnityEditor.Android.AndroidSDKTools.RunAndroidSdkToolElevatedWindowsInternal (System.String elevatedCommandPath, System.String toolName, System.String javaHome, System.String arguments, System.String errorMsg, System.String toolsdir) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.AndroidSDKTools.RunAndroidSdkToolElevatedWindows (System.String toolName, System.String javaHome, System.String arguments, System.String errorMsg) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.AndroidSDKTools.InstallPlatform (System.Int32 apiLevel) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK+SDKPlatformDetector.Update (UnityEditor.Android.AndroidSDKTools sdkTools, System.Version minVersion, UnityEditor.Android.PostProcessor.ProgressHandler onProgress) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK.EnsureSDKComponentVersion (System.Version minVersion, UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK+SDKComponentDetector detector) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK.EnsureSDKComponentVersion (System.Int32 minVersion, UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK+SDKComponentDetector detector) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessor.Tasks.CheckAndroidSDK.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.PostProcessAndroidPlayer.PrepareForBuild (UnityEditor.BuildPlayerOptions buildPlayerOptions) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.Android.AndroidBuildPostprocessor.PrepareForBuild (UnityEditor.BuildPlayerOptions buildOptions) (at <2a152c15da574a70b6653d9f1dbcd106>:0)
UnityEditor.PostprocessBuildPlayer.PrepareForBuild (UnityEditor.BuildPlayerOptions buildOptions) (at <35c0e5f206594d2fa707969117964d70>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
Error building Player: Win32Exception: ApplicationName='powershell', CommandLine='-ExecutionPolicy Bypass -File "C:/Program Files/Unity/Hub/Editor/2022.3.8f1/Editor/Data/PlaybackEngines/AndroidPlayer/Tools\RunElevatedCommand.ps1" -ArgumentList Ignored "C:\Program Files\Unity\Hub\Editor\2022.3.8f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\cmdline-tools\6.0\bin\sdkmanager.bat" "C:\Program Files\Unity\Hub\Editor\2022.3.8f1\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK" ""platforms;android-33"" "I:\SampleProject\Temp\AndroidSDKTool"', CurrentDirectory='', Native error= 지정된 파일을 찾을 수 없습니다.
Build completed with a result of 'Failed' in 8 seconds (7966 ms)
2 errors
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
빌드를 하려고 했는데 아래와 같은 오류가 뜨면서 빌드가 안됬습니다.


오류가 길게 나오지만 "Android SDK is missing required plaform API" 이것만 보면 비교적 쉽게 접근할 수 있습니다.

타겟 API Level을 안드로이드 13.0 (API level 33)으로 세팅했는데

"C:\Program Files\Unity\Hub\Editor\에디터 버전\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms" 위 경로에 android-33이 없어서였습니다. 저는 해결을 한 후라서 스크린샷에는 있는 거입니다.
유니티 안드로이드 빌드 (API Level 29 ~ 30) (tistory.com)
해결법은 안드로이드 스튜디오를 설치한 후에 셋팅즈에 들어가서 안드로이드 API Level33을 지원하는 SDK를 설치해주면

"C:\Users\유저명\AppData\Local\Android\Sdk\platforms" 해당 경로에

android-33이 설치가 될 탠데 이 폴더를 통째로 아까 "C:\Program Files\Unity\Hub\Editor\에디터 버전\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms" 경로에 복사를 해주고 에디터를 재실행하면 빌드가 정상적으로 됩니다.
유니티 안드로이드 빌드 (API Level 29 ~ 30) (tistory.com)
| [Unity] Built In Standard Shader => URP Shader 변경 (0) | 2024.06.09 |
|---|---|
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #2 (MySQL) (0) | 2023.12.01 |
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #1 (MySQL) (2) | 2023.11.30 |
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
네트워크 연결은 LAN, MAN, WAN으로 구분됩니다.
네트워크 회선은 정보를 전송하는 데 사용되는 전송 매체로, 다양한 유형이 있습니다. 이들은 네트워크 연결의 핵심을 이루며, 정보의 안정적인 전달을 보장합니다. 네트워크 회선에는 인터넷 회선, 전용 회선, 인터넷 전용 회선, VPN, 그리고 DWDM 등이 있습니다. 이들은 각각의 용도와 특징에 따라 다르게 사용됩니다. 이제 각각의 유형을 자세히 설명해 보겠습니다.
| [Network] 네트워크 시작하기(네트워크 기초 정리 #1) (4) | 2024.03.14 |
|---|
1.1.1 홈 네트워크
홈 네트워크를 이루는 주요 구성 요소인 모뎀, 공유기, 그리고 단말 간의 물리적 연결은 네트워크의 핵심입니다. 아래에서 각 요소에 대해 더 자세히 알아보겠습니다.
1.1.2 데이터 센터 네트워크
데이터 센터 네트워크는 기업이나 대규모 서비스 제공 업체가 안정적이고 효율적인 대용량 서비스를 제공하기 위해 구성하는 핵심 부분입니다.
통신 시 규약으로 사용되는 프로토콜의 개념을 소개합니다.
프로토콜 정의 : 네트워크 통신 시 사용되는 규약에 대한 개념 설명
OSI 7계층과 TCP/IP 프로토콜 스택의 관계를 비교하여 설명합니다.

OSI 7 계층 : 2계층과 3계층으로 세분화하여 이해
TCP/IP 프로토콜 스택 : OSI 7 계층을 더 실용적인 관점에서 묶어 설명
각 계층에 대한 상세한 내용과 주요 프로토콜을 설명합니다.
1계층(피지컬 계층)
2계층(데이터 링크 계층)
3계층(네트워크 계층)
4계층(트랜스포트 계층)
트랜스포트 계층의 주요 역할은 네트워크 통신 중에 발생할 수 있는 오류를 발견하고 수정하는 것입니다. 이 계층에서는 데이터 패킷을 안전하고 효율적으로 전송하기 위해 여러 기술과 프로토콜을 사용합니다.
5계층(세션 계층)
세션 계층은 네트워크 연결의 시작과 끝을 관리하며, 데이터 전송 중 발생할 수 있는 문제를 해결하는 역할을 합니다.
6계층(프레젠테이션 계층)
프레젠테이션 계층은 서로 다른 시스템 간에 데이터를 주고받을 때, 그 데이터가 이해할 수 있는 공통의 형식으로 변환되도록 돕습니다. 이 계층에서는 데이터를 알맞은 형식으로 '번역'하여, 다양한 애플리케이션과 시스템 간의 호환성을 보장합니다.
7계층(애플리케이션 계층) :
애플리케이션 계층은 사용자와 직접 상호작용하는 소프트웨어 애플리케이션을 위한 프로토콜과 서비스를 제공합니다. 이 계층은 사용자가 네트워크를 통해 데이터를 송수신할 수 있게 하는 인터페이스 역할을 합니다.
패킷 네트워크에서 데이터의 전송과 수신에 관한 과정을 인캡슐레이션과 디캡슐레이션을 통해 설명합니다.
인캡슐레이션
포장 과정 이라고 생각할 수 있습니다. 마치 물건을 배송하기 위해 상자에 포장하고, 배송지 주소와 같은 정보를 붙이는 과정과 비슷합니다.
디캡슐레이션 : 포장 해제 과정으로 이해할 수 있습니다. 배송된 물건이 목적지에 도착하여 상자를 열고 내용물을 꺼내는 과정과 유사합니다.
이러한 과정은 데이터가 네트워크를 통해 안전하고 효율적으로 전송되게 하며, 데이터의 무결성과 신뢰성을 보장하는 데 중요합니다. 인캡슐레이션은 데이터를 올바르게 포장하여 전송하는 반면, 디캡슐레이션은 받은 데이터를 정확하게 해석하고 사용할 수 있도록 합니다.
- <도서> IT 엔지니어를 위한 네트워크 입문 - 예스24 (yes24.com)
| [Network] 네트워크 연결과 구성 요소(네트워크 기초 정리 #2) (2) | 2024.03.16 |
|---|
1. 효율적인 코드 작성: 컴퓨터 구조를 알면 코드를 더 효율적으로 작성할 수 있습니다. 이는 빠르고 효율적인 프로그램을 만드는데 도움이 됩니다.
2. 문제 해결 능력 향상: 컴퓨터 구조를 이해하면 버그를 찾고 해결하는 능력이 향상됩니다. 코드가 하드웨어와 어떻게 상호 작용하는지 이해하면 오류를 예방하고 빠르게 고칠 수 있습니다.
3. 리소스 효율성: 시스템 리소스를 효율적으로 활용할 수 있습니다. 이는 메모리나 프로세서 등의 자원을 효과적으로 사용하여 성능을 향상할 수 있습니다.
4. 최신 기술 적용: 컴퓨터 구조를 알면 최신 기술을 적용하는데 도움이 됩니다. 빠르게 변하는 기술 트렌드에 대응할 수 있죠.
int[] myArray = { 1, 2, 3, 4, 5 };
int length = myArray.Length; // 배열의 길이를 변수에 저장
// 비효율적인 메모리 액세스
for (int i = 0; i < myArray.Length; i++)
{
int value = myArray[i];
// 작업 수행
}
// 효율적인 메모리 액세스
for (int i = 0; i < length; i++) // 변수를 사용하여 배열의 길이에 직접 접근하지 않음
{
int element = myArray[i];
// 작업 수행
}
간단한 예시 코드 입니다. 여기서 주목할 점은 루프에서 배열의 길이에 접근할 때 myArray.Length를 매번 호출하는 것이 아니라, 한 번 변수에 저장하여 사용하는 것입니다. 이렇게 하면 루프 내에서 배열의 길이에 대한 반복적인 메모리 액세스가 감소하게 되어 효율성이 향상됩니다.
이렇게 컴퓨터 구조를 고려하여 코드를 작성하게 되는 것이 컴퓨터 구조를 알아야 하는 이유 중 하나입니다.
1-1. CPU (Central Processing Unit - 중앙 처리 장치)
역할: 명령어를 해석하고 실행하여 컴퓨터의 모든 연산과 작업을 제어하는 중심 처리 장치입니다.
기능: 산술 논리 연산, 제어 흐름 관리, 메모리 액세스 등을 수행하여 프로그램의 실행을 담당합니다.
1-2. 주기억장치 (RAM - Random Access Memory)
- 역할: 현재 실행 중인 프로그램 및 데이터를 일시적으로 저장하는 공간으로, CPU가 빠르게 액세스 할 수 있는 메모리입니다.
- 기능: 프로그램의 실행에 필요한 데이터 및 명령을 저장하며, 전원이 꺼지면 내용이 소멸하는 휘발성 메모리입니다.
1-3. 보조기억장치
- 역할: 데이터와 프로그램을 장기적으로 저장하는 데 사용되며, 전원이 꺼져도 정보를 보존합니다.
- 종류: 하드 디스크 드라이브 (HDD), SSD (Solid State Drive), USB 등이 있습니다.
- 기능: 운영 체제, 소프트웨어, 파일 등을 저장하여 필요할 때 불러와 사용합니다.
1-4. 입출력장치:
- 역할: 컴퓨터와 외부 세계 간의 데이터 송수신을 담당하는 장치입니다.
- 종류: 키보드, 마우스, 모니터, 프린터, 스캐너, 네트워크 카드 등 다양한 장치가 포함됩니다.
- 기능: 사용자 입력을 받고 결과를 표시하며, 외부 데이터를 컴퓨터에 입력하거나 컴퓨터의 결과를 외부에 출력합니다.
컴퓨터의 핵심 구성요소로는 CPU, 주기억장치, 보조기억장치, 입출력장치가 있습니다. 그러나 이들은 직접적으로 서로 통신할 수 없습니다. 따라서 이 구성요소들 간의 상호 작용을 중계하고 제어하기 위해 메인보드와 시스템 버스가 필요합니다.
2-1. 메인보드 (Mainboard)
역할: 컴퓨터의 모든 구성 요소를 연결하고 제어하는 중앙 플랫폼입니다.
구성: CPU, RAM, 그래픽 카드, 저장 장치 및 다양한 입출력 장치를 연결하는 슬롯과 포트를 가지고 있습니다.
기능: 전기 신호를 전달하고 데이터를 교환하여 컴퓨터의 모든 부품이 원활하게 동작할 수 있도록 합니다.
2.2 시스템 버스 (System Bus)
역할: 메인보드 상의 다양한 구성 요소들 간에 데이터와 제어 신호를 전송하는 통로입니다.
구성: 데이터 버스, 주소 버스, 제어 버스로 구성되어 있습니다.
데이터 버스: 데이터 전송을 위한 경로로, CPU와 주기억장치 및 입출력 장치 간에 데이터를 전송합니다.
주소 버스: 주소 정보를 전송하여 주기억장치나 입출력 장치를 식별합니다.
제어 버스: 데이터와 주소를 제어하고 명령어를 전송하는 데 사용됩니다.
기능: CPU와 주기억장치 간의 데이터 전송, 입출력 장치와의 통신, 그리고 주변 장치들 간의 상호 작용을 가능하게 합니다.
메인보드는 컴퓨터의 중심 부품으로써 다른 모든 하드웨어를 연결하고 통합하는 역할을 합니다. 시스템 버스는 이러한 구성 요소들 간의 통신을 가능하게 하여 컴퓨터의 기능을 조정하고 제어합니다.

- <도서> 혼자 공부하는 컴퓨터 구조+운영체제 ( 혼자 공부하는 컴퓨터 구조+운영체제 - 예스24 (yes24.com) )
| [CS] 프로세스, 스레드, 멀티태스킹, 멀티스레딩, 멀티프로세싱, 멀티프로그래밍 (0) | 2023.02.06 |
|---|
이전 글에서 분량 문제로 추가하지 못한 Insert, Delete, Update 기능을 추가하겠습니다.
[Unity] RestApi 서버 이용하여 유저정보 관리 #1 (MySQL) :: 별빛상자 (tistory.com)
[Unity] RestApi 서버 이용하여 유저정보 관리 #1 (MySQL)
0. 개요 이전에 Nodejs로 RestApi 서버를 실습한 적이 있습니다. 이거를 그때 당시엔 데이터베이스 데이터를 웹브라우저 상에서만 확인했었는데 유니티 클라이언트에서 데이터를 받는 방법도 정리
starlightbox.tistory.com
여기까지 되었다면 UI를 수정해주겠습니다.
1_1 UserCellView 수정

유저 데이터에 내용을 변경하면 좌상단에 체크 오브젝트를 표시해서 누를 경우 업데이트 내용이 서버에 반영되게 구현을 해볼 예정입니다.
우상단에 X 표시를 누를 경우엔 서버에 유저에 데이터 삭제 요청을 보낼 예정입니다.
1_2 신규유저 추가 버튼

우상단에 + 버튼을 추가하여 신규 유저를 추가할 수 있는 버튼을 만들었습니다. 해당버튼을 누르게 되면 신규유저 추가 화면이 나올 예정입니다.

Packets.cs
using System.Collections.Generic;
public class Packets
{
public class user
{
public string user_id;
public string user_password;
public string user_name;
}
public class req_get_users
{
}
public class res_get_users
{
public int status_code;
public List<user> users;
}
public class req_insert_user
{
public string user_id;
public string user_password;
public string user_name;
}
public class res_insert_user
{
public int status_code;
}
public class req_delete_user
{
public string user_id;
}
public class res_delete_user
{
public int status_code;
}
public class req_update_user
{
public string user_id;
public string user_password;
public string user_name;
}
public class res_update_user
{
public int status_code;
}
}
HTTPManager에 서버의 정의해둔 Api를 호출하는 부분을 추가하겠습니다.
HTTPManager.cs
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
public class HTTPManager : MonoBehaviour
{
public static HTTPManager instance;
public UnityAction<List<Packets.user>> onGetUsers;
public void RequestUsers()
{
StartCoroutine(RequestUsersImpl());
}
public void RequestInsertUser(Packets.req_insert_user packet)
{
StartCoroutine(RequestInsertUserImpl(packet));
}
public void RequestDeleteUser(Packets.req_delete_user packet)
{
StartCoroutine(RequestDeleteUserImpl(packet));
}
public void RequestUpdateUser(Packets.req_update_user packet)
{
StartCoroutine(RequestUpdateUserImpl(packet));
}
private string _host = "http://localhost";
private int _port = 3000;
private void Awake()
{
instance = this;
}
private IEnumerator RequestInsertUserImpl(Packets.req_insert_user packet)
{
var url = string.Format("{0}:{1}{2}", _host, _port, "/users/insertUser");
Debug.Log(url);
var www = new UnityWebRequest(url, "POST");
// 객체를 => 문자열 직렬화
var json = JsonConvert.SerializeObject(packet);
// 문자열 => byte 배열로 직렬화
var rawdata = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(rawdata); // 요청
www.downloadHandler = new DownloadHandlerBuffer(); // 응답
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if(www.result == UnityWebRequest.Result.Success)
{
Debug.LogFormat("---->{0}", www.downloadHandler.text);
var res_signup = JsonConvert.DeserializeObject<Packets.res_insert_user>(www.downloadHandler.text); //역직렬화
Debug.LogFormat("status : {0}", res_signup.status_code);
}
else
{
Debug.LogFormat("에러");
}
}
private IEnumerator RequestDeleteUserImpl(Packets.req_delete_user packet)
{
var url = string.Format("{0}:{1}{2}", _host, _port, "/users/deleteUser");
Debug.Log(url);
var www = new UnityWebRequest(url, "POST");
// 객체를 => 문자열 직렬화
var json = JsonConvert.SerializeObject(packet);
// 문자열 => byte 배열로 직렬화
var rawdata = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(rawdata); // 요청
www.downloadHandler = new DownloadHandlerBuffer(); // 응답
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if(www.result == UnityWebRequest.Result.Success)
{
Debug.LogFormat("---->{0}", www.downloadHandler.text);
var res_signup = JsonConvert.DeserializeObject<Packets.res_insert_user>(www.downloadHandler.text); //역직렬화
Debug.LogFormat("status : {0}", res_signup.status_code);
}
else
{
Debug.LogFormat("에러");
}
}
private IEnumerator RequestUpdateUserImpl(Packets.req_update_user packet)
{
var url = string.Format("{0}:{1}{2}", _host, _port, "/users/updateUser");
Debug.Log(url);
var www = new UnityWebRequest(url, "POST");
// 객체를 => 문자열 직렬화
var json = JsonConvert.SerializeObject(packet);
// 문자열 => byte 배열로 직렬화
var rawdata = Encoding.UTF8.GetBytes(json);
www.uploadHandler = new UploadHandlerRaw(rawdata); // 요청
www.downloadHandler = new DownloadHandlerBuffer(); // 응답
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if(www.result == UnityWebRequest.Result.Success)
{
Debug.LogFormat("---->{0}", www.downloadHandler.text);
var res_signup = JsonConvert.DeserializeObject<Packets.res_insert_user>(www.downloadHandler.text); //역직렬화
Debug.LogFormat("status : {0}", res_signup.status_code);
}
else
{
Debug.LogFormat("에러");
}
}
private IEnumerator RequestUsersImpl()
{
var url = string.Format("{0}:{1}{2}", _host, _port, "/users/getUsers");
Debug.Log(url);
var www = new UnityWebRequest(url, "GET");
www.downloadHandler = new DownloadHandlerBuffer(); //응답
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
var res_get_users = JsonConvert.DeserializeObject<Packets.res_get_users>(www.downloadHandler.text);
if (res_get_users.status_code == 200)
{
onGetUsers(res_get_users.users);
}
}
else
{
Debug.Log("에러");
}
}
}
각각 Insert, Delete, Update에 대한 호출 부분을 추가하였습니다.
UserCellView.cs
using UnityEngine;
using UnityEngine.UI;
public class UserCellView : MonoBehaviour
{
public Text textUserId;
public InputField inputFieldPassword;
public InputField inputFieldUserName;
public GameObject submitBtnGo;
public void Init(Packets.user user)
{
_userId = user.user_id;
_password = user.user_password;
_userName = user.user_name;
textUserId.text = _userId;
inputFieldPassword.text = _password;
inputFieldUserName.text = _userName;
submitBtnGo.SetActive(false);
}
public void CheckUpdateInfo()
{
if (_isUpdate)
return;
// 유저 데이터를 변경한 경우
if (inputFieldPassword.text != _password || inputFieldUserName.text != _userName)
{
_isUpdate = true;
submitBtnGo.SetActive(true);
}
}
public void OnClickUpdate()
{
if (inputFieldPassword.text == "")
return;
if (inputFieldUserName.text == "")
return;
Packets.req_update_user packet = new Packets.req_update_user
{
user_id = _userId,
user_password = inputFieldPassword.text,
user_name = inputFieldUserName.text
};
HTTPManager.instance.RequestUpdateUser(packet);
TestMain.instance.Refresh();
}
public void OnClickDelete()
{
Packets.req_delete_user packet = new Packets.req_delete_user
{
user_id = _userId
};
HTTPManager.instance.RequestDeleteUser(packet);
TestMain.instance.Refresh();
}
private string _userId;
private string _password;
private string _userName;
private bool _isUpdate;
}
TestMain.cs
using UnityEngine;
using UnityEngine.UI;
public class TestMain : MonoBehaviour
{
public static TestMain instance;
public GameObject userCellviewPrefab;
public GameObject insertUserGo;
public RectTransform content;
public InputField inputFieldUserId;
public InputField inputFieldPassword;
public InputField inputFieldUserName;
public void OnClickShowInsertUser()
{
inputFieldUserId.text = "";
inputFieldPassword.text = "";
inputFieldUserName.text = "";
insertUserGo.SetActive(true);
}
public void OnClickHideInsertUser()
{
insertUserGo.SetActive(false);
}
public void OnClickInsertUser()
{
if (inputFieldUserId.text == "")
return;
if (inputFieldPassword.text == "")
return;
if (inputFieldUserName.text == "")
return;
Packets.req_insert_user packet = new Packets.req_insert_user
{
user_id = inputFieldUserId.text,
user_password = inputFieldPassword.text,
user_name = inputFieldUserName.text
};
HTTPManager.instance.RequestInsertUser(packet);
Refresh();
OnClickHideInsertUser();
}
public void Refresh()
{
foreach (Transform child in content)
{
Destroy(child.gameObject) ;
}
HTTPManager.instance.RequestUsers();
}
private void Start()
{
HTTPManager.instance.onGetUsers = (users) =>
{
foreach (var user in users)
{
var go = Instantiate<GameObject>(userCellviewPrefab, content);
var cellview = go.GetComponent<UserCellView>();
cellview.Init(user);
}
};
HTTPManager.instance.RequestUsers();
}
private void Awake()
{
instance = this;
}
}

감사합니다.
| [Unity] Built In Standard Shader => URP Shader 변경 (0) | 2024.06.09 |
|---|---|
| [Unity Error - 해결] 빌드 에러 Android SDK is missing required plaform API (0) | 2024.04.03 |
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #1 (MySQL) (2) | 2023.11.30 |
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
이전에 Nodejs로 RestApi 서버를 실습한 적이 있습니다. 이거를 그때 당시엔 데이터베이스 데이터를 웹브라우저 상에서만 확인했었는데 유니티 클라이언트에서 데이터를 받는 방법도 정리를 해두면 좋을 거 같아 정리를 하게 되었습니다.
기본 구조는
[Node.Js] 서버 열고 DB연동해보기 (MySQL) :: 별빛상자 (tistory.com)
[Node.Js] 서버 열고 DB연동해보기 (MySQL)
저는 Visual Studio Code로 작업했어요. 1. Express 서버 열기 1-1. Visual Studio Code 실행 1-2. 작업 폴더 설정 1-3. 'Open Folder' 클릭 1-4. App.js 파일 생성 1-5. Express 서버 설정 커맨드창에 아래 명령어 입력 npm init
starlightbox.tistory.com
이걸 그대로 가져올 예정이나 여기선 유저정보 리스트만 볼 수 있기에 간단하게 기능을 추가하여 구현해보려고 합니다.
기존 기능
1. 유저리스트 정보 확인
추가 기능
1. 유저 추가
2. 유저 삭제
3. 유저 정보 변경
기존엔 SELECT만 사용 하고 있으니 INSERT, DELETE, UPDATE까지 사용해 볼 겸 이렇게 3가지 기능정도만 추가하면 좋을 거 같네요.
1_1. userDBC.js 수정
const mysql = require('mysql2');
// Create the connection pool. The pool-specific settings are the defaults
const pool = mysql.createPool
({
host: 'localhost',
user: 'user명',
database: 'db명',
password: '비밀번호',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
const getUsers = async ()=>
{
const promisePool = pool.promise();
const [rows] = await promisePool.query('SELECT * FROM users;');
console.log(rows);
return rows;
};
const insertUser = async (values)=>{
const promisePool = pool.promise();
const [rows] = await promisePool.query('INSERT INTO users (user_id, user_password, user_name) values (?, ?, ?)', values);
return rows;
};
const deleteUser = async (userId) => {
const promisePool = pool.promise();
const [rows] = await promisePool.query('DELETE FROM users WHERE user_id = ?', [userId]);
return rows;
};
const updateUser = async (userId, updatedValues) => {
const promisePool = pool.promise();
const [rows] = await promisePool.query('UPDATE users SET user_password = ?, user_name = ? WHERE user_id = ?', [...updatedValues, userId]);
return rows;
};
module.exports =
{
getUsers, insertUser, deleteUser, updateUser
};
1_2. userRouter.js 수정
const express = require('express');
const userDBC = require('./usersDBC');
const router = express.Router();
router.get('/getUsers', async (req, res)=>{
let res_get_users = {
status_code : 500,
users : []
};
try{
const rows = await userDBC.getUsers();
res_get_users.status_code = 200;
if(rows.length > 0){
rows.forEach((user)=>{
res_get_users.users.push({
user_name : user.user_name,
user_id : user.user_id,
user_password : user.user_password
});
});
}else{
console.log('사용자 없음');
}
}catch(error)
{
console.log(error.message);
}finally
{
//응답
res.json(res_get_users);
}
});
router.post('/insertUser', async(req, res)=>{
const res_signup = {
status_code : 500
};
try{
const {user_id, user_password, user_name} = req.body;
const rows = await userDBC.insertUser([user_id, user_password, user_name]);
if(rows.affectedRows > 0){
// 정상작동
res_signup.status_code = 200;
}else{
// ERROR
res_signup.status_code = 201;
}
}catch(err)
{
// ERROR
console.log(err.message);
}finally{
res.json(res_signup);
}
});
router.post('/deleteUser', async(req, res)=>{
const res_delete_user = {
status_code : 500
};
try{
const {user_id} = req.body;
const rows = await userDBC.deleteUser([user_id]);
if(rows.affectedRows > 0){
// 정상작동
res_delete_user.status_code = 200;
}else{
// ERROR
res_delete_user.status_code = 201;
}
}catch(err)
{
// ERROR
console.log(err.message);
}finally{
res.json(res_delete_user);
}
});
router.post('/updateUser', async(req, res)=>{
const res_update_user = {
status_code : 500
};
try{
const {user_id, user_password, user_name} = req.body;
const rows = await userDBC.updateUser(user_id, [user_password, user_name]);
if(rows.affectedRows > 0){
// 정상작동
res_update_user.status_code = 200;
}else{
// ERROR
res_update_user.status_code = 201;
}
}catch(err)
{
// ERROR
console.log(err.message);
}finally{
res.json(res_update_user);
}
});
module.exports = router;
서버 작업은 여기 까지면 될 것 같습니다.
이제 유니티로 넘어 갑니다.
2_1 기본 UI 구성

저는 먼저 user_id를 표현해 줄 Text 오브젝트와 password, user_name 수정을 할 수 있게 할거기 때문에 InputField 오브젝트 2개를 구성하였습니다.

그럼 이런 식으로 서버에 있는 데이터들을 읽어와서 UserCellView 오브젝트를 생성하며 데이터를 표현해줄 것입니다.
2_2 UI 기능 구현
먼저 서버에 있는 유저 데이터를 가져오는 코드를 작업해보겠습니다.
Packets.cs
using System.Collections.Generic;
public class Packets
{
public class user
{
public string user_id;
public string user_password;
public string user_name;
}
public class res_get_users
{
public int status_code;
public List<user> users;
}
}
HTTPManager.cs
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
public class HTTPManager : MonoBehaviour
{
public static HTTPManager instance;
public UnityAction<List<Packets.user>> onGetUsers;
public void RequestUsers()
{
StartCoroutine(RequestUsersImpl());
}
private string _host = "http://localhost";
private int _port = 3000;
private void Awake()
{
instance = this;
}
private IEnumerator RequestUsersImpl()
{
var url = string.Format("{0}:{1}{2}", _host, _port, "/users/getUsers");
Debug.Log(url);
var www = new UnityWebRequest(url, "GET");
www.downloadHandler = new DownloadHandlerBuffer(); //응답
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
var res_get_users = JsonConvert.DeserializeObject<Packets.res_get_users>(www.downloadHandler.text);
if (res_get_users.status_code == 200)
{
onGetUsers(res_get_users.users);
}
}
else
{
Debug.Log("에러");
}
}
}
TestMain.cs
using UnityEngine;
using UnityEngine.UI;
public class TestMain : MonoBehaviour
{
public static TestMain instance;
public GameObject userCellviewPrefab;
public RectTransform content;
public InputField inputFieldUserId;
public InputField inputFieldPassword;
public InputField inputFieldUserName;
private void Awake()
{
instance = this;
}
private void Start()
{
HTTPManager.instance.onGetUsers = (users) =>
{
foreach (var user in users)
{
var go = Instantiate<GameObject>(userCellviewPrefab, content);
var cellview = go.GetComponent<UserCellView>();
cellview.Init(user);
}
};
HTTPManager.instance.RequestUsers();
}
}
UserCellView.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class UserCellView : MonoBehaviour
{
public Text textUserId;
public InputField inputFieldPassword;
public InputField inputFieldUserName;
public void Init(Packets.user user)
{
_userId = user.user_id;
_password = user.user_password;
_userName = user.user_name;
textUserId.text = _userId;
inputFieldPassword.text = _password;
inputFieldUserName.text = _userName;
}
private string _userId;
private string _password;
private string _userName;
}

이렇게 서버에서 주는 데이터를 유니티에서 확인할 수 있었습니다.
글이 생각보다 너무 길어지는 관계로 Insert, Update, Delete 관련 내용은 다음 글에서 다루겠습니다. 감사합니다.
| [Unity Error - 해결] 빌드 에러 Android SDK is missing required plaform API (0) | 2024.04.03 |
|---|---|
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #2 (MySQL) (0) | 2023.12.01 |
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
| [Unity] 에디터 확장 기능으로 스크립트 일괄 제거하기 (2) | 2023.08.21 |
오랜만에 서버 관련 코드를 복습해보려고 했는데 시작부터 원활하지 않네요.

connect ECONNREFUSED ::1:3306 구글링을 해보니 mysql 커넥션 부분에서 host를 127.0.0.1로 수정한 방법이 있길래 적용해 봤습니다.
const pool = mysql.createPool
({
host: 'localhost',
user: '계정명',
database: 'database이름',
password: '비밀번호',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
이 부분을
const pool = mysql.createPool
({
host: '127.0.0.1',
user: '계정명',
database: 'database이름',
password: '비밀번호',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
이렇게요.

아 저는 이렇게 해도 해결이 안 되네요. 다른 방법을 찾아봐야 했습니다.
e conn refused
e가 무슨 뜻인진 모르겠지만 conn은 커넥션일 거 같고 refused는 거절이니 커넥션이 거절됬다인데 다른 글을 찾아보니 데이터베이스와 접속이 문제일 경우가 있을 수 있다 하여 확인해 봤습니다.
MySql workbench 를 열고 테스트 커넥션을 해보니 역시나

접속이 안되네요.

서비스가 중지가 되어 있으니 당연히 접속이 안되던 오류였습니다.

서비스를 실행시키고 다시 코드를 실행해 보니

다행히 잘 되네요. 간단한 오류여서 다행이었습니다.
[nodejs] node에서 mySQL 연결(Error: connect ECONNREFUSED ::1:3306) (tistory.com)
| [Node.Js] 서버 열고 DB연동해보기 (MySQL) (0) | 2023.02.26 |
|---|---|
| [Node.Js] 설치 (18.14.2 LTS) (0) | 2023.02.26 |
디자인 패턴은 소프트웨어 개발에서 발생하는 일반적인 문제에 대한 해결책을 제공하는 일종의 Well-established pattern으로, 디자인에서 자주 발생하는 문제에 대한 해결책을 제공하는 일종의 템플릿 또는 모범 사례입니다.
프로그램 개발에서 디자인 패턴을 알아야 하는 이유는 여러 가지가 있습니다. 다양한 측면에서 개발 프로세스를 개선하고 코드의 유지보수성과 확장성을 향상하는 데 도움을 줍니다.
1. 재사용성 증가: 디자인 패턴을 사용하면 이미 검증된 솔루션을 사용하여 코드를 작성할 수 있습니다. 이는 개발자가 비슷한 문제에 계속해서 새로운 해결책을 개발할 필요 없이 기존의 패턴을 활용하여 시간을 절약하고 코드의 재사용성을 증가시킬 수 있습니다.
2. 유지보수성 향상: 디자인 패턴을 사용하면 코드의 일관성과 가독성이 향상되어 유지보수가 더 쉬워집니다. 다른 개발자나 여러 프로젝트 간에도 일관된 디자인이 있어 코드를 이해하고 수정하기가 더 쉬워집니다.
3. 확장성 강화: 디자인 패턴은 시스템이 나중에 변경되거나 확장될 때 유연성을 제공합니다. 새로운 요구사항이나 기능이 추가될 때, 디자인 패턴을 통해 기존 코드를 변경하지 않고도 새로운 기능을 추가할 수 있습니다.
4. 코드의 가독성 증가: 디자인 패턴은 일반적으로 잘 알려진 개발 관행을 따르기 때문에 코드의 가독성을 향상시킵니다. 이는 코드를 이해하고 유지보수하기가 더 쉽게 만들어줍니다.
5. 품질 향상: 디자인 패턴은 소프트웨어 개발에서 품질을 향상시킬 수 있는 다양한 원칙을 포함하고 있습니다. 예를 들어, 객체 지향 디자인 원칙을 따르는 패턴은 모듈화, 낮은 결합도, 높은 응집도 등과 같은 품질 개선을 지원합니다.
6. 커뮤니케이션 향상: 디자인 패턴은 개발자들 간의 의사 소통을 촉진합니다. 일반적으로 알려진 패턴을 사용하면 다른 개발자들도 빠르게 코드를 이해할 수 있으며, 이는 협업을 더 효과적으로 만듭니다.
이러한 이유로, 디자인 패턴은 개발 프로세스에서 중요한 역할을 하며 효율적이고 유지보수 가능한 소프트웨어를 만들기 위해 반드시 알아두어야 하는 개념 중 하나입니다.
디자인 패턴은 크게 세 가지 카테고리로 나눌 수 있습니다.
1. 생성 패턴 (Creational Patterns): 객체의 생성 메커니즘을 다루는 패턴입니다. 이 패턴은 객체를 생성, 합성 및 표현하는 방법을 결정하는데 도움을 줍니다.
2. 구조 패턴 (Structural Patterns): 클래스와 객체를 조합하여 더 큰 구조를 만드는 패턴입니다. 이러한 패턴은 상속, 객체 컴포지션을 사용하여 시스템을 더 유연하게 만듭니다.
3. 행위 패턴 (Behavioral Patterns): 객체 간의 알고리즘 및 역할을 나누는 패턴입니다. 이 패턴은 객체 간의 통신 및 역할 분배에 중점을 둡니다.
디자인 패턴은 주로 GoF(Gang of Four)에서 제안한 23가지 디자인 패턴이 널리 알려져 있습니다. 이러한 패턴은 "Design Patterns: Elements of Reusable Object-Oriented Software"라는 책에서 소개되었습니다. 이러한 디자인 패턴을 이해하고 적용함으로써 코드를 더 구조적이고 유연하게 만들 수 있습니다.
| 생성 패턴 | 구조 패턴 | 행동 패턴 |
| 싱글톤 (Singleton) | 어댑터 (Adapter) | 책임 연쇄 (Chain-of-Responsibility) |
| 팩토리 메소드 (Factory Method) | 브릿지 (Bridge) | 커맨드 (Command) |
| 추상 팩토리 (Abstract Factory) | 컴포짓 (Composite) | 인터프리터 (Interpreter) |
| 빌더 (Builder) | 데코레이터 (Decorator) | 이터레이터 (Iterator) |
| 프로토타입 (Prototype) | 퍼사드 (Facade) | 중재자 (Mediator) |
| 플라이웨이트 (Flyweight) | 메멘토 (Memento) | |
| 프록시 (Proxy) | 옵저버 (Observer) | |
| 상태 (State) | ||
| 전략 (Strategy) | ||
| 템플릿 메소드 (Template Method) | ||
| 비지터 (Visitor) |
Unity 2022 LTS 버전이 나왔더라고요.
기존 프로젝트가 Unity 2021.3.5f1 버전을 사용 중이어서 아직 초창기라 버전을 올려줬습니다.

Unity is running with Administrator privileges, which is not supported. Unity executes scripts and binary libraries in your project that may originate from third party sources and potentially be harmful to your computer. Unity may also execute scripts and binary libraries that are still under development and not yet fully tested. Running Unity with Administrator privileges may lead to catastrophic consequences, including but not limited to accidental data loss, change of global system settings or even bricking your device.

근데 버전을 올린 후로 실행할 때마다 해당메시지가 계속 떠서 찾아본 결과 UAC(사용자 계정 컨트롤 설정 변경)으로 해결할 수 있더라고요.


설정 후 재부팅

이후 UAC 설정을 원래대로 바꿔도 정상 작동 확인 했습니다.
참고문헌
How do I run 2022.2.1f1 as a standard user? : r/Unity3D (reddit.com)
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #2 (MySQL) (0) | 2023.12.01 |
|---|---|
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #1 (MySQL) (2) | 2023.11.30 |
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
| [Unity] 에디터 확장 기능으로 스크립트 일괄 제거하기 (2) | 2023.08.21 |
| [Unity] 로컬 푸쉬 Mobile Notifications 구현 (야간푸쉬 체크) (0) | 2023.07.18 |
0. 실행환경
Unity 2021.3.5f1
씬에선 Content Size Fitter 컴포넌트가 정상 작동해서 Content 사이즈가 잘 늘어났으나 실행 시 정상적으로 작동 안 하는 이슈 발생
오브젝트를 껐다 켰을경우 정상 작동 확인 후 검색해 보니 유니티에서 간헐적으로 발생하는 오류라고 합니다. 이때 임시로
LayoutRebuilder.ForceRebuildLayoutImmediate(transform as RectTransform);
문제가 되는 오브젝트를 강제로 다시 재빌드 해주면 되는데요. 저는 이걸 스크립트화 해가지고 문제가 되는 오브젝트에 넣어 줘서 해결했습니다.


using UnityEngine;
using UnityEngine.UI;
public class UIRebuildLayout : MonoBehaviour
{
private void Start()
{
LayoutRebuilder.ForceRebuildLayoutImmediate(transform as RectTransform);
}
}

참고문헌
| [Unity] Rest Api 서버 이용하여 유저정보 관리 #1 (MySQL) (2) | 2023.11.30 |
|---|---|
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
| [Unity] 에디터 확장 기능으로 스크립트 일괄 제거하기 (2) | 2023.08.21 |
| [Unity] 로컬 푸쉬 Mobile Notifications 구현 (야간푸쉬 체크) (0) | 2023.07.18 |
| [Unity] Lerp 사용해보기 (0) | 2023.05.08 |
0. 구현 이유
에셋스토어에서 가져온 캐릭터를 사용하려 했는데, 캐릭터에 포함된 불필요한 스크립트들을 제거해야 할 상황이었습니다. 그래서 자식 오브젝트들을 일일이 확인하며 스크립트를 제거하려 했으나, 이 작업이 상당한 시간을 요구하는 것을 알게 되었습니다. 결국 제 시간을 절약하기 위해 자체적으로 스크립트 제거 기능을 개발하게 되었습니다.
Unity 에디터 확장을 사용하여 게임 오브젝트에 붙은 여러 스크립트를 한 번에 제거하는 기능을 구현하는 방법에 대해 알아보겠습니다.
1. 에디터 확장 스크립트 작성
먼저, Unity 프로젝트에서 스크립트를 생성해야 합니다. 프로젝트 안에 Editor 폴더를 만들고, 그 안에 ScriptRemoverWindow.cs라는 이름으로 스크립트 파일을 생성합니다.
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
public class ScriptRemoverWindow : EditorWindow
{
private int Count = 10;
private List<string> scriptNames = new List<string>();
// 에디터 메뉴에서 "SLG/Remove Scripts by Name" 옵션을 추가합니다.
[MenuItem("slg/Remove Scripts by Name")]
private static void ShowWindow()
{
// "Script Remover"라는 윈도우를 엽니다.
GetWindow(typeof(ScriptRemoverWindow), false, "Script Remover");
}
private void OnGUI()
{
GUILayout.Label("Enter the script names to remove:");
// 입력 필드를 생성하여 스크립트 이름을 입력받습니다.
for (int i = 0; i < Count; i++)
{
scriptNames.Add("");
}
for (int i = 0; i < Count; i++)
{
scriptNames[i] = EditorGUILayout.TextField("Script " + (i + 1), scriptNames[i]);
}
// "Remove Scripts" 버튼을 생성하고 클릭 시 스크립트 제거 함수를 호출합니다.
if (GUILayout.Button("Remove Scripts"))
{
RemoveComponentsByNames(scriptNames);
}
}
private static void RemoveComponentsByNames(List<string> targetComponentNames)
{
// 선택된 게임 오브젝트에 대해 스크립트 제거 함수를 호출합니다.
if (Selection.gameObjects != null)
{
foreach (GameObject go in Selection.gameObjects)
{
RemoveComponentsRecursively(go.transform, targetComponentNames);
Component[] components = go.GetComponents<Component>();
foreach (Component component in components)
{
if (component != null && targetComponentNames.Contains(component.GetType().Name))
{
// 즉시 객체를 제거하고, 실행 취소 기록에 남깁니다.
Undo.DestroyObjectImmediate(component);
}
}
}
}
}
private static void RemoveComponentsRecursively(Transform parent, List<string> targetComponentNames)
{
// 하위 자식들에 대해 재귀적으로 컴포넌트 제거 함수를 호출합니다.
for (int i = parent.childCount - 1; i >= 0; i--)
{
Transform child = parent.GetChild(i);
RemoveComponentsRecursively(child, targetComponentNames);
// 하위 자식 오브젝트의 컴포넌트를 순회하며 제거 대상인 경우 제거합니다.
Component[] components = child.GetComponents<Component>();
foreach (Component component in components)
{
if (component != null && targetComponentNames.Contains(component.GetType().Name))
{
// 즉시 객체를 제거하고, 실행 취소 기록에 남깁니다.
Undo.DestroyObjectImmediate(component);
}
}
}
}
}
이 스크립트는 "slg" 메뉴에 "Remove Scripts by Name" 옵션을 추가하고, 해당 옵션을 선택하면 "Script Remover"라는 윈도우가 열립니다. 여기에서 제거할 스크립트 이름을 입력하고 "Remove Scripts" 버튼을 클릭하면 선택된 게임 오브젝트에서 해당 스크립트를 제거합니다.
2. 사용 방법


Before



After



감사합니다.
| [Unity Error] unity is running as administrator (0) | 2023.09.03 |
|---|---|
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
| [Unity] 로컬 푸쉬 Mobile Notifications 구현 (야간푸쉬 체크) (0) | 2023.07.18 |
| [Unity] Lerp 사용해보기 (0) | 2023.05.08 |
| [Unity] XLua 연동해보기 (0) | 2023.03.26 |
0. Mobile Notifications 구현해야 하는 이유
게임 앱에서 푸시 알림을 사용하는 이유는 다양합니다. 이러한 알림은 사용자 경험을 개선하고 게임의 참여도를 높일 수 있는 강력한 도구입니다.
재참여 유도: 게임을 잊지 않고 계속해서 플레이하도록 유도할 수 있습니다. 푸시 알림을 통해 사용자에게 게임에 대한 업데이트, 이벤트, 할인, 새로운 콘텐츠 등을 알릴 수 있습니다. 이렇게 하면 사용자들이 게임에 다시 참여하고 새로운 콘텐츠나 기능을 경험하도록 유도할 수 있습니다.
이벤트 및 경쟁 참여 유도: 게임 내 이벤트, 경쟁, 토너먼트 등에 사용자를 참여시킬 수 있습니다. 푸시 알림을 통해 이러한 이벤트에 대한 알림과 참여 방법, 보상 등을 전달할 수 있습니다. 사용자는 이러한 알림을 통해 게임에서의 목표를 인식하고 참여 동기를 얻을 수 있습니다.
소셜 상호작용 장려: 게임에서의 소셜 상호작용은 매우 중요합니다. 푸시 알림을 통해 사용자에게 친구 요청, 선물, 도움 요청 등을 알릴 수 있습니다. 또한 다른 플레이어와의 상호작용을 촉진하기 위해 이벤트에 대한 초대, 공유, 리더보드 업데이트 등을 알릴 수도 있습니다.
개인화된 경험 제공: 푸시 알림은 사용자에게 개인화된 경험을 제공할 수 있는 효과적인 방법입니다. 사용자의 선호도, 플레이 스타일, 진행 상황 등을 고려하여 맞춤형 알림을 전송할 수 있습니다. 이렇게 하면 사용자는 게임에서 더 많은 관심과 참여를 보일 수 있습니다.
중요한 업데이트 및 경고 전달: 푸시 알림을 사용하면 게임 내 중요한 업데이트, 경고 또는 이슈에 대해 사용자에게 신속하게 알릴 수 있습니다. 예를 들어, 서버 다운타임, 보안 경고, 결제 확인 등을 사용자에게 알릴 수 있습니다.
푸시 알림은 게임 애플리케이션의 사용자 참여와 유지에 매우 유용한 도구입니다. 그러나 알림의 빈도와 타이밍은 사용자 경험에 큰 영향을 줄 수 있으므로 신중하게 계획하고 구성해야 합니다. 사용자의 플레이 스타일과 선호도를 고려하여 푸시 알림을 사용하는 것이 좋습니다.
유니티에서 Mobile Notifications에 관련된 패키지를 제공하고 있기때문에 쉽게 구현할 수 있었습니다.
1. 프로젝트 생성

안드로이드 셋팅

2. 패키지 추가

3. 샘플도 임폴트 Import 해줍니다.

4.
샘플 생성확인 후 NotificationsManager.cs 스크립트 작성

using NotificationSamples;
using System;
using UnityEngine;
public class NotificationsManager : GameNotificationsManager
{
// Public
////////////////////////////////////////////////////////////////////////////////////////
public const string channel1 = "channel1";
public const string channel2 = "channel2";
public const string channel3 = "channel3";
// 알람푸쉬 권한
public void Init(bool isAlarmAccept = true, bool isNightAlarmAccept = true)
{
_isAlarmAccept = isAlarmAccept;
_isNightAlarmAccept = isNightAlarmAccept;
}
private void SendNotification(string title, string body, DateTime deliveryTime, int? badgeNumber = null,
bool reschedule = false, string channelId = null,
string smallIcon = null, string largeIcon = null)
{
// 알람푸쉬 권한 체크
if (!_isAlarmAccept)
return;
// 야간푸쉬 권한 체크
if(!_isNightAlarmAccept)
{
bool isNight = CheckNightTime(deliveryTime);
if (isNight)
return;
}
IGameNotification notification = instance.CreateNotification();
if (notification == null)
{
return;
}
notification.Title = title;
notification.Body = body;
notification.Group = !string.IsNullOrEmpty(channelId) ? channelId : channel1;
notification.DeliveryTime = deliveryTime;
notification.SmallIcon = smallIcon;
notification.LargeIcon = largeIcon;
if (badgeNumber != null)
{
notification.BadgeNumber = badgeNumber;
}
PendingNotification notificationToDisplay = instance.ScheduleNotification(notification);
notificationToDisplay.Reschedule = reschedule;
}
// Private
////////////////////////////////////////////////////////////////////////////////////////
private GameNotificationsManager instance;
private float _tenSecond = 10f;
private float _twentySecond = 20f;
private bool _isAlarmAccept = true;
private bool _isNightAlarmAccept = true;
private int nightStartHour = 22;
private int nightEndHour = 6;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
var c1 = new GameNotificationChannel(channel1, "channel1", "channel1 notifications");
var c2 = new GameNotificationChannel(channel2, "channel2", "channel2 notifications");
var c3 = new GameNotificationChannel(channel3, "channel3", "channel3 notifications");
instance.Initialize(c1, c2, c3);
instance.Platform.CancelAllScheduledNotifications();
}
private void OnApplicationPause(bool pause)
{
if (pause)
{
RefreshNotifications();
}
else
{
//resume
if (instance != null && instance.Platform != null)
{
instance.Platform.CancelAllScheduledNotifications();
}
}
}
private void OnApplicationQuit()
{
RefreshNotifications();
}
private void RefreshNotifications()
{
if (instance == null || instance.Platform == null)
{
return;
}
CancelAllNotifications();
// 알람 허용자 체크
if(_isAlarmAccept)
{
var title = "TITLE TEXT";
SendNotification(title, "tenSecond", DateTime.Now.AddSeconds(_tenSecond));
SendNotification(title, "twentySecond", DateTime.Now.AddSeconds(_twentySecond));
}
}
private bool CheckNightTime(DateTime checkTime)
{
bool isNight = false;
int hour = int.Parse(checkTime.ToString("HH"));
if (hour < nightEndHour || hour >= nightStartHour)
isNight = true;
return isNight;
}
}
5. 스크립트 넣어주고 빌드


참고문헌
Introduction | Mobile Notifications | 1.3.2 (unity3d.com)
| [Unity] Content Size Fitter 버그 증상 임시 (0) | 2023.08.24 |
|---|---|
| [Unity] 에디터 확장 기능으로 스크립트 일괄 제거하기 (2) | 2023.08.21 |
| [Unity] Lerp 사용해보기 (0) | 2023.05.08 |
| [Unity] XLua 연동해보기 (0) | 2023.03.26 |
| [Unity] 오브젝트 풀링 (Object pooling) (12) | 2023.03.18 |
1. 제목
- 백준 15903 카드 합체 놀이
- BOJ 15903 카드 합체 놀이
문제 링크 : 15903번: 카드 합체 놀이 (acmicpc.net)
15903번: 카드 합체 놀이
첫 번째 줄에 카드의 개수를 나타내는 수 n(2 ≤ n ≤ 1,000)과 카드 합체를 몇 번 하는지를 나타내는 수 m(0 ≤ m ≤ 15×n)이 주어진다. 두 번째 줄에 맨 처음 카드의 상태를 나타내는 n개의 자연수 a1,
www.acmicpc.net
2. 풀이 과정
이 카드 합체를 총 m번 하면 놀이가 끝난다. m번의 합체를 모두 끝낸 뒤, n장의 카드에 쓰여있는 수를 모두 더한 값이 이 놀이의 점수가 된다. 이 점수를 가장 작게 만드는 것이 놀이의 목표이다.
이문제에서 핵심 문장이라고 생각합니다. N개의 카드들 중 2개를 선정해서 합체를 하면 2개의 카드가 모두 같은 숫자가 된다는 규칙이 있기 때문에 가장 작은 숫자의 카드끼리 합체를 하는 게 유리합니다. 그렇기에 이문제는 카드들을 오름차순으로 정렬하고 가장 작은 숫자의 카드 2장을 합치 고를 M번 반복하는 방법으로 풀었습니다. 정렬방법으로는 우선순위큐를 이용하여 큐에 넣을 때 카드들이 정렬되게 했습니다.
1. 우선순위큐에 카드를 넣는다.
2. 가장 작은 숫자의 카드 2장을 골라 우선순위큐에서 빼고 합친다음 다시 우선순위큐에 넣는다
3. 코드
// 1. 우선순위큐에 카드를 넣는다.
// 2. 가장 작은 숫자의 카드 2장을 골라 우선순위큐에서 빼고 합친다음 다시 우선순위큐에 넣는다
#include <iostream>
#include <queue>
#include <functional>
using namespace std;
int main()
{
int n, m;
priority_queue <long long, vector<long long>, greater<long long>> cards;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
long long card;
cin >> card;
// 1. 우선순위큐에 카드를 넣는다.
cards.push(card);
}
for (int i = 0; i < m; i++)
{
// 2. 가장 작은 숫자의 카드 2장을 골라 우선순위큐에서 빼고 합친다음 다시 우선순위큐에 넣는다
long long card1 = cards.top();
cards.pop();
long long card2 = cards.top();
cards.pop();
long long mergeCard = card1 + card2;
cards.push(mergeCard);
cards.push(mergeCard);
}
long long result = 0;
for (int i = 0; i < n; i++)
{
result += cards.top();
cards.pop();
}
cout << result << endl;
return 0;
}| [백준 BOJ1946] 신입 사원 (C++) (0) | 2023.07.09 |
|---|---|
| [백준 BOJ13305] 주유소 (C++) (0) | 2023.07.02 |
| [백준 BOJ1789] 수들의 합 (C++) (0) | 2023.07.02 |
| [백준 BOJ1026] 보물 (C++) (0) | 2023.07.02 |
| [백준 BOJ2217] 로프 (C++) (0) | 2023.07.02 |
1. 제목
- 백준 1946 신입사원
- BOJ 1946 신입사원
문제 링크 : 1946번: 신입 사원 (acmicpc.net)
1946번: 신입 사원
첫째 줄에는 테스트 케이스의 개수 T(1 ≤ T ≤ 20)가 주어진다. 각 테스트 케이스의 첫째 줄에 지원자의 숫자 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N개 줄에는 각각의 지원자의 서류심사 성
www.acmicpc.net
2. 풀이 과정
서류심사 성적으로 이미 한번 정렬을 했기 때문에 N번째 지원자보다 서류심사 성적이 높은 지원자들 중 면접 점수가 가장 높은지 체크하는 것
1. 서류심사 성적으로 먼저 지원자를 정렬한다.
2. minScore2 값에 N번째 지원자 중 가장 면접 점수가 높은 점수를 저장
3. N번째 지원자가 N번째 지원자 중 가장 면접 점수가 높다면 합격
3. 코드
// 서류심사 성적으로 이미 한번 정렬을 했기 때문에 N번째 지원자보다 서류심사 성적이 높은 지원자들 중 면접 점수가 가장 높은지 체크하는 것
//
// 1. 서류심사 성적으로 먼저 지원자를 정렬한다.
// 2. minScore2 값에 N번째 지원자 중 가장 면접 점수가 높은 점수를 저장
// 3. N번째 지원자가 N번째 지원자 중 가장 면접 점수가 높다면 합격
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Employee
{
int score1;
int score2;
};
bool Compare(Employee e1, Employee e2)
{
return e1.score1 < e2.score1;
}
int main()
{
int T;
scanf("%d", &T);
vector <Employee> employees;
vector <int> result;
for (int t = 0; t < T; t++)
{
int N;
scanf("%d", &N);
for (int n = 0; n < N; n++)
{
int score1, score2;
scanf("%d %d", &score1, &score2);
employees.push_back({ score1, score2 });
}
// 1. 서류심사 성적으로 먼저 지원자를 정렬한다.
sort(employees.begin(), employees.end(), Compare);
int minScore2 = employees[0].score2;
int passer = 1;
for (int i = 1; i < N; i++)
{
// 2. minScore2 값에 N번째 지원자 중 가장 면접 점수가 높은 점수를 저장
// 3. N번째 지원자가 N번째 지원자 중 가장 면접 점수가 높다면 합격
if (employees[i].score2 < minScore2)
passer++;
minScore2 = min(minScore2, employees[i].score2);
}
result.push_back(passer);
employees.clear();
}
for (int t = 0; t < T; t++)
printf("%d \n", result[t]);
return 0;
}| [백준 BOJ15903] 카드 합체 놀이 (C++) (0) | 2023.07.11 |
|---|---|
| [백준 BOJ13305] 주유소 (C++) (0) | 2023.07.02 |
| [백준 BOJ1789] 수들의 합 (C++) (0) | 2023.07.02 |
| [백준 BOJ1026] 보물 (C++) (0) | 2023.07.02 |
| [백준 BOJ2217] 로프 (C++) (0) | 2023.07.02 |
1. 제목
- 백준 13305 주유소
- BOJ 13305 주유소
문제 링크 : 13305번: 주유소 (acmicpc.net)
13305번: 주유소
표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 도시의 개수를 나타내는 정수 N(2 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 인접한 두 도시를 연결하는 도로의 길이가 제일 왼쪽 도로부터 N-1
www.acmicpc.net
2. 풀이 과정
1. 현재 위치에서 다음 위치까지 가는 데 필요한 기름이 없다면 기름을 충전
2. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳이 있다면 최소한의 기름만 충전
3. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳까지 이동에 필요한 기름을 충전
3. 코드
// 1. 현재 위치에서 다음 위치까지 가는 데 필요한 기름이 없다면 기름을 충전
// 2. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳이 있다면 최소한의 기름만 충전
// 3. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳까지 이동에 필요한 기름을 충전
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct City
{
// 기름 가격
long long oilPrice;
// 다음 지역까지 거리
long long nextDistances;
};
vector<City> cities(100001);
int N;
int main()
{
cin >> N;
long long oil = 0;
long long result = 0;
for (int index = 0; index < N - 1; index++)
cin >> cities[index].nextDistances;
for (int index = 0; index < N - 1; index++)
cin >> cities[index].oilPrice;
for (int index = 0; index < N - 1; index++)
{
// 1. 현재 위치에서 다음 위치까지 가는 데 필요한 기름이 없다면 기름을 충전
if (oil < cities[index].nextDistances)
{
// 2. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳이 있다면 최소한의 기름만 충전
if (cities[index+1].oilPrice < cities[index].oilPrice)
{
oil += cities[index].nextDistances;
result += oil * cities[index].oilPrice;
}
else
{
// 3. 기름을 충전할 때 배열에 현재 나라보다 기름 가격이 싼 곳까지 이동에 필요한 기름을 충전
long long remainingDistance = 0;
for (int j = index; j < N - 1; j++)
{
if (cities[j].oilPrice < cities[index].oilPrice)
break;
remainingDistance += cities[j].nextDistances;
}
oil += remainingDistance;
result += oil * cities[index].oilPrice;
}
}
oil -= cities[index].nextDistances;
}
cout << result << endl;
return 0;
}| [백준 BOJ15903] 카드 합체 놀이 (C++) (0) | 2023.07.11 |
|---|---|
| [백준 BOJ1946] 신입 사원 (C++) (0) | 2023.07.09 |
| [백준 BOJ1789] 수들의 합 (C++) (0) | 2023.07.02 |
| [백준 BOJ1026] 보물 (C++) (0) | 2023.07.02 |
| [백준 BOJ2217] 로프 (C++) (0) | 2023.07.02 |
1. 제목
- 백준 1789 수들의 합
- BOJ 1789 수들의 합
문제 링크 : 1789번: 수들의 합 (acmicpc.net)
1789번: 수들의 합
첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.
www.acmicpc.net
2. 풀이 과정
1 ~ N 개의 자연수의 합 S
1. 1부터 1씩 증가시키며 누적합 계산
2. 누적합이 S를 넘어섰다면 이전 인덱스가 최댓값
2번 조건문에서 실수를 했는데
if (sum >= S)
break;
처음에는 while문을 빠져나오는 조건을 이렇게 설정을 했습니다. 누적합이 S이상 이기만 해도 빠져나와야 한다고 생각을 한 게 문제였습니다.
이렇게 하게 되면 예시로 3이 주어졌을 때
1 + 2로
빠져나오는 조건에 충족하게 되며 이전 인덱스를 참조하게 되면 1을 리턴하며 오답을 반환하게 됩니다. 그렇기에 무조건 누적합이 S를 초과했을 때 while문을 빠져나오게 조건문을 수정하였습니다.
3. 코드
// 1 ~ N 개의 자연수의 합 S
// 1. 1부터 1씩 증가시키며 누적합 계산
// 2. 누적합이 S를 넘어섰다면 이전 인덱스가 최댓값
#include <iostream>
using namespace std;
int main()
{
long long S;
cin >> S;
long long index = 1;
long long sum = 0;
while (true)
{
// 1. 1부터 1씩 증가시키며 누적합 계산
sum += index;
// 2. 누적합이 S를 넘어섰다면 이전 인덱스가 최댓값
if (sum > S)
break;
index++;
}
cout << index - 1;
return 0;
}
| [백준 BOJ1946] 신입 사원 (C++) (0) | 2023.07.09 |
|---|---|
| [백준 BOJ13305] 주유소 (C++) (0) | 2023.07.02 |
| [백준 BOJ1026] 보물 (C++) (0) | 2023.07.02 |
| [백준 BOJ2217] 로프 (C++) (0) | 2023.07.02 |
| [백준 BOJ1931] 회의실 배정 (C++) (0) | 2022.10.10 |
1. 제목
- 백준 1026 보물
- BOJ 1026 보물
문제 링크 : 1026번: 보물 (acmicpc.net)
1026번: 보물
첫째 줄에 N이 주어진다. 둘째 줄에는 A에 있는 N개의 수가 순서대로 주어지고, 셋째 줄에는 B에 있는 수가 순서대로 주어진다. N은 50보다 작거나 같은 자연수이고, A와 B의 각 원소는 100보다 작거
www.acmicpc.net
2. 풀이 과정
배열 A와 배열 B를 곱해서 최소의 수를 만들기 위해선 가장 높은 수 와 가장 낮은 수를 곱하면 됩니다.
1. 배열 A는 오름차순 정렬, 배열 B는 내림차순 정렬
2. 각 정렬된 배열 A와 배열 B를 곱한 후 더해줍니다.
3. 코드
// 배열 A와 배열 B를 곱해서 최소의 수를 만들기 위해선 가장 높은 수 와 가장 낮은 수를 곱하면 됩니다.
// 1. 배열 A는 오름차순 정렬, 배열 B는 내림차순 정렬
// 2. 각 정렬된 배열 A와 배열 B를 곱한 후 더해줍니다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
// 내림차순
bool Compare(int num1, int num2)
{
if (num1 > num2)
return true;
return false;
}
int main()
{
int N;
cin >> N;
vector<int> A(N), B(N);
for (int index = 0; index < N; index++)
cin >> A[index];
for (int index = 0; index < N; index++)
cin >> B[index];
// 1. 배열 A는 오름차순 정렬, 배열 B는 내림차순 정렬
sort(A.begin(), A.end());
sort(B.begin(), B.end(), Compare);
int result = 0;
// 2. 각 정렬된 배열 A와 배열 B를 곱한 후 더해줍니다.
for (int index = 0; index < N; index++)
result += A[index] * B[index];
cout << result << endl;
return 0;
}| [백준 BOJ13305] 주유소 (C++) (0) | 2023.07.02 |
|---|---|
| [백준 BOJ1789] 수들의 합 (C++) (0) | 2023.07.02 |
| [백준 BOJ2217] 로프 (C++) (0) | 2023.07.02 |
| [백준 BOJ1931] 회의실 배정 (C++) (0) | 2022.10.10 |
| [백준 BOJ11399] ATM (C++) (0) | 2022.10.10 |