ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 내일배움캠프 47일차 TIL - 유니티 심화 주차 팀 프로젝트 4
    TIL/Unity 2024. 6. 24. 20:59

     

    [한 줄 요약]

    심화 주차 팀 프로젝트를 진행하면서 스테이지 패배, 재화 획득 기능 등을 구현했다.


    [학습 내용]

     

    심화 주차 팀 프로젝트


    버그 수정 및 기타 기능 구현

    승리 문구 출력

    화면 상단에 스테이지 클리어 시 Victory, 스테이지 패배 시 Defeat 문구가 출력되도록 구현하였다. 기존의 텍스트 UI가 Canvas 밖에 나와서 출력되지 않던 버그를 수정하였다.

    Victory 출력

     

    상단 체력바 동작

    상단의 체력바가 몬스터의 체력에 따라 동작하도록 연결해주었다.

    체력바

     

    추후에 소수점에 대한 처리를 해주어야 할 거 같다.

     

    플레이어 애니메이션 미출력 버그

    몬스터가 새롭게 생성됨에 따라서 플레이어가 타겟 몬스터를 찾지 못해 애니메이션이 출력되지 않는 버그가 있었다. 이를 해결하기 위해서 몬스터 스크립트 안에 몬스터가 생성되었을 때 플레이어 타겟에 자신을 등록하도록 수정해주었다.

    private void Start()
    {
        ...
        GameManager.Instance.Player.stateMachine.Target = gameObject;
    }

     

     

    스테이지 패배

    플레이어 사망 추가

    스테이지 패배 상황을 구현하기 위해서 우선 플레이어 사망 처리를 해야 했다. 우선 상태머신에 DieState를 만들고, 관련 애니메이션도 제작해주었다. 그리고 이후에 스테이지 시스템에 스테이지 패배 이벤트를 만들고, 플레이어 사망 시 스테이지 패배 이벤트를 동작하도록 구현하였다.

    플레이어 사망


    !! 문제 발생 !!

     

    * 내용

    애니메이션 이벤트를 사용하여, 플레이어 사망 애니메이션이 출력된 후에 사망 처리 관련 기능을 실행해주고 싶었다. 그런데 이벤트에 메서드 이름을 등록하여도 메서드가 실행되지 않았다.

     

    * 탐색

    구글에 검색해보니 같은 오브젝트 안의 스크립트 컴포넌트 안에 메서드가 존재해야 한다는 걸 알게 되었다. 그런데 애니메이터를 자식 오브젝트에 따로 넣어놨기 때문에 이에 대한 처리가 곤란하였다.

     

    * 해결

    그래서 결국 새로운 스크립트를 하나 만들고 이벤트 핸들러라고 이름을 지었다. 그리고 애니메이터와 같은 위치에 컴포넌트로 붙여주었다.

    public class PlayerDieAnimationEventHandler: MonoBehaviour
    {
        public void PlayerDie()
        {
            enabled = false;
            GameManager.Instance.StageSystem.PlayerDieEvent.Invoke();
            Destroy(GetComponentInParent<Player>().gameObject);
        }
    }

     

    플레이어가 사라졌을 시 몬스터 동작 버그 수정

    기존의 코드는 플레이어가 사라지지 않을 때를 가정하여 작성되었기 때문에 플레이어가 사라지자 Null 관련 오류가 다수 발생하였다. 이를 if문으로 미리 검사하여 오류가 나지 않도록 수정해주었다.

    protected bool InAttackRange()
    {
        if (stateMachine.Target != null && GameManager.Instance.Player != null)
        {
            if (stateMachine.Enemy.transform.position.x - stateMachine.Target.transform.position.x <= 1)
                return true;
        }
        return false;
    }

     

    플레이어 재생성

    플레이어를 프리펩화하고 스테이지 시작마다 생성하도록 구현하였다.

    플레이어 프리펩

     


    !! 문제 발생 !!

     

    * 내용

    Destroy(gameObject)를 하였으나 플레이어 프리펩이 사라지지 않고 보이지 않은 상태로 계속 공격을 하는 현상이 발생하였다.

     

    * 탐색

    처음에는 플레이어 프리펩이 사라졌다가 새로 생성되는 프리펩에 문제가 생긴 줄 알았다. 그런데 해결되지 않았고 일일이 코드 한 줄씩 지워본 결과 기존 프리펩이 사라지지 않고 스프라이트가 달려있는 자식 오브젝트만 사라진다는 것을 알았다.

     

    * 해결

    Destroy(gameObject)가 작동하는 스크립트가 자식오브젝트에 붙어있어서 그런 것이었다. 그래서 부모 오브젝트가 Destroy 되도록 부모 오브젝트를 가리키는 코드가 필요했다. 구글에 검색해본 결과 transform.parent를 사용하거나 GetComponentInParents를 사용하면 된다는 것을 알게 되었다.

    public class PlayerDieAnimationEventHandler: MonoBehaviour
    {
        public void PlayerDie()
        {
            ...
            Destroy(GetComponentInParent<Player>().gameObject);
        }
    }

     

    재화 획득

    골드 프리펩 추가

    우선 골드 프리펩을 만들어주었다. 생성되자마자 폴짝하는 애니메이션을 재생하도록 만들고, 이후 Destroy 되도록 해주었다.


    !! 문제 발생 !!

     

    * 내용

    애니메이션으로 폴짝 뛰는 애니메이션을 만들기 위해 transform의 rotation을 변경해주었는데, 이것이 절대좌표로 작동하여 이상한 곳에서 애니메이션이 출력되었다.

    Position.y를 변경해주자 월드 상의 (0, 0.1, 0) 좌표로 이동하였다.

     

    * 탐색

    이 문제를 그대로 구글에 검색해보았는데, 상대좌표로 만들기 위해서는 어느 오브젝트 안에 넣어주면 된다는 글이 있었다. 처음에는 골드 생성 위치를 담은 오브젝트를 부모로 둘까 고민하였으나, 몬스터 위치에 따라 실시간으로 변해야 하기 때문에 바람직하지 않아보였다.

     

    * 해결

    그러다 문득 자식오브젝트에 스프라이트와 애니메이터를 넣고 상위 오브젝트는 오브젝트의 위치와 스크립트를 담아놓으면 된다는 걸 떠올렸다. 간단한 구조인데 이게 생각나지 않았다는 게 아쉬웠다.

    애니메이터를 자식오브젝트로 넣어주었다.


     

    애니메이션 이벤트

    골드도 플레이어와 마찬가지로 골드가 사라지는 애니메이션 출력 이후에 기능이 동작하도록 애니메이션 이벤트를 사용하였다. 이것도 애니메이터와 같은 위치에 스크립트를 생성하여 애니메이션 이벤트가 호출할 수 있도록 설계하였다.

     

    보석 추가

    처음에 골드를 만드는 것만 생각해서 보석이 드랍되는 걸 구현하기 위해서 다시 코드를 짜야했다. 먼저 골드 드랍 이벤트의 이름을 변경하여 일반 몬스터 드랍 이벤트로 만들었다. 그리고 보스 드랍 이벤트를 또 만들었다. 이렇게 해서 일반 몬스터 드랍 이벤트에는 골드 획득 메서드를, 보스 드랍 이벤트에는 골드 획득 메서드와 보석 획득 메서드를 추가했다.

     

    코드 재활용

    우선 보석을 구현하기 위해서 골드에서 재활용할 수 있는 것들을 생각해보았다. 먼저, 애니메이션을 재활용했다. 스프라이트는 달라도 애니메이션 정보에는 위치와 색상값 정보만 들어있었기 때문에 재활용할 수 있었다.

    그리고 애니메이션을 재생하는 스크립트도 재활용할 수 있었다. 그래서 DropItem으로 이름을 변경하고 재활용하였다.

     


    [결과물]

    인게임 화면


    [회고]

    일단 최소한의 게임루프 구현은 완성하였다. 그런데 상점이나 강화 등의 구현이 덜 구현되어 내일 빠르게 진행해야 한다. 또한 여러가지 버그들이 남아있기 때문에 내일은 다른 팀원들이 기능 구현을 할 동안 나는 버그 수정을 진행하게 될 거 같다.

    늦어도 내일 오후에는 발표준비에 들어가야 할 거 같다.