개요
UNNAMED의 마지막 개발일지 입니다.
게임 소개글을 적기 전에 설명 못한 구조들 간단하게 설명하겠습니다.
시작하기전에..
프로젝트의 이름이 정해졌습니다.
거창한건 없고 예전엔 이름이 없었기 때문에 '이름 미정' 이라고 제목에 적혀있었죠?
프로젝트 이름을 제출 5시간 정도 전까지 정하지 못해서 그냥 UNNAMED(이름 없음) 으로 정했습니다.
스테이지
아이디어 정리
저번 글에서 스테이지 식의 타임어택 게임을 만든다고 했었죠?
근데 대충 구성을 해보고 플레이 해보니 긴박감이 없더라구요.
그래서 스테이지마다 제한시간을 두고 그 안에 클리어 못하면 그냥 재시도 하도록 바꿨습니다.
일단 각자 스테이지의 분량이 길다기 보단 각각 깨는데 10초 내외로 아주 짧기 때문에 당연하게도 씬으로 나누기보단 프리팹으로 나누는게 효율이 좋습니다.
타이머가 스테이지에 돌입하자마자 시작할 경우 불합리 할 수도 있으니 버튼을 눌러 문을 열고 시작하는 것으로 하는게 낫겠죠? 대충 아이디어는 정리 됐으니 만들겠습니다.
음... '만들겠다' 라는 미래시제는 지금 제 글에 별로 맞진 않네요.
아무튼 만들었습니다.
구현
일단 각 스테이지들은
1. 제한시간
2. 적과의 전투를 상정한 적의 List
3. 시작 위치
정도가 필요합니다.
적이 필요한 이유는 만약 스테이지에 적을 배치했는데 적을 잡지 않고 클리어 하는 상황을 막기 위해섭니다.
만약 enemyList.Count가 0보다 크다면 적을 모두 잡지 않았다는 뜻이니 그냥 스테이지를 안넘겨주면 되죠.
적는건 간단합니다.
public class Stage : MonoBehaviour
{
public List<Enemy> enemyList = new List<Enemy>();
public Transform startPosTrm;
public float clearTime;
private void OnValidate()
{
enemyList = GetComponentsInChildren<Enemy>().ToList();
}
}
적은 하나하나 넣어주기 귀찮아서 그냥 OnValidate에서 알아서 넣어주도록 해주었습니다.
이제 이 Stage를 프리팹에 달아주면 되죠.
그리고 이 Stage들을 넘기기 위해 StageManager를 만들어줍니다.
정말 간단하게 모든 스테이지와 현재 스테이지 정도만 있으면 됩니다.
[SerializeField]
private List<Stage> _stageList;
private Stage _currentStage;
public Stage CurrentStage => _currentStage;
private int _currentStageIndex = 0;
다음 스테이지로 넘어갈땐 _currentStage를 지우고 다음 스테이지를 만든 다음 그 스테이지의 시작 위치로 플레이어를 이동시켜주면 됩니다.
public void NextStage()
{
Destroy(_currentStage.gameObject);
_currentStageIndex++;
if(_currentStageIndex >= _stageList.Count)
{
PlayerPrefs.SetInt("RetryCount", _retryCount);
SceneManager.LoadScene("EndScene");
return;
}
_currentStage = Instantiate(_stageList[_currentStageIndex], transform);
PlayerManager.Instance.Player.MovementCompo.Teleport(_currentStage.startPosTrm.position);
GameManager.Instance.SetTimer(_currentStage.clearTime);
}
쉽죠?
이러면 스테이지 구조 끝입니다.
튜토리얼
아이디어 정리
튜토리얼 구조는 State패턴을 사용해서 만들었습니다.
FSM을 배워두니 State패턴 관련해서 응용할 곳이 많더라구요. C++ 프로젝트에도 사용했습니다.
명확한 단점이 있긴해요. 클래스 수가 말도 안되게 많아지거든요.
아무튼 튜토리얼도 쉬운편이죠.
일단 각각의 튜토리얼들은 '점프를 하세요.' 나 '총을 쏘세요.' 같은 간단한 지시사항을 하나씩 들고 있습니다.
그리고 지시사항을 통과할 때 다음 튜토리얼로 넘어가야합니다.
이러면 이제 전에 만들었던 StateMachine처럼 모든 튜토리얼의 객체와 현재 튜토리얼을 들고 있는 TutorialManager를 만들어 주고 각자 튜토리얼이 들고 있는 Update를 실행시켜주면 그만입니다.
구현
일단 기본적으로 TutorialStep부터 적어보죠.
public abstract class TutorialStep : MonoBehaviour
{
public virtual void Enter() { }
public virtual void UpdateStep() { }
public virtual void Exit() { }
}
FSM이랑 똑같이 생겼죠?
같은 디자인 패턴을 사용해서 똑같을 수밖에 없어요.
그리고 TutorialManager는 방금 전 적었던 StageManager처럼 적어주면 됩니다.
[SerializeField]
private List<TutorialStep> _tutorialStepList;
private TutorialStep _currentStep;
private int _currentStepIndex = 0;
private void Update()
{
_currentStep.UpdateStep();
}
public void NextTutorial()
{
_currentStep.Exit();
_currentStepIndex++;
_currentStep = _tutorialStepList[_currentStepIndex];
_currentStep.Enter();
}
음 쉽다.
아, 왜 각각의 Step이 일반 클래스가 아니라 MonoBehaviour나면 인게임에서 충돌 감지를 해야할 경우 때문입니다.
인스펙터에서 직접 만지면서 하는게 편하잖아요, 그죠?
이제 각각의 TutorialStep들에서 다음 튜토리얼을 나가기 위해 TutorialManager를 가져와야할 필요성이 생기니 싱글톤으로 만들었습니다.
이러면 끝입니다.
마치는 말
놀랍게도 코딩도 별로 안한 프로젝트가 우수작입니다.
이유를 들어보니 우수작을 뽑아봤는데 대부분의 우수작이 한 반에 몰려 나오는 바람에 몇명 더 뽑을 수 밖에 없었다고 합니다.
물론 그래도 별로 납득은 안가지만 좋은게 좋은거죠.
무려 지금까지 우수작을 한번도 놓친적 없는 사나이! 좋은 울림아닙니까?
아무튼 그러니 지금 영상을 부리나케 만들고 있습니다. 프로젝트가 너무 구려서 어떻게든 영상을 정신 없게 만들기 위해 노력중이에요. 그래도 게임 프로그래밍 산출물은 잘나와서 나름대로의 명성은 지켰습니다.
'개발 > UNNAMED' 카테고리의 다른 글
UNNAMED | 네번째 프로젝트 # Final : 완성 (1) | 2024.07.09 |
---|---|
UNNAMED | 네번째 프로젝트 # 6 : 버튼과 기획 변경 (1) | 2024.06.10 |
UNNAMED | 네번째 프로젝트 # 5 : 적 FSM (0) | 2024.06.08 |
UNNAMED | 네번째 프로젝트 # 4 : 총 (0) | 2024.06.02 |
UNNAMED | 네번째 프로젝트 # 3 : Player FSM (0) | 2024.06.01 |