맨 처음 입력 값을 받을 때에는 단순히 텍스트 길이로 계산을 해서 문자 상관없이 무조건 입력 값 하나당 길이가 1이었다. 하지만 보통 한글은 2byte, 영어/공백/특수문자는 1byte로 계산을 하기 때문에 이를 맞춰주기 위해 로직을 다시 작성했다. [ Encoding.Defalut ]int userNameByteCnt = Encoding.Defalut.GetByteCount(inputUserName.text);int farmNameByteCnt = Encoding.Defalut.GetByteCount(inputFarmName.text);Defalut로 했을 때에는 한글은 3byte, 영어는 1byte로 계산이 돼서 한글을 6글자로 제한하면 영어는 18글자까지 입력 가능해서 원하는 대로 동작하지 않았다...
전체 글
[ 확인 문제 ]1. LinkedList가 무엇인지 알고 있나요? 어떤 방식으로 작동하는지 설명할 수 있을까요? : 링크드 리스트는 데이터를 가지고 있는 노드들이 연결된 구조로, 각 노드는 이전과 다음에 있는 노드와 연결되어 있다. 이 연결을 통해서 이전, 다음으로 움직이며 데이터를 탐색한다. 2. inkedList를 직접 구현해본 경험이 있을까요? 없다면 직접 구현해봅시다. 더보기💡 LinkedList 클래스를 직접 구현해보세요.클래스 및 주요 멤버 변수Node: 데이터와 다음 노드를 저장하는 내부 클래스.Data: 노드가 저장하는 데이터.Next: 다음 노드를 가리키는 포인터.My_LinkedList: LinkedList를 구현하는 클래스.head: 리스트의 첫 번째 노드를 가리키는 포인터.coun..
2024.07.03 - [Coding/Unity] - [내일배움캠프 55일차 TIL] 2D 하루 낮밤과 다음 날 구현하기 [내일배움캠프 55일차 TIL] 2D 하루 낮밤과 다음 날 구현하기[ URP 설정 ]2D에서 빛을 이용해 낮과 밤을 만들고 싶다면 URP 설정이 되어있어야 한다.URP는 Universal Render Pipeline으로 빌트 인(Built-In) 보다 향상된 그래픽 품질을 제공하는 파이프 라인이다. 유니티siknyang.tistory.com저번에 24시간 내내 시간이 흘러가고, 시간에 맞춰 빛 색이 변화하는 기능을 구현했다. 이번에는 침대에서 잠을 자면 다음 날 오전 6시로 넘어가는 기능을 추가했다. [ 수면 시스템 구현] 전체 코드using System.Collections;usin..
[ URP 설정 ]2D에서 빛을 이용해 낮과 밤을 만들고 싶다면 URP 설정이 되어있어야 한다.URP는 Universal Render Pipeline으로 빌트 인(Built-In) 보다 향상된 그래픽 품질을 제공하는 파이프 라인이다. 유니티 버전 2022.3.17f1빌트 인으로 시작했더라도 패키지 매니저에서 URP를 설치하면 사용할 수 있다. URP를 검색해서 Install을 누르면 자동으로 설치된다. 이후 렌더링 토글에 생성 가능한 URP 파일들이 생기는데, URP Asset (with Universal Renderer)을 누르면 프로젝트 탭에 두 파일이 생성된다. 프로젝트 세팅에서 Graphics의 Scriptable Render Pipeline Settings에 아까 생성되었던 파일 중 _Asset..
[ 확인 문제 ]using System;// 사각형 클래스public class Rectangle{ public double Width { get; set; } public double Height { get; set; } public double CalculateArea() { return Width * Height; }}// 원 클래스public class Circle{ public double Radius { get; set; } public double CalculateArea() { return Math.PI * Radius * Radius; }}// 면적 계산기 클래스public class AreaCalculator{ ..
[ 확인 문제 ]using System;public class Car{ // 속성 public string Make { get; set; } public string Model { get; set; } public int Year { get; set; } // 메서드 public void DisplayInfo() { Console.WriteLine($"Car Make: {Make}, Model: {Model}, Year: {Year}"); }}class Program{ static void Main(string[] args) { Car car1 = new Car(); car1.Make = "Genesis"; ..
[ 트러블 슈팅 ]적이 죽고 리스폰되지 않음적을 구현할 때 오브젝트 풀을 이용해서 생성, 제거를 반복하지 않고 계속해서 가져다 쓰는 기능을 구현했다. 하지만 맨 처음 풀 사이즈만큼 적들이 생성되고 죽고 나면 다시 리스폰되지 않는 현상이 발생했다. private IEnumerator DestroyAfterDelay(float delay) { yield return new WaitForSeconds(delay); Destroy(gameObject); // 오브젝트 파괴 }그 이유는 적이 죽고 오브젝트를 씬에서 삭제하는 코루틴에서 적 오브젝트 자체를 파괴해버려서 다시 큐에 들어가지 못했기 때문에 생성되지 않았다. private IEnumerator DestroyAfterDe..
[ 오브젝트 풀에서 큐의 동작 원리 ]오브젝트 풀에서 자주 사용되는 것이 선입선출 구조인 큐(Queue)이다. 큐에 오브젝트를 넣을 때는 Enqueue 메서드, 뺄 때는 Dequeue 메서드를 사용하라고 해서 사용하곤 있지만, 오브젝트 풀에서 정확히 어떤 원리로 동작하고 있는지 이해를 해야 적절한 시점에서 해당 메서드들을 사용할 수 있다. 큐와 오브젝트예를 들어 설명하자면 큐는 관리자, 오브젝트는 일꾼이다. 일꾼들이 작업할 순서를 정해주는 것이 큐의 역할이다.활성화는 작업 중인 것이고, 비활성화는 작업을 하고 있지 않은 상태이다.모집 인원에 맞춰 이제 막 고용된 일꾼들은 일을 하고 있지 않는다. Enqueue()맨 처음 일꾼들이 일을 하러 와서 관리자에게 출석 확인을 한다. 작업 명단을 작성해서 관리자가..
[ 플레이어 데이터 ]데이터가 저장되어 있는 변수를 바로 사용하는 것이 아니라, 직렬화하려는 데이터들만 따로 별도의 class나 struct로 만든다. public class Character : MonoBehaviour{ public UserData data; private void Start() { data.nickname = "식냥"; data.lv = 7; data.hp = 100; } private void Update() { // JSON 직렬화 if (Input.GetKeyUp(KeyCode.Q)) { var jsonData = JsonUtility.ToJson(data); ..
2024.05.10 - [Coding/Unity] - [내일배움캠프 19일차 TIL] New Input System, 이벤트 처리 [내일배움캠프 19일차 TIL] New Input System, 이벤트 처리사용자가 플레이어를 움직이기 위해서 키보드 방향키를 눌렀다. 그러면 플레이어는 이동에 대한 입력을 받은 것이다. 우리는 입력이 들어오면 이동과 관련된 모든 메서드들이 실행되기를 원한siknyang.tistory.com지금까지는 계속 Player Input component로 이벤트를 호출하는 방식을 사용했다. 2024.06.12 - [Coding/Unity] - [내일배움캠프 40일차 TIL] Input System 다이렉트, 임베디드, 액션 에셋, C# 제너레이트, Action Properties [..
[ 파티클 시스템(Particle System) ]반짝이는 효과나 마법진 같은 이펙트를 제작하는 데 활용되는 컴포넌트이다.이펙트에 사용되는 오브젝트 하나하나를 파티클이라고 부르며, 파티클 시스템은 이런 수천 개의 파티클의 동작과 생애를 체계적으로 관리한다.파티클 시스템의 주요 컴포넌트는 emitter(발사체), particles(파티클), animator(애니메이터), renderer(렌더러) 등이 있다.시간에 따른 파티클의 행동을 시뮬레이션하면서 각 파티클의 위치, 속도, 수명, 색상, 크기 등의 정보를 저장한다.파티클 시스템은 최대 파티클 수 제한, 적용 범위 제한 등과 같은 기능으로 성능 최적화를 한다. 주요 모듈Main 모듈가장 기본적인 값인 파티클의 속도, 크기, 회전, 최대 개수를 정할 수 있..
[ InputSystem ]기존에는 인풋 액션 창에서 키를 직접 설정하고 인풋 시스템 컴포넌트를 추가해서 사용했다. 하지만 코드 작성으로 인풋 시스템을 사용할 수도 있다.캐릭터가 A키와 D키를 통해 좌우로 움직이는 로직을 코드를 사용해서 구현해보자. 우선 기본적으로 스크립트에서 인풋 시스템을 사용하려면 UnityEngine.InputSystem 네임스페이스가 있어야 한다.using UnityEngine.InputSystem; 다이렉트다이렉트 방식은 코드로 모든 입력을 받아오는 로직을 작성한다.public float dir;Keyboard keyboard;void Start(){ keyboard = Keyboard.current; // 현재 연결된 기기 받아옴}void Update(){ if(keyboar..
[ 아이템 데이터 NullReferenceException 에러 ]트러블 슈팅클릭한 오브젝트, 놓인 오브젝트, 들고 있는 오브젝트 비교해서 모두 동일하면 해당 오브젝트를 보이게 하는 코드가 있다. 기존에는 테스트를 위해 전역 변수로 직접 인스펙터 창에서 오브젝트를 할당해서 사용했는데, 팀원들과 작업물을 합치면서 플레이어가 실제로 장착하고 있는 아이템의 정보를 가져오는 코드로 수정했다. 하지만 플레이어가 항상 아이템을 장착하고 있는 것이 아니기 때문에, 아이템을 장착하고 있지 않을 때 클릭을 하면 NullReferenceException 에러가 뜬다. GameObject curItem = CharacterManager.Instance.Player.equipItem.ItemPrefab;if (curItem ..
[ 오브젝트 컴포넌트에 플레이어 위치 자동 할당 ]트러블 슈팅건물 에셋을 가져왔는데, 기존에 있던 임시 플레이어를 삭제하고 새로운 플레이어를 생성했더니 기존에 할당되어 있던 플레이어 오브젝트가 모두 None이 되면서 문이 열리지 않게 되었다. 문 외에도 서랍장, 창문 등 열리고 닫히는 오브젝트와의 상호작용 자체가 되지 않았다. 모든 것을 할당하기에는 오브젝트가 몇 백개라서 현실적으로 일일이 할당하기란 불가능했다. 오브젝트가 프리팹이라서 프로젝트에서 프리팹을 수정하면 되지 않을까했는데, 스크립트가 있는 오브젝트가 자식 오브젝트라서 플레이어를 할당할 수 없었다. 그리고 오브젝트 수도 엄청 많아서 이것도 현실적으로 불가능했다. 그래서 각 오브젝트에 있는 스크립트를 수정하는 방향으로 해결했다. 문을 여닫고 싶은..
[ 패시브 아이템 사용 불가 버그 ]트러블 슈팅컨디션과 관련된 아이템은 정상적으로 사용되고 UI에도 적용이 됐지만, 패시브와 관련된 아이템은 사용부터 되지 않는 버그가 있었다. 사용하기 버튼을 누르면 NullReferenceException: Object reference not set to an instance of an object 에러가 떴다. 원인을 확인하기 위해서 에러가 발생하는 코드에서 디버깅을 했다. 디버깅을 했을 때 UIInventory 스크립트의 OnUseButton 메서드에서 passive에 null 값이 있어서 에러가 발생했다. 해당 스크립트에서 정의된 passive 변수에서도 null이 떴다. 원인은 PlayerPassive 스크립트와 UIInventory 스크립트와의 연결이 잘 되..
[ 인벤토리 아이템 NullReferenceExeption 에러 ]트러블 슈팅인벤토리에 들어온 아이템을 클릭하면 오브젝트를 찾을 수 없다는 NullReferenceException: Object reference not set to an instance of an object 에러가 뜬다. 에러가 뜬 줄에서 디버깅을 했더니 selectedItem이 null이었다.selectedItem에서는 slots[index].item이 null이었다.slots[index].item이 있는 if문을 확인해보니 == 연산자를 사용해서 값이 null인지 확인하는 조건이 되게 해야하는데, = 연산자를 사용해서 null이 할당되어 있었다. == 연산자로 수정했더니 정상적으로 작동되었다. [ 인벤토리 창의 아이템 능력치 표시 ..
[ 스크립터블 오브젝트 ]스크립터블 오브젝트(ScriptableObject)는 유니티에서 데이터를 저장하고 관리하는 일종의 컨테이너이다. 오브젝트에 대한 데이터 및 설정을 스크립터블 오브젝트에 저장하고, 이를 다른 오브젝트에 적용해서 재사용할 수 있다. 인스펙터 창에서 직접 수정하고 관리할 수 있다. using UnityEngine;[CreateAssetMenu(fileName = "Stat", menuName = "Monster/Defalut")]public class StatSO : ScriptableObject{ public string name; public int level; public float attackDemage;}예를 들어 몬스터에 대한 이름, 레벨, 공격력에 대한 데..
[ 절차 지향 VS 객체 지향 ]이전에는 순서대로 코드를 실행하는 방식인 절차 지향 프로그래밍으로 개발을 했다. 그러나 복잡한 시스템에서는 코드를 관리하고 오류를 추적하는 것이 어려우며, 한 부분에서 문제가 발생하면 이후의 모든 절차에 영향을 줄 수 있다는 단점이 있었다. 이러한 문제를 보완하기 위해 등장한 방식이 객체 지향 프로그래밍이다. 데이터와 함수를 객체 단위로 묶어서 각 객체가 독립적으로 동작할 수 있게 하여 재사용성을 높이고 유지보수가 편리해졌다. [ 특징 ]객체 지향 프로그래밍의 가장 큰 특징은 아래 4가지가 있다.① 추상화: 공통적인 속성과 기능을 추출하여 정의한다② 상속: 기존 코드를 확장하여 새로운 기능을 만들 수 있다③ 다형성: 같은 메서드와 클래스를 다른 방식으로 구현할 수 있다④ ..
[ 애니메이션 적용 ]트러블 슈팅애니메이션을 적용했을 때 스프라이트가 바뀌면서 캐릭터가 깜빡거리는 현상이 발생했다.또한 CameraController가 오브젝트의 위치를 참조하지 못하면서 카메라 화면도 이동하지 않게 됐다. 캐릭터 오브젝트를 할당하지 않았던 간단한 문제였다. 이후 정상적으로 깜빡임 현상 없이 카메라 화면도 잘 움직였다. 너무 기본적인 거라 당연히 했을 거라고 생각하고 까먹을 때가 있는데, 뭔가 잘 안 된다면 일단 컴포넌트에 오브젝트를 할당했는지 체크해 보자. [ 이름 입력 ]StartScene을 생성해서 이름을 입력하고 Join 버튼을 누르면 MainScene으로 이동한다. 단, 이름은 2~10글자여야 한다. 트러블 슈팅public class JoinButton : MonoBehaviou..
[ 카메라 추적 ]구현 코드카메라가 캐릭터의 움직임을 따라가고 함께 이동하기 때문에, TopDownMovement 클래스에서 캐릭터 이동 메서드에 카메라 이동 코드를 구현하면 되지 않을까 하고 생각했다.하지만 메서드를 구분해 놓는 것이 찾기도 쉽고 구현도 편할 것 같아서 CameraController 클래스를 새롭게 생성했다. //최종 코드public class CameraController : MonoBehaviour{ private Camera camera; public Transform chracterPos; public Vector3 offset = new Vector3(0, 0, -10); private void Awake() { camera = Camer..
사용자가 플레이어를 움직이기 위해서 키보드 방향키를 눌렀다. 그러면 플레이어는 이동에 대한 입력을 받은 것이다. 우리는 입력이 들어오면 이동과 관련된 모든 메서드들이 실행되기를 원한다. 이는 이벤트 핸들링을 통해 해결할 수 있다. 잠깐! 근데 그냥 입력된 이동을 처리하는 메서드에서 관련된 메서드를 바로 호출하면 되는 것 아닌가요🤔?이 의문을 해결하기 위해서는 New Input System을 알아야 한다. [ New Input System ]기존에 사용되던 InputManager에서 모든 기능들이 하나의 클래스에 존재하여 발생하는 문제점을 보완한 것이다. 기능별로 클래스를 나눠서 구현하는 것은 객체 지향 프로그래밍에서 매우 중요한 요소이기 때문에, New Input System을 이용하면 수월하게 로직을..
[ 쿼터니언 ]쿼터니언은 3차원 회전을 표현할 때 사용되고, 유니티에서는 오브젝트의 회전을 처리한다. 유니티 인스펙터 창의 회전은 3차원 벡터로 표현되고, 이를 오일러 각이라고 한다. 오일러 각은 피치(Pitch)는 x축, 요(Yaw)는 y축, 롤(Roll)은 z축을 기준으로 회전한다. 이때 하나의 축에서 과한 회전이 일어나 다른 회전축과 평행하게 됐을 때 짐벌락(Gimbal Lock)이 발생한다. 두 개의 회전축이 겹쳐지면서 기존의 축이 방향을 잃어버리는 것이다. 쿼터니언을 이용하면 이러한 짐벌락 문제를 피할 수 있다. 쿼터니언은 수학적으로 (x, y, z, w) 형태의 4가지 숫자로 구성되어 있고, 이를 직접 조정할 수는 없다. 대신 Quaternion.Euler, Quaternion.LookRota..
[ 게임 엔진 ]게임 엔진이란 게임 개발에 필요한 여러 기능들을 제공하는 프로그램이다. 그래픽, 사운드, 애니메이션 등과 같은 다양한 요소들을 관리하고 통합한다. [ 스크립트 ]컴포넌트는 Monobehavior를 상속받고 있는 것들이다.Monobehaviour를 상속 받는 클래스는 유니티 이벤트 함수를 활용할 수 있고, 게임 오브젝트에 있는 이벤트 함수들은 특정 순서에 따라 호출되는 라이프 사이클을 가지고 있다. [ PPU ]Pixels Per Unit의 약자로, 스프라이트 픽셀 수 / 해당 스프라이트의 값이 게임 세계에서 차지하는 공간이다. 따라서 PPU 값이 클수록 스프라이트의 크기는 작아진다. 예를 들어 100 PPU는 1단위의 공간에 100개의 픽셀이 배치됨을 의미한다. 500 PPU는 1단위의 ..
[ 제네릭 ]제네릭은 데이터 타입을 일반화해서 다양한 자료형에 대응할 수 있게 한다. 를 사용해서 특정 자료형 없이 선언한 뒤, 이를 사용할 때 원하는 자료형을 입력한다. 제네릭을 사용하면 코드를 재사용성을 높이고, 컴파일 오류를 줄여 타입 안전성을 제공한다. public class Inventory{ private T content; public void Put(T item) { content = item; } public T Get() { return content; }}제네릭 타입 를 사용해서 특정 자료형을 미리 정의하지 않고 아이템을 저장하거나 꺼낼 수 있는 코드를 작성했다. public class Program{ public s..
[ 로직 설계하기 ]노션에 구현할 기능에 대한 요소들을 정리한 뒤, 이를 바탕으로 코드를 짰다.먼저 콘솔 창에 보이길 원하는 화면을 적는다. 화면의 내용들이 보이기 위해서 필요한 코드들을 구현해 나가는 방식으로 진행하면, 일이 훨씬 수월하게 진행된다.저 기능을 어디에 구현해야 할지 위치를 파악하기 위해서 어떤 시점에서 해당 기능이 구현되는지도 정리했다. 이름 입력 메서드 마지막에 직업 선택 메서드를 불러오고, 직업 선택이 끝나면 메인 메뉴 메서드를 불러오면 된다.이외에도 직업에 관련된 정보들을 미리 정리해 놓고, 클래스나 코드를 미리 구현해서 실행시켜 보기도 했다.최종적으로 완성된 코드는 처음과는 매우 달랐지만, 노션을 통해 내 생각을 정리함으로서 빠르게 시작할 수 있었고 어떤 순서로 진행해야 할지도 감..
[ 추상 클래스 ]구조public abstract class Character{ public int Health { get; set; } public abstract void Move(); public void TakeDamage(int damage) { Health -= damage; }}추상 클래스는 접근제한자 뒤에 abstract 키워드를 넣어서 만들 수 있다. 클래스 내에는 abstract 키워드가 있는 추상 메서드와 넣지 않은 일반 메서드가 포함된다. 추상 메서드는 구체적인 구현을 포함하지 않고 선언만 한다. public class Player : Character{ public override void Move() { Deb..
[ 클래스 ]클래스 변수 사용//옳은 예class Program{}class StartGarme{}//틀린 예class Program{ class StartGame { }}클래스는 클래스를 변수로 사용할 수 있다. 이 말은 하나의 파일에 여러 개의 클래스가 들어갈 수 있다는 것이고, 이중클래스의 의미는 아니다. 메모리 구조메모리의 구조는 코드 영역, 데이터 영역, 힙 영역, 스택 영역으로 나뉘어 있다.코드 영역은 사용자가 실제로 작성한 코드가 실행되는 곳이다.데이터 영역은 대표적으로 static을 사용한 코드가 있다. static은 프로젝트 전반에 필요하고 공유되어야 하는 데이터에 사용한다. int num; 처럼 변수를 선언했을 때에는 스택 영역에 들어간다. 그리고 num 변수에 값 1을 할당..
다중 상속은 이름이 같은 멤버가 있을 때 어떤 부모 클래스의 것을 사용해야 하는지 모호해지고, 이렇게 이름이 충돌했을 때 이를 명확히 해주어야 하기 때문에 코드가 복잡해진다. 따라서 단일 상속을 통해서 관계를 명확하고 단순하게 해서 코드의 가독성과 이해도를 높인다. 하지만 경우에 따라서 다중 상속이 필요할 때도 있다. 이럴 때는 인터페이스라는 개념을 사용한다. [ 인터페이스 ]public interface IItemPickable{ void PickUp();}public interface IUseable{ void Use();}public class Item : IItemPickable, IUseable{ public string Name { get; set; } public voi..
[ 배열 VS 리스트 ]배열(Array)은 크기가 1로 고정되지 않고, 확장성을 가지고 있어 크기를 그 이상으로 설정할 수 있다. 하지만 한 번 크기를 설정하고 난 이후에는 크기를 바꿀 수 없는 정적 배열이다. 만약 크기를 바꾸고 싶다면 새로운 배열을 선언해야 한다. 게임에서는 스킬들을 배치하는 스킬 단축키에서 쓰일 수 있다. 메모리에 데이터가 연속적으로 저장되어 있고, 메모리 내에 데이터들이 정리가 되어 있기 때문에 새로운 데이터를 추가할 수가 없다. 따라서 원래 배열에서 새로운 데이터를 추가하고 싶다면, 기존의 배열을 바탕으로 새로 생성해서 자리를 만들어야 한다. 하지만 자리가 고정되어 있기 때문에 접근하는 것이 용이하다. 선언한 크기를 모두 사용하면 리스트보다 메모리를 효율적으로 사용할 수 있지만,..