유니티

[유니티] #9 광부 타이쿤 게임 만들기 (창고 광부, 로딩바)

디버그러 2025. 1. 20. 22:27

 

 

창고 광부의 Idle, WalkingNoGold 애니메이션을 만들었다.

Idle은 고개와 오른발을 까딱까딱하도록 했다.

WalkingNoGold는 카트에 골드 없이 걷는 동작만 만들었다.

 

 

 

골드 없이 걷는 애니메이션을 복사하고 Animator로 가서 드래그한다.

이렇게 하면 똑같은 애니메이션을 복제하여 일부만 수정할 수 있다.

 

 

 

Gold 오브젝트를 ShopCart 안에 넣고 비활성화 상태로 둔 후

WalkingWithGold 애니메이션에 Is Active를 추가하고 체크해 두면 된다.

 

 

 

애니메이션 파라미터를 Bool 타입으로 WalkingNoGold, WalkingWithGold를 만든다.

MakeTransition을 통해 Idle과 Walking을 연결한다.

Exit Time 등은 0으로 하고 Fixed Duration을 해제한 후 파라미터도 각각 지정한다.

 

 

 

오류 방지를 위해 StringToHash를 통해 파라미터의 해시readonly로 선언한다.

MoveMiner 함수를 오버라이드 해서 베이스는 그대로 쓰고 애니메이션만 추가한다.

 

CollectGold 함수도 오버라이드 해서 CurrentGold가 0보다 작거나 같을 경우
방향과 상태를 전환하고 창고로 돌아오도록 한다.

 

코드를 확인하기 위해 Update 메서드에 P 키를 눌렀을 경우 방향을 전환하고 x값만 이동하도록 했다.

 

 

 

WalkingWithGold 파라미터도 readonly int를 통해 해쉬로 선언한다.

CollectGold 함수에서 NoGold 애니메이션을 끄고, WithGold 애니메이션이 나오도록 한다.

 

 

 

CollectGold함수에서 골드가 있을 때는 엘리베이터의 골드와 수집 시간을 코루틴에 전달한다.

코루틴에서 수집 시간만큼 기다리고 골드를 수집한 후 방향과 상태를 전환하여 창고 자리로 돌아온다.

 

이렇게 실행해 보면 버그가 발생한다.

엘리베이터 UI에 분명 골드가 있는 게 보이는데 창고 광부가 이 골드를 가져오지 못하는 것이다.

계속 0인 상태로 돌아오게 된다.

 

 

 

문제는 Warehouse에서 참조를 잘못 넣은 것이다.

Elevator의 오브젝트에 있는 Deposit을 넣어야 하는데 Warehouse에 있는 빈 Deposit을 넣었던 것이다.

 

Deposit 스크립트를 서로 다른 GameObject에 추가하면, 각 오브젝트는 독립적인 Deposit 인스턴스를 생성한다.

그 결과 CurrentGold 같은 변수는 각 인스턴스마다 개별적으로 존재하게 된다.

기본적으로 0으로 초기화가 되어있어 계속 수집하려 해도 0으로 참조됐던 것이다.

 

문제는 파악했으니 헷갈리게 만든 ElevatorDeposit 객체는 삭제한다.

 

 

 

애니메이션에도 약간의 문제가 있다.

수집하고 돌아갈 때 반드시 Idle을 거칠 필요는 없기에 NoGold와 WithGold 끼리도 화살표를 연결한다.

 

 

 

MoveMiner 함수가 호출될 때 무조건 NoGold 애니메이션이 호출되기에 Update 메서드와 합친다.

코루틴을 통해 수집하기도 전에 WithGold 애니메이션이 나오기 때문에 아래로 옮긴다.

이제 수집하기 위해 이동할 때는 NoGold 애니메이션이 나오고

수집을 다 하고 이동할 때는 WithGold 애니메이션이 나올 것이다.

 

 

 

DepositGold오버라이딩하여 재정의한다.

광부가 가지고 있는 CurrentGold가 0일 경우에는 바로 엘리베이터로 이동한다.

그렇지 않은 경우 walking 애니메이션을 끄고 코루틴을 호출한다.

 

코루틴에서 depositTime만큼 기다리고 GoldManager 인스턴스의 CurrentGold에 골드를 입금하고,

광부의 CurrentGold는 0으로 한 후 다시 엘리베이터로 이동한다.

 

 

 

새로운 WarehouseUI 스크립트를 만든다.

GoldManager의 CurrentGold를 띄우기 위해 텍스트 변수를 선언하고,

Update 메서드에서 계속 업데이트하도록 한다.

 

 

 

ElevatorMiner의 로딩바를 만들기 위해 LoadBar를 만들었다.

Canvas를 만들고 빈 오브젝트인 Container와 Bar이미지가 담긴 LoadBar를 만든다.

Image 타입을 Filled로 하고 Horizontal로 설정한 후 Amount를 조정해 보면 게이지바처럼 움직인다.

 

 

 

BarCanvas를 프리팹으로 만들고 삭제한다.

Bar가 어디에 떠야하는지 지정하기 위해 BarPosition을 만든다.

 

 

 

(여기서부터 Fira Code 폰트로 변경했다. 기본값은 FillImage가 바코드처럼 보인다.)

새로운 LoadBar 스크립트를 만든다.

프리팹과 위치 변수를 추가하고 CreateLoadBar 함수를 만든다.

Instantiate로 만든 로딩바를 변수에 저장하고, 자식 구조에서 Image 컴포넌트를 찾아서 _fillImage 변수에 저장한다.

 

 

 

현재 BarCanvas의 상태다.

BarCanvas 안에 Container가 들어있고 그 안에 LoadBar가 들어있다.

이렇게 2번 들어가야 하는 경우 transform.GetChild(0)을 2번 써야 한다.

 

 

 

BaseMiner 스크립트에 Action(델리게이트 축약형)을 선언한다.

 

 

 

if (OnLoading != null) OnLocation.Invoke를 줄여서 OnLoading?.Invoke로 쓸 수 있다.

엘리베이터 광부의 코루틴 전에 로딩바가 나타나야 자연스러울 것이다.

 

 

 

BaseMiner 클래스 변수를 선언한다.

GetComponent<BaseMiner>()는 BaseMiner를 상속받은 모든 자식 클래스를 포함하여,

해당 오브젝트에 부착된 컴포넌트를 가져온다.

 

만약 오브젝트에 ShaftMiner 컴포넌트가 붙어 있다면,

_miner는 ShaftMiner 객체를 참조하지만 BaseMiner 타입으로 작동한다.

 

한 마디로 부모 클래스 타입을 반환하지만, 실제로는 자식 클래스의 객체를 가져오는 것이다.

이것이 가능하도록 만든 것이 다형성이며, 객체지향 프로그래밍의 핵심 원리 중 하나이다.

 

 

 

LoadingBar 함수를 만들고 Action과 동일한 매개 변수를 받도록 한다.

여기서 로딩바를 활성화하고 fillAmount를 0으로 해서 처음부터 시작되도록 한다.

 

_miner == minerSender 인지 확인하여 이벤트를 호출한 대상에게 로딩바가 활성화 되도록 하는 것이다.

 

DoTween의 함수 DoFillAmount를 쓰면 로딩바를 쉽게 구현할 수 있다.

1f는 로딩바가 완전히 가득 찬 상태를 말하며, 애니메이션은 duration초 동안 진행된다.

애니메이션이 완료되면 OnComplete 콜백이 실행되어 로딩바가 비활성화 된다. (람다 함)

 

 

 

OnEnable은 이벤트 구독의 역할을 할 뿐, 직접적으로 이벤트를 발생시키지는 않는다.

OnLoading 이벤트를 발생시키면, 구독된 LoadingBar 함수가 호출되는 것이다.

참고로 LoadingBar 함수는 로딩바가 비활성화된 상태에서도 호출될 수 있다.

 

반대로 OnDisable은 이벤트 구독 해제를 한다.

 

 

 

샤프트 광부와 창고 광부에 빈 오브젝트로 BarPosition을 만들고 로딩바가 뜰 위치를 맞춰준다.

Miner 스크립트가 있는 오브젝트에 LoadBar 스크립트를 넣고 인스펙터에 참조할 객체를 넣어준다.

프리팹을 가져왔기 때문에 override를 눌러서 Apply All을 눌러줘야 프리팹에 적용된다.

 

 

 

샤프트 광부와 창고 광부 스크립트에서도 코루틴이 호출되기 전에

로딩바 이벤트를 호출하여 자연스럽게 이어지도록 한다.

 

 

 

한 가지 문제가 있다면 금을 수집하는 시간과 입금하는 시간에 모두 로딩바가 있는 창고 광부다.

창고 광부가 RotateMiner를 통해 localScale이 반대로 되는데 이 때 로딩바도 반대로 되는 것이다.

 

먼저 LoadBar 스크립트에서 BarContainer 변수에 캔버스의 Transform을 저장한다.

 

 

 

창고 광부는 LoadBar 스크립트를 가지고 있기에 GetComponent만 해주면 변수를 사용할 수 있다.

BarContainer의 localScale을 로딩바가 나오기 전에 전환해주면 끝이다.

 

 

 

강의 출처: #29 Load Bar (Unity Tutorial | Tycoon idle game)