0.들어가기에 앞서
컨디션 관리를 하자... 2일차는 컨디션이 별로 좋지 않아서 투자 시간 대비 작업량이 많지 않았다.
크게 아래와 같이 정리할 수 있겠다
1스테이지 - 튜토리얼 맵 제작
Spell을 오브젝트 풀 패턴으로 구현하여 프리팹을 파괴하지 않고 저장하도록 함
Cinemachine을 통한 카메라워크 구현
Monster 에셋 확보 및 몬스터를 스크립터블 오브젝트로 구현하여 생성할 수 있게 함
추가로 몬스터에 상태 패턴을 적용해서 몬스터의 행동을 구현함
오늘자로 구현한 몬스터의 행동은 대기, 정찰(걷기), 추격, 공격 등을 구현했다.
스크립터블 오브젝트란 걸 다루는 게 익숙하지 않아서, 이를 공부하는 데에 시간 투자를 많이 했던 것 같다.
이에 대해 최종적인 구현 과정을 정리해보고자 한다.
먼저 몬스터의 종류를 다양하게 하기 위해, 스크립터블 오브젝트를 추상 클래스로 구현했다.
using UnityEngine;
public abstract class MonsterData : ScriptableObject
{
public string Name;
public GameObject Prefab;
public int MonsterHp;
public int MonsterAtk;
public int MonsterMoveSpeed;
public abstract void Attack(PlayerController player);
}
이를 상속하여 노멀 몬스터부터 만들 것이기에, NormalMonsterData 스크립터블 오브젝트를 만들었다.
using UnityEngine;
[CreateAssetMenu(fileName = "Normal Monster", menuName = "Scriptable Objects/Normal Monster", order = 1)]
public class NormalMonsterData : MonsterData
{
public float MonsterSight;
public override void Attack(PlayerController controller)
{
controller.TakeDamage(MonsterAtk);
}
}
다음으로 테스트용으로 만든 스크립터블 오브젝트를 소환하는 스크립트, NormalMonsterSummoner를 만든다.
using UnityEngine;
public class NormalMonsterSummoner : MonoBehaviour
{
[field: SerializeField] public MonsterData Data { get; private set; }
private GameObject _childObject;
private void OnEnable()
{
_childObject = Instantiate(Data.Prefab, transform);
}
private void OnDisable()
{
Destroy(_childObject);
}
}
해당 스크립트를 포함한 빈 오브젝트로 프리팹으로 만든다.
여기까지 작업하면 슬라임 프리팹이 정상적으로 소환되는 것을 확인할 수 있었다.
이 다음으로 생성된 몬스터가 행동을 할 수 있도록 NormalMonsterController와, BaseState를 상속한 NormalMonsterState를 만들어 작업하면 된다.
여기서 특히 중요한 것은, 스크립터블 오브젝트의 정보를 가져오기 위해서 인스펙터에서 끼울 수 있도록 설정해주어야 한다는 것이다.
이것 때문에 자꾸 스크립터블 오브젝트의 정보를 사용할 수 없어서 애를 먹었었다.
특히나 상태 패턴 때문에 public으로 참고할 수 있게끔 설정해 두어야만 했다.
이와 같은 방식으로 스크립터블 오브젝트로 구현한 몬스터를 생성하는 방법과, 스크립터블 오브젝트의 정보를 참조한 몬스터의 행동 정의과정이 이루어진다.
몬스터 생성기의 경우에는 나중에 오브젝트 풀로 적용할 여지가 있어 추후에 적용할 예정이다.
이전에 몬스터 움직임을 구현할 때 바닥을 감지하는 방법을 Trigger 충돌체로 구현했었다. 하지만 리서치한 것의 결과로, 몬스터의 마릿수가 많아질수록 충돌체 구현 방식보다 Raycast 방식이 훨씬 비용이 싸다는 것을 아게 되었다.
그래서 이번에는 Raycast 방식으로 몬스터의 바닥 탐지를 구현했다.
또한 벽도 추가로 탐지하기 위해 벽을 탐지하는 Raycast도 쏴서 만들어주었다.
이와 같이 MonsterSummoner로 스크립터블 오브젝트를 생성하고, 그 자식 오브젝트에 컨트롤러를 붙여서 스크립터블 오브젝트의 행동을 정의한다.
Walk로만 탐지되기 전과 탐지 후의 행동을 정의하려 하니, 제약이 심해질 것 같아서 Trace 상태를 따로 만드는 것이 좋겠다는 판단을 했다.
오류 자체는 생각보다 쉽게 고치긴 했지만 짚고 넘어가는 편이 좋을 것 같아서 추가로 적어둔다.
카메라의 시점 조절을 잘 하자. 카메라의 거리 조절이 안 되서 이상한 걸 건드리고 있다가 꽤 심각한 오류가 발생해서 한 번 프로젝트를 이전 버전으로 돌렸었다. (Virtual Camera를 지워도 오류가 안 없어지더라...)
Virtual Camera가 시점을 벗어나서 카메라의 위치가 벗어나는 버그가 발생해서 초마다 오류 알림이 두 개씩 뜨는 버그가 나타나서 생각보다 고생했다.
처음에 맵 세팅을 했을 때 자꾸 플레이어가 깜빡이는 오류가 있었는데, 배경과 플레이어의 거리가 같게 되니까 자꾸 깜빡이면서 배경 뒤로 사라졌다가 나타났다 하는 것임을 알게 되었다. 그래서 배경은 추가로 더 뒤로 가도록 Z축을 조정했다.
어제자 수정 내용으로 적었던 스펠 쿨타임의 경우 구현되어 있기는 하나, 임시 방편으로 플레이어 컨트롤러에 구현해 둔 상태이고 변경될 예정이다.
해당 쿨타임은 GameManager쪽에 Static으로 저장해 두고 쿨타임 표시 등으로 활용하는 것이 좋겠다는 판단이 들어 GameManager 구현이 시작되면 옮겨올 예정이다.
몬스터와 플레이어가 얼추 구성된 상태로 오늘의 작업을 마쳤고, 이제 서로가 공격을 주고받을 수 있는 상태까지 완성하면 게임으로서의 뭔가를 보여줄 수 있을 것이다.
현재 몬스터의 생성 방법을 Instatiate로 하고 있다. 여기에 오브젝트 풀 패턴을 사용하면 추가로 최적화의 효과를 볼 수 있을 것으로 기대된다.
게임매니저, 오디오 매니저 및 UI 매니저 등 이제는 게임성에 중요한 요소들을 개발할 때가 되었다.
이를 바탕으로 스테이지 또한 제작하여 완성된 게임을 만들고자 한다.