1.Tiny Island Project?
- 일단 모바일 게임 프로젝트이다. AOS/iOS 모두 출시예정이다
- 모바일게임 특성상 조작이 불편하기에 한손조작을 택했다.
- 내가 좋아하는 콘솔게임은 거의 위쳐/젤다의전설과같은 스토리가 가미된 RPG게임이라고 정리할수있다. 모바일게임은 정말 왠만해서는 즐겨하지않기에 나도 즐길수있는 모바일게임을 목표로 만들기시작한다.
- 스토리는 다크소울이나 블러드본과같이 불친절한 스토리보다는 선형적이고 쉬운 스토리가 좋더라. 메인스토리는 굵고 진하게 있으면서 서브스토리에서 자유도를 주는게 내 취향이기에 요렇게 만들어보고자한다.
- 개발지향성은 가볍게 빨리 만들어서 빠르게 출시하자인데, 요건 조금 오래걸릴것같긴하다. RPG를 만든다는건 진짜 어려운일이다.
- 아트스타일은 스타일이라고 할것도없다. 거의 에셋스토어에서 구매해서 조정하는식으로 가야할것같다. 다음번에는 2D 도트스프라이트를 도전하기로하고 이번에는 꼭 해보고싶어서 계속 도전했지만 매번 접었던 3D 로우폴리곤 스타일 게임을 만들어보고자한다.
2.진척사항은?
- 2020년 6월 현재, 프로젝트생성한지는 두달정도된것같다. 겁나빠르네
- 현재 유니티 기본터레인으로 가장 기본이되는 섬을 60%정도 만들었다.
- Triplanar Shader를 통해 절벽과 평지를 자연스럽게 블렌딩하게하고, 터레인 모델링이 완성되면 이를 mesh로 변환하여 유니티 polybrush를 통해 버텍스컬러를 칠해서 평지의 길등을 블렌딩하려고 한다.
현재개발스크린샷. 섬에서 펼쳐지는 이야기.
- grass도 잘 넣고싶은데 지오메트리쉐이더를 통해서 풀을 만들고싶었는데 ios metal에서는 이 쉐이더가 작동이 안되는것같다.. 결국 그냥 mesh를 c#에서 조정해서 만들어봤다. 요건 계속 조정해봐야할듯.
- 캐릭터 이동은 에셋스토어에서 사서 써봤다. 게속 캐릭터컨트롤러 혼자서 만들어서 썼었는데 굴곡있는 지형에서 갑자기 뚫고내려간다던가, 경사에서 붙어버린다던가 하는 버그가 계속있어서 스트레스.. 역시 잘만든 코드 가져다 쓰는게 최고긴하다. 잘된다. 나중에 요 코드 공부해서 내것으로 만들긴해야지. (사용한 에셋은 다음과같다:Character Controller Fundamentals)
- 카메라 워크는 역시 유니티에서 제공하는 시네머신을 사용했다. 빠르게 만드는게 중요하다.
모델링도 커스터마이징해야한다. 일단synty studio 에서 받은 에셋을 사용중이다
3.해야할것들
아직 엄청 많다. 큰 골격으로 조만간해야할것들은 다음과같다.
- 기본적인 전투기획. 어떻게 공격하고 회피하고 할지 정하지못했다.
- 적 AI구현. 일단 단순 스테이트머신이아니라 행동트리로 구현하기로 결정.
- 퀘스트 구조 짜기.
- 컷씬 및 이벤트 관련 매니저.
- 아트적인건 거의 다 스토어에서 살거긴하지만, 조금씩 조정하려면..
암튼 엄청 많다. 몇달은 걸릴것같은 장기프로젝트이다. 다음달에 각을 봐서 프로토타입을 일단 만들고 출시일을 설정해야겠다.
4.오늘 한것.
- 오늘은 데이터 매니저를 만들었다.
- 기본적으로 게임데이터를 파일에 쓰고 읽는 역할과 씬간 이동시 데이터를 가지고있는 매니저이다.
- 씬전환시 모든 데이터를 세이브하고 씬로드후에 다시 모든데이터를 로드하며, 파일로 쓰고 읽는건 Easy Save 에셋을 활용하였다. 데이터클래스들은 interface를 상속하였고 이 인터페이스들을 데이터매니저가 hashset/dictionary로 관리한다. 유니티 2d kit 코드를 많이 참고하였다.
관련 코드예제.
public interface IStayableData
{
DataSetting GetDataSetting();
void SetDataSetting(string dataTag, DataSetting.DataPermission permissionType);
Data SaveData();
void LoadData(Data data);
}
public class Data
{
}
public class Data<T> : Data
{
public T value;
public Data(T value)
{
this.value = value;
}
}
public class DataManager : SingletonBase<DataManager> {
private Dictionary<string, Data> dicData = new Dictionary<string, Data>();
private HashSet<IStayableData> hsStaybleData = new HashSet<IStayableData>();
protected override void Awake()
{
base.Awake();
if (Instance != this)
{
Destroy(this.gameObject);
return;
}
DontDestroyOnLoad(this.gameObject);
}
public void Register(IStayableData data)
{
if (!string.IsNullOrEmpty(data.GetDataSetting().dataTag))
{
hsStaybleData.Add(data);
}
}
public void UnRegister(IStayableData data)
{
hsStaybleData.Remove(data);
}
public void ClearRegisers()
{
hsStaybleData.Clear();
}
public void SaveAllData()
{
foreach(var data in hsStaybleData)
{
SaveData(data);
}
}
private void SaveData(IStayableData data)
{
if (data.GetDataSetting().dataPermission == DataSetting.DataPermission.ReadOnly)
return;
dicData[data.GetDataSetting().dataTag] = data.SaveData();
}
public void LoadAllData()
{
foreach (var data in hsStaybleData)
{
if (data.GetDataSetting().dataPermission == DataSetting.DataPermission.WriteOnly)
continue;
if(dicData.ContainsKey(data.GetDataSetting().dataTag)){
Debug.Log(data.GetDataSetting().dataTag);
data.LoadData(dicData[data.GetDataSetting().dataTag]);
}
}
}
public void SavePlayerDataAtFile(int fileNum)
{
SaveAllData();
if(dicData.ContainsKey("Player"))
{
Data<PlayerData> playerData=(Data<PlayerData>)dicData["Player"];
ES3.Save<PlayerData>("PlayerData", playerData.value, "Save/testPlayer.txt");
}
}
public void LoadPlayerDataFromFile(int fileNum)
{
Data<PlayerData> playerData = new Data<PlayerData> (ES3.Load<PlayerData>("PlayerData", "Save/testPlayer.txt"));
dicData["Player"] = playerData;
}
댓글남기기