본문 바로가기

Unity

(11)
C#에서 데이터를 압축하는 코드 유니티로 게임을 만지다 보면 데이터를 직접 압축할 일이 종종 생긴다. 특히 서버와 큰 데이터를 주고받거나 서버에서 굳이 열어보지 않을 데이터를 수집하는 등의 작업에서 압축을 하면 효과를 볼 때가 있다. 아래는 문자열을 압축하는 간단한 코드이다. 유니티서 사용할 경우 동기 버전으로 변형하거나 Task 대신 UniTask 등으로 변형해서 사용할 수 있다. brotli compression in C# brotli compression in C#. GitHub Gist: instantly share code, notes, and snippets. gist.github.com using System.IO; using System.IO.Compression; using System.Text; using System..
코루틴 여러개가 모두 완료될때까지 대기하는 코드 언제 끝날 지 모르는 코루틴 여러개를 동시에 실행하되, 모든 코루틴이 끝날때까지 기다리는 기능이 필요해서 만들어 보았다. 개념으론 Task.WhenAll과 동일한데, Task와 달리 코루틴 여러개를 기다리는 기능은 유니티가 기본으로 제공해주지 않는다. . WaitForCoroutines WaitForCoroutines. GitHub Gist: instantly share code, notes, and snippets. gist.github.com using System.Collections; using UnityEngine; public class WaitForCoroutines : CustomYieldInstruction { public override bool keepWaiting => _remain..
유니티에서 async/await를 어떻게 쓰면 좋을까? async/await는 비동기? 병렬? C#의 async/await와 Task는 비동기를 표현한 것일까 병렬실행을 표현한 것일까? 이 점을 헷갈려하는 사람들이 아주 많다. 결론부터 말하면 Task는 비동기 작업을 표현하는 클래스이다. 그러나 병렬로 실행되기도 한다. 이 점 때문에 Task를 쓰면 멀티스레드를 사용하여 병렬 작업이 일어난다고 알고 있는 경우가 많다. 그러나 이것은 단순히 .NET에 포함된 Task의 구현이 스레드 풀을 사용하도록 되어 있어서 그렇기 때문이다. Task는 어디서 실행될까? await SomethiingAsync(); async Task SomethingAsync() { Console.WriteLine(Environment.CurrentManagedThreadId); await..
Unity에서의 실제 FSM 구현에 대해 들어가며.. 흔히 게임에서 캐릭터를 조종한다던가 할 일이 있을 때 가장 먼저 배우는 것이 유한 상태 기계, FSM이다. FSM에 대해서는 이미 매우 잘 알려져 있고 양질의 정보도 쉽게 접할 수 있으므로 이 글에서 FSM에 대한 상세한 설명은 생략한다. 하지만 FSM이라는 개념에 너무 매몰되어 생각하는 경우 오버엔지니어링이 잔뜩 된 좋지 못한 코드를 쓰는 경우가 종종 있다. 특히 AI의 구현을 FSM으로 구현하려고 할 경우 그렇게 될 가능성이 큰데, 이 글에선 그에 대해 이야기한다. "게임에서의" FSM과 실제 구현에서의 문제 그런데 사실 컴퓨터과학에서 말하는 FSM과 실제로 게임에서 일반적으로 구현하는 FSM은 약간의 차이가 있다. 컴퓨터과학에서 이야기하는 FSM이 어떤 알고리즘을 수학적으로 표현하는 모..
Unity의 ScriptableObject의 활용법 ScriptableObject 유니티의 공식 문서(https://docs.unity3d.com/kr/current/Manual/class-ScriptableObject.html)에는 스크립터블 오브젝트를 다음과 같이 정의하고 있다. ScriptableObject는 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너입니다. ScriptableObject의 주요 사용 사례 중 하나는 값의 사본이 생성되는 것을 방지하여 프로젝트의 메모리 사용을 줄이는 것입니다. 이는 연결된 MonoBehaviour 스크립트에 변경되지 않는 데이터를 저장하는 프리팹이 있는 프로젝트의 경우 유용합니다. 이리저리 꼬아놨지만, 결론적으로는 어떤 데이터를 에셋 형태로 저장하는 기능이다. 스크립터블 ..
Unity의 fake null 문제 유니티 엔진의 구조 UnityEngine.Object를 == null로 비교해서 true가 떨어졌다고 진짜 null인 것은 아니다. 이 문제는 유니티 개발자들에게는 잘 알려져 있는 문제지만, 워낙 직관적이지 않은 문제이기 때문에 유니티를 처음 접하는 사람들은 백이면 백 빠지는 함정이기도 하다. 유니티 코어 레벨의 객체들은 모두 다 C++로 구현되어 있고, C++ 객체로서 존재한다. 유니티 스크립트 상에서 보이는 C# 객체는 C++ 객체를 참조하는 wrapper로 볼 수 있다. 이 C# wrapper 객체는 무조건 생성되는게 아니라, C++ 객체가 C#레벨에서 노출되어야 할 때만 생성되는데, 상황에 따라서는 C++ 객체만 생성되어있고 C# 객체는 생성되어 있지 않을 수도 있다. 하지만 반대로 C++ 객체는..
MonoBehaviour의 초기화는 어떻게 해야 하는가? Awake로 충분하지 않나요? MonoBehaviour의 초기화 메소드로는 유니티에서 Awake, Start 등을 지원하고 있다. 일반적으로 초기화는 Awake에서 하게 될 것이다. using UnityEngine; public class Something : MonoBehaviour { private void Awake() { Debug.Log("awake."); } } 잘 동작한다. 그런데 문서에는 강조되지 않는부분이지만, 생성 당시 GameObject가 비활성화 상태일때는 Awake가 호출되지 않는다. 나중에 활성화되는 시점에 Awake가 호출된다. using UnityEngine; public class SomethingParent : MonoBehaviour { public Something s..
유니티에서 테이블 데이터 로드하기 #4 - Source Generator C#의 Source Generator를 사용하여 직렬화/역직렬화 코드를 생성하는 방법도 있다. 이론적으로 어떤 클래스를 byte array로 변환하려면 각 멤버를 모두 개별적으로 BitConverter 등을 이용해서 순서대로 byte array에 쓰면 되는데, 모든 데이터를 표현하는 클래스에 개별적으로 직렬화하는 코드를 작성하는 방법은 현실적이지 않다. 하지만 C#에는 이럴 때 사용할 수 있는 기능이 있는데, 바로 Source Generator이다. https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview Source Generators Source Generators is a C# compiler featu..
유니티에서 테이블 데이터 로드하기 #3 - Marshal System.Runtime.InterOpServices.Marshal을 사용하여 byte array로 변환하는 방법도 고려해볼 수 있다. 이 방법은 특히 관리되지 않는 형식, 즉 int, float 등으로만 구성된 클래스를 저장하고 읽을 때 빠른 속도를 보여준다. 데이터의 형식에 따라 상당히 달라질 수 있지만 json보다도 3~5배가량의 속도 향상을 기대해볼 수 있다. Marshal은 프로그램이 다른 프로그램에서 사용할 수 있도록 데이터를 전송하는 것을 의미하는데, Marshal을 하려면 직렬화를 하는 경우가 많다. 따라서 .NET에서는 Marshal.StructureToPtr과 Marshal.PtrToStructure를 이용해 간단히 클래스를 byte array로 직렬화하는 메소드를 제공한다. usin..
유니티에서 테이블 데이터 로드하기 #2 - CSV 두번째로 소개할 형식은 CSV이다. 과거에는 비교적 사용 빈도가 높았으나, 최근에는 게임 등 일부 분야를 빼고는 사용 빈도가 많이 줄어든 느낌이다. 장점으로는 사람이 읽고 비교하기가 가장 쉬운 형식이라는 점, 엑셀이나 구글 시트, 오픈오피스 등에서 CSV 익스포트를 모두 지원하기 때문에 간단한 경우 익스포터를 따로 만들 필요가 없다는 점 등이 있다. 단점으로는 CSV 파서는 유니티 내장 기능이 아니다보니 적당한 외부 라이브러리를 찾아와야 하는 점과, 속도가 비교적 느리다는 점 등이 있다. 또한 파서에 따라 빈 컬럼 (,,) 을 빈 문자열 ""로 읽거나 null로 읽는 등 동작이 조금씩 다른 점도 문제가 될 수 있다. C#용 CSV 파서는 여러가지가 있는데, 가장 널리 쓰이는 것은 CsvHelper(htt..