부트캠프/본캠프

[내일배움캠프_2025SEP01] Cooking Knight 1일차

Young_A 2025. 9. 1. 21:19

목차

    Cooking Knight 1일차

    지난주에 기획분들과 교류하며 작성한 기획서를 토대로 게임을 만드는 것이 이번주 팀 프로젝트다.

    게임 이름은 Cooking Knight.

    비록 프로그래머는 2명 뿐이지만 최선을 다해보기로 했다.

     

    주말에 잠깐씩 나와서 프로젝트 구조정도만 만졌다.

    계획했던 스타트매니저는 씬로드매니저를 구현하면서 폐기했다.

    현재 프로젝트 규모로는 필요성이 많이 없기 때문에, 씬 로드 매니저가 존재한다면 효용가치가 별로 없는 것 같았다.

     

    오늘은 플레이어 액션을 구현할 것 같다.

    완성할 수 있다면 좋겠지만 안된더라도 기획분들이 만져보면서 조작감을 테스트 및 조정할 수 있도록 하고 싶다.


    AsyncOperation

    유니티에서 백그라운드에서 진행되는 비동기 작업을 나타내는 객체이다.

    게임의 메인 스레드를 멈추지 않고, 시간이 오래 걸리는 작업(씬 로딩)의 진행 상황을 추적할 때 사용한다.


    간단히 생각하자면 로딩 중인 씬이나 불러오는 에셋의 진행 상황을 담고 있는 바구니와 같다.

     

    주요 속성

    • idDone: 작업이 완전히 끝났는지를 알려주는 Boolean 값.
    • progress: 작업의 진행률을 알려주는 float (0.0~1.0)값. 씬 로딩의 경우 0.9까지 진행되다가 씬 활성화 후 1.0이 된다.
    • allowSceneActivation: 씬 로딩에만 있는 속성으로 0.9가 되었을 때 이 값을 true로 바꾸어주어야 씬이 완전히 활성화됨.

    주요 사용 사례

    • 씬 로딩: SceneManager.LoadSceneAsync()
    • 에셋 로딩: AssetBundle.LoadAssetAsync()

    이를 통해 로딩 화면을 만들거나, 게임을 멈추지 않고 큰 파일을 로드하여 사용자 경험이 원활하도록 할 수 있다.

     

    나 같은 경우는 SceneLoadManager를 구현하면서, Loading UI를 보여주기 위해 사용하려고 한다. (예정)

    //실제 다음 씬 비동기 로드
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(_currentScene.GetSceneName());
    asyncOperation.allowSceneActivation = false;    //로딩 완료 후에도 활성화 false
    
    while (asyncOperation.progress < 0.9f)
    {
        //todo. 로딩 진행률 표시할 때 여기에서.
        yield return null;
    }
    
    asyncOperation.allowSceneActivation = true;
    yield return new WaitForEndOfFrame();   //렌더링 끝날때까지 대기
    _currentScene.OnLoad(); //씬 초기화 진행

     

    WaitForEndOfFrame()

    모든 카메라와 GUI 렌더링이 완료될때까지 기다리는 특수 코루틴 명령어다.

    프레임의 마지막 단계인 모든 렌더링이 끝난 후에 실행된다.

     

    이번 프레임의 모든 그리기 작업이 끝날 때까지 기다려줘, 라고 말하는 것과 같다.

    씬 전환할 때 발생할 수 있는 깜빡임을 예방하기 위해서 쓴다고 하는데, 굳이...? 싶긴함.


    2D 플랫포머 게임 플레이어 지면체크

    [Header("Ground check")]
    [SerializeField] private Transform groundCheck;
    [SerializeField] private LayerMask groundLayer;
    [SerializeField] private float groundCheckRadius = 0.1f;
    
    public bool IsGrounded()
    {
        return Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
    }

    우리 게임의 플레이어는 이중점프가 되지 않는다.

    그래서 점프를 시작한 뒤 지면에 닿았을 때 다시 점프가 가능한지 확인을 해야한다.

    처음에는 콜라이더로 충돌판정을 하려고 했으나, 점프 시작할때 IsGrounded 판정이 true가 나오는 바람에 생각한대로 구현할 수 없었다.

     

    인터넷을 찾아 나온대로 구현했다.

     

    Physics2D.OverlapCircle()은 유니티 2D 물리 시스템에서 제공하는 함수로, 특정 위치에 원 모양의 충돌 감지 영역을 만들고, 그 영역 안에 groundLayer에 속한 콜라이더가 있는지 확인하여 bool값을 반환한다.

    //땅에 붙어있거나, 아래로 하강할때만.
    if (player.IsGrounded() && player.MovementController.Rigidbody2D.velocity.y <= 0f)
    {
        player.TransitionToActionState(PlayerState.Action.Idle);
    }

    더해서, 점프를 시작하여 캐릭터 y값이 상승할 때가 아니라, 하강할 경우라는 조건을 추가하여 '착지'일 경우를 한 번 더 확인하여 Action 상태를 Idle로 되돌릴 수 있도록 하였다.


    중력 조절 방법

    Rigidbody2D 내 Gravity Scale 조절

    캐릭터 점프를 하는데 내려오는 시간이 너무 느리다고 하셔서 중력을 조절했다.

    당연하지만 중력을 무겁게 설정하면 하강하는 속도는 빨라지지만, 같은 Jump force로 점프하는 높이가 줄어든다.

    간단하게 Jump Force를 증가시켜 원하는 높이로 점프할 수 있도록 진행하였다.

     

    이토록 Rigidbody2D에서 Gravity Scale을 조절하게 되면 특정 객체만 보다 특별한 중력을 받거나, 아이템 효과 같은 것을 스크립트로 구현하기 좋다.

    프로젝트 세팅에서 변경

    그 외에도 일괄적으로 프로젝트 전체에 걸리는 중력을 조절할 수도 있다.

    Edit -> Project Settings -> Physics 2D를 선택하여 Gravity를 조절할 수 있다.

    Y축 중력 -9.81이 기본 셋팅이다.

    수를 더 작게 조절하면 중력이 강해지고, 양수를 입력하면 위로 중력이 가해진다. 


    애니메이션 레이어 (Animation Layers)

    원래는 3D 애니메이션에서 서로 다른 신체 부위의 복잡한 상태 머신을 관리하기 위해 Animation Layers를 사용한다.

    예를 들어서 하체 레이어는 뛰거나 걷는 것을 관맇가ㅗ, 상체 레이어는 오브젝트를 던지거나 사격하는 것을 관리할 수 있따.

    나 같은 경우는 Attack이 다른 애니메이션들보다 우선적으로 출력되어야하므로 생성했는데!

    만들고나니 굳이 필요했나...? 싶다! 그치만 이미 잘 돌아가는 거 냅두고 다른거 하다가 나중에 리팩토링 하러 돌아오려고 한다.

    (PlayerMovementState이랑 PlayerActionState 구분한 것들 포함해서 리팩토링 해야함^^;)

     

    • Override: 새 레이어의 애니메이션을 사용하여 아래 레이어의 애니메이션을 대체한다.
    • Additive: 아래 레이어의 애니메이션 위에 새 레이어의 애니메이션을 추가한다.

    느낀점

    오늘 그래도 꽤 많은 걸 해냈다!

    • 플레이어의 상태 패턴을 구현했고(병렬로 만들어서 다시 하나로 합치는 리팩토링을 하긴 해야하지만)
    • 플레이어를 모듈화하여 AttackController, MovementController, ConditionController를 구현했고
    • 플레이어의 Movement(Idle, Walk, Jump, Attack)를 구현했고
    • 애니메이션들도 붙였다!
    • 또한 StateScene에 모아놔서 기획 분들도 원하시면 조작감을 테스트해볼 수 있다! (비록 장애물도 뭣도 없지만)

    내일 학습 할 것은 무엇인지

    앞으로 할 것은 적 골조를 짜서 일단 플레이어의 기능들이 완벽하게 구현되었는지 확인하고 (피격, 공격 테스트용)

    죽음까지 진행해서 플레이어를 완성하는 것이 목표다.

     

    몬스터 스폰 매니저를 생성하고, 몬스터의 상태패턴과, 이동 영역을 설정해서 몬스터가 정해진 곳에서만 이동할 수 있도록 해야한다.

    또한 몬스터의 경우 도망 패턴이 있기 때문에 이걸 유의해서 만들어야겠다.