내일배움캠프 Unity 50일차 TIL - 팀 오오오오오 - 개발일지

Wooooo·2024년 1월 8일
0

내일배움캠프Unity

목록 보기
52/94

[오늘의 키워드]

발표 때 사용할 개발 과정에서의 트러블 슈팅들을 정리해보려한다.
빌드 후에는 발생하지 않지만 Unity Editor에서는 발생하는 문제들로 괜히 밑바진 독에 물을 붓는 일이 없도록 정리해보려한다.

추가로, 프로젝트를 진행하면서 잘했다고 느낀 것과 보완해야겠다고 느낀 것도 정리해보려한다.


[Unity Editor에서 Shader Compile]

여러가지 에셋을 추가하는 과정에서 머티리얼과 셰이더가 추가됐는데, 테스트 중 런타임에서 셰이더를 컴파일링하고, 그동안은 메쉬 렌더링이 단색으로 깨지는 현상이 있었다.

처음에 이 문제를 맞닥들이자마자 든 생각은, 어떻게든 비동기로 셰이더 컴파일링을 먼저 완료한 후에 씬 초기화를 시작할 수 있는 구조로 만들어야겠다 였다.

하지만, 공식문서를 찾아보니, 에디터 상에서만 발생하는 문제였다. Unity Editor는 모든 셰이더를 다 컴파일하는 건 시간이 너무 오래 걸릴 수도 있으니, 필요한 셰이더만 컴파일하고, 만약 캐싱되지 않은 셰이더를 런타임에서 인스턴싱한다면 그때 그때 비동기로 컴파일 하는 방식이라는 듯하다.

한 번 컴파일을 하고나니깐 에디터 자체에 캐시파일이 남아서 계속 발생하진 않는 것 같기도..?

빌드 파일로 뽑아낼 때는 빌드 과정에서 모든 셰이더를 컴파일한다고 한다!


[Unity Editor에서 Cursor.Visible]

우리 프로젝트는 FPS게임이다. 따라서 플레이어를 조작 중일 때는 마우스 커서를 보이지 않게 설정한 뒤, 커서의 위치를 화면의 중앙으로 고정시켜야한다. 마우스를 확확 돌려도 화면 밖으로 빠져나가서 애플리케이션의 포커스를 잃어버리지 않게 하기 위함이다.
반면에 UI를 조작 중일 때는 마우스 커서를 보이게 해줘야한다.

InputManager.cs

    public void OnOpenUI()
    {
        SwitchActionMap("UI");
        _isUsingUI = true;
        RefreshCursor();
    }

    public void OnCloseUI()
    {
        SwitchActionMap("Player");
        _isUsingUI = false;
        RefreshCursor();
    }

    private void RefreshCursor()
    {
        if (!_isUsingUI)
            Cursor.visible = false;
        else
            Cursor.visible = true;
    }
	
    // 애플리케이션이 Focus를 얻거나 잃었을 경우 호출되는 라이프사이클 메서드
    private void OnApplicationFocus(bool focus)
    {
        if (focus)
            RefreshCursor();
    }

    private void Update()
    {
        if (!_isUsingUI)
            Mouse.current.WarpCursorPosition(new(Screen.width / 2, Screen.height / 2));
    }

ESC 버튼을 눌렀을 때 모든 UI가 닫히도록 설정했는데, 문제는 여기서 발생했다.
다른 방법으로 UI가 닫혔을 때는 커서가 정상적으로 보이지 않게 됐지만, ESC를 눌러서 UI를 닫았을 때는 커서가 사라지지 않았다.

구글링을 해보니 이 문제도 유니티 에디터에서 ESC 버튼을 누르면 커서가 보이도록 설정돼 있었기 때문이다. 이 문제도 빌드를 하고 나면 발생하지 않는 문제였다.


[잘한 것, 못한 것]

[FSM 기반 클래스/인터페이스 작성]

public interface IState
{
    void OnStateEnter();
    void OnStateStay();
    void OnStateExit();
}

public interface IStateMachine<T> where T : IState
{
    void StateTransition(T nextState);
}
using UnityEngine;

public class StateMachine<T> : MonoBehaviour, IStateMachine<T> where T : IState
{
    protected T _currentState;

    public virtual void StateTransition(T nextState)
    {
        _currentState?.OnStateExit();
        _currentState = nextState;
        _currentState?.OnStateEnter();
    }

    protected virtual void Update()
    {
        _currentState?.OnStateStay();
    }
}

플레이어 캐릭터에 FSM을 적용하기 위해 FSM의 기반 클래스를 작성했다.
플레이어 캐릭터의 상태머신을 구현하는 클래스를 다음과 같이 선언했다.
public class PlayerStateMachine : StateMachine<PlayerStateBase>

여기까진 깔끔하게 잘 작성한 것 같은데, 문제는 플레이어의 상태를 얼마나 세세하게 나눠야할까였다.
앉은 상태선 상태 클래스를 작성했지만, 정조준 상태재장전 상태는 플레이어의 상태가 아니라 총기의 상태라 생각하고 작성하지 않다가 결국 나중에 가서는 if문의 지옥과 예외처리의 지옥을 맛봤다.

다음엔 상태를 더 세세하게 나눠야겠다...

profile
game developer

0개의 댓글