Tiny island 프로젝트 01

Summary
Tiny Island Project에 대하여
카테고리
Private Projects
Original creation date
Jun 3, 2020
생성일
Jan 30, 2026 12:56 AM
태그
tinyisland
unity

1.Tiny Island Project?

  • 일단 모바일 게임 프로젝트이다. AOS/iOS 모두 출시예정이다
  • 모바일게임 특성상 조작이 불편하기에 한손조작을 택했다.
  • 내가 좋아하는 콘솔게임은 거의 위쳐/젤다의전설과같은 스토리가 가미된 RPG게임이라고 정리할수있다. 모바일게임은 정말 왠만해서는 즐겨하지않기에 나도 즐길수있는 모바일게임을 목표로 만들기시작한다.
  • 스토리는 다크소울이나 블러드본과같이 불친절한 스토리보다는 선형적이고 쉬운 스토리가 좋더라. 메인스토리는 굵고 진하게 있으면서 서브스토리에서 자유도를 주는게 내 취향이기에 요렇게 만들어보고자한다.
  • 개발지향성은 가볍게 빨리 만들어서 빠르게 출시하자인데, 요건 조금 오래걸릴것같긴하다. RPG를 만든다는건 진짜 어려운일이다. > - 아트스타일은 스타일이라고 할것도없다. 거의 에셋스토어에서 구매해서 조정하는식으로 가야할것같다. 다음번에는 2D 도트스프라이트를 도전하기로하고 이번에는 꼭 해보고싶어서 계속 도전했지만 매번 접었던 3D 로우폴리곤 스타일 게임을 만들어보고자한다.

2.진척사항은?

  • 2020년 6월 현재, 프로젝트생성한지는 두달정도된것같다. 겁나빠르네
  • 현재 유니티 기본터레인으로 가장 기본이되는 섬을 60%정도 만들었다.
  • Triplanar Shader를 통해 절벽과 평지를 자연스럽게 블렌딩하게하고, 터레인 모델링이 완성되면 이를 mesh로 변환하여 유니티 polybrush를 통해 버텍스컬러를 칠해서 평지의 길등을 블렌딩하려고 한다.
기본 세로 한손모드로 섬에서 펼쳐지는 이야기
{: .align-center}
현재개발스크린샷. 섬에서 펼쳐지는 이야기.
  • grass도 잘 넣고싶은데 지오메트리쉐이더를 통해서 풀을 만들고싶었는데 ios metal에서는 이 쉐이더가 작동이 안되는것같다.. 결국 그냥 mesh를 c#에서 조정해서 만들어봤다. 요건 계속 조정해봐야할듯.
  • 캐릭터 이동은 에셋스토어에서 사서 써봤다. 게속 캐릭터컨트롤러 혼자서 만들어서 썼었는데 굴곡있는 지형에서 갑자기 뚫고내려간다던가, 경사에서 붙어버린다던가 하는 버그가 계속있어서 스트레스.. 역시 잘만든 코드 가져다 쓰는게 최고긴하다. 잘된다. 나중에 요 코드 공부해서 내것으로 만들긴해야지. (사용한 에셋은 다음과같다:Character Controller Fundamentals)
  • 카메라 워크는 역시 유니티에서 제공하는 시네머신을 사용했다. 빠르게 만드는게 중요하다.
모델링도 커스터마이징이 필요하다
{: .align-center}
모델링도 커스터마이징해야한다. 일단synty studio 에서 받은 에셋을 사용중이다

3.해야할것들

아직 엄청 많다. 큰 골격으로 조만간해야할것들은 다음과같다.
  1. 기본적인 전투기획. 어떻게 공격하고 회피하고 할지 정하지못했다.
  1. 적 AI구현. 일단 단순 스테이트머신이아니라 행동트리로 구현하기로 결정.
  1. 퀘스트 구조 짜기.
  1. 컷씬 및 이벤트 관련 매니저.
  1. 아트적인건 거의 다 스토어에서 살거긴하지만, 조금씩 조정하려면..

암튼 엄청 많다. 몇달은 걸릴것같은 장기프로젝트이다. 다음달에 각을 봐서 프로토타입을 일단 만들고 출시일을 설정해야겠다.

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; }