이전에 만들었던 킹덤러시는 꽤 많은 컨텐츠를 구현했기에, 입력해야 데이터의 양도 꽤 많았다. 그래서 기억으로는 데이터를 입력하는데만 1주일이 넘게 걸렸었다. 이때 스테이지 에디터를 구현하여 사용할 데이터를 찍고, 바이트단위로 직렬화하여 txt파일로 저장하였는데, 이 파일을 재사용할 수 만 있다면, 1주일이라는 시간을 버는 것과 다름이 없다. 그렇기 때문에 Deserializer를 만들었다.
using Assets.Scenes.Object.Stage.ContentsEnum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.VisualScripting;
using UnityEngine;
namespace Assets.Scenes.Object.Base
{
internal class MyDeserializer
{
private Array Data;
UInt64 Offset = 0;
public void ReadFile(byte[] File)
{
Data = File;
}
public void Read(ref int Value)
{
byte[] intBytes = BitConverter.GetBytes(Value);
Read(intBytes, sizeof(int));
Value = BitConverter.ToInt32(intBytes);
}
public void Read(ref float Value)
{
byte[] floatBytes = BitConverter.GetBytes(Value);
Read(floatBytes, sizeof(float));
Value = BitConverter.ToSingle(floatBytes);
}
public void Read(ref MonsterEnum Value)
{
int temp = (int)Value;
Read(ref temp);
Value = (MonsterEnum)temp;
}
public void Read(Array Dest, int Size)
{
Buffer.BlockCopy(Data, (int)Offset, Dest, 0, Size);
Offset += (UInt64)Size;
}
}
}
구현 자체는 간단하다. 바이트단위 버퍼, 데이터 기록 오프셋, 그리고 데이터를 버퍼에 입력할 방법만 있으면 된다. C#에서는 void ptr은 커녕 ptr조차 잘 사용하지 않기 때문에, 조금 다른 방식을 사용하였다.
기능을 지원해준다. System.IO.File에 있는 ReadAllBytes("파일 경로") 함수를 사용하면, 해당 파일을 byte[](바이트 단위 배열 자료형이다)에 담아 반환해준다. 또한 byte[]는 Array로 암시적 형변환이 된다. 파일을 받아 Array Data에 저장해준다.이 방법으로 파일을 로드하게 되면, 경로 오류가 생기기 때문에, 빌드 시 exe파일로 실행하게 됐을 때 문제가 생긴다.
Resources 클래스를 사용할 것을 권장한다. Asset/Resources폴더에 있는 모든 파일을 동적 로드 할 수 있게 도와주는 클래스이다. Data를 TextAsset타입으로 받은 후 .bytes를 통해 byte[]로 받을 수 있다.
프로젝트를 진행하면서 느낀 점은, 프리팹이던 애니메이터건 내가 로드해서 사용할 필요가 있는 파일들은 그냥 Resources폴더에 넣는게 맞다.
C의 memcpy_s에 해당하는 함수인 Buffer.BlockCopy(Src, SrcOffset, Dest, DestOffset, Size)함수를 사용한다. Src에서 SrcOffset부터 Size만큼 복사한 데이터를 Dest에 DestOffset부터 붙여넣는 방식으로 작동한다. 이 함수는 포인터가 아니라 배열을 받기 때문에 사용하는 데이터들(Src, Dest)이 Array형태로 있어야할 필요가 있다. 이때문에 Dest의 Buffer를 byte[]로 컨버팅하는 방법을 알아야한다.
BitConverter.GetBytes(Value) 함수를 사용한다. Value를 byte[]로 반환해준다.
private void LoadOneLine(MyDeserializer Buffer, int StageIndex, int PathIndex)
{
int PointSize = 0;
Buffer.Read(ref PointSize); //배열에 담겨있는 자료의 개수 정보를 읽음
LinePath CurLineData = AllStageData[StageIndex].Lines[PathIndex];
CurLineData.Points.Capacity = PointSize;
for (int i = 0; i < PointSize; i++)
{
Vector4 temp = new Vector4(0f, 0f, 0f, 0f);
Buffer.Read(ref temp.x); //x좌표 읽기
Buffer.Read(ref temp.y); //y좌표 읽기
Buffer.Read(ref temp.z); //z좌표 읽기
Buffer.Read(ref temp.w); //w 읽기
temp = MyMath.CentimeterToMeter(temp); //측량치를 나누기 100 해야 정상작동
CurLineData.Points.Add(temp); //데이터 추가
}
}
매우 잘 작동합니다. 저는 컨텐츠 구현만 하면 바로 6개의 스테이지가 완성될 예정입니다. ★★★★★