Falling Foods 개발일지4

SMN·2025년 4월 20일

Falling Foods

목록 보기
5/8
post-thumbnail

1. 체력 UI

2. GameManager (게임오버)

3. MapManager (무한 맵)

게임을 하면서 자신의 체력을 볼수 있게끔 이번엔 체력 UI를 만들어 볼 것이다.

우선 생각 중인 것은 Screen상에서 UI를 띄워도 되지만 나는 WorldSpace에서 UI를 띄워 볼 것이다.

먼저 Canvas를 캐릭터 안에서 만들고 렌더링 모드를 WorldSpace로 설정해주었다.

이후 이미지를 하나 만들어 캐릭터 밑에 두고 이미지 채움을 통해 시계처럼 점점 체력이 떨어지는 것처럼 연출할 것이다.

PlayerHealth 스크립트.

먼저 healthBar라는 이미지를 선언한 뒤, HealthUpdat안에서 이미지의 채움을 구하였다.

살짝 어려운 난관이 있었는데 처음에는 아래 코드를

healthBar.fillAmount = Health / maxHealth; 		// 0이 출력됨

라고 작성하였더니 계속해서 0이 나오길래 어떻게 해야하는지 몰랐다.
찾아본 결과 int의 나눗셈 에서는 작은수 / 큰수이기에 0이 나오는게 맞지만 float로 변환시 소수점까지 나오는걸 다시 깨달은 것 같다.

healthBar.fillAmount = (float)Health / maxHealth; 		// 비율이 출력됨

그러면 이렇게 계속해서 Hp바가 감소하고 음식을 먹게되면 조금씩 차는 것을 볼 수 있다.

이렇게 이미지로 표현해도 좋지만 정확한 체력값도 보여주고 싶기에 Text도 추가할 것이다.

이렇게 HealthBar의 자식오브젝트로 HealthText를 넣었다.

이후 알맞게 배치하였다. 근데 UI쪽은 완전히 이해하지 못해서 비효율적으로 만든 것 같기도하다..

PlayerHealth 스크립트.

healthText로 Text를 가져오고 HealthUpdate에 변경값을 계속 넣어준다.

그러면 이렇게 이미지와 텍스트가 health를 계속해서 플레이어에게 알려주는 것을 볼 수 있다.

이번에는 게임 오버 시스템을 만들어 보도록 하겠다.

GameManager 같은 경우에는 Hp가 0이 되면 GameManager의 state(bool)을 false로 바꿔서 동작을 멈추게끔 하도록 하겠다.

GameManager 스크립트

먼저 싱글톤을 작성하고, 게임의 상황을 알려주는 중요한 변수인 state를 프로퍼티를 이용하여 외부 클래스에서 값을 읽을 순 있지만 쓰지는 못하도록 하였다.
GameStart함수와 GameOver함수를 만들었고 각각 state의 값을 조절한다.

PlayerHealth 스크립트

Update함수 내에서 health의 값이 0과 같거나 작아지면 GameManager의 GameOver를 호출한다.
이렇게 되면 state가 false가 되고 이에 따른 다른 스크립트의 동작멈춤을 구현하면 된다.

if (GameManager.Instance.State == false) return;

스크립트의 동작을 멈추는 한줄짜리 코드이다.

이 코드를 게임이 종료되었을 때 동작을 멈춰야 하는 코드에 넣으면 된다.

while(GameManager.Instance.State)

(코루틴 내 while문 조건문의 경우)

현재는 PlayerInput , FoodSpawner , PlayerHealth 이렇게 총 3개의 코드를 수정하였다.


이후 플레이 하기전에 GameManager의 state를 따로 true로 만들지 않았기 때문에 임시적으로
GameManager의 Start함수에 state를 true로 하는 코드를 작성하도록 하겠다.

이후 GameManager를 Hierarchy창에 생성시키고 실행해보면...

실행도 잘 작동하고, hp가 0이 되었을 때 이동불가, 음식 생성X, 체력감소X 가 되는 것을 볼 수 있다.

지금 약간 밋밋해 보이는 건 UI를 따로 만들지 않았기 때문이다...

다음날이 되고 다시 게임 플레이를 해보니 이번에는 체력이 달지 않는 것 오류가 있는 것을 볼 수 있었다.

뭔가 이상하다..

나는 GameManager의 state가 문제가 되는 것 같다고 판단하여
GameManager와 PlayerHealth스크립트를 병행해가며 살펴보았다.

확인해본 결과 PlayerHealth의 DecreaseHealth함수가 GameManager의 GameStart함수가 실행되기 전

실행되는 것을 알게되었다. 두개의 함수 모두 Start에서 실행되기 때문에, 랜덤으로 실행순서가 정해지는 것이였다. 이런!

이 문제를 해결하기 위해 gameStartAction 이벤트 함수를 만들거나, 상속을 이용했지만 아직을 어떻게 해결해야 할지 몰라서 '급한 불부터 끄자' 라는 심정으로 GameManager에서 GameStart함수를 호출하는 함수의 위치를 Start에서 OnEnable로 바꿔주었다...

(유니티 lifecycle을 보면 OnEnable이 Start함수보다 빠른 것을 알 수 있다..)

이제야 잘 Hp가 깎이는 것을 볼수 있다.

이번엔 맵을 무한정 돌아다닐수 있게 만들어 볼 것이다.

현재 맵은 일시적인 공간만 있을 뿐 한쪽으로 쭉 가게 되면 맵이 생성되지 않은 곳을 볼수 있다.

이 문제를 해결하기 위해 플레이어의 위치에 따른 맵 생성및 파괴를 만들어 볼 것 이다.

대략적으로 이렇게 플레이어를 가운데 기준하에 8방향으로 맵이 존재하게 하고, 떨어진 맵들을 삭제할 것이다.

나는 이 문제를 이차원 배열을 사용해 풀어보기로 하였다.

MapManager 스크립트

먼저 maps라는 maps 라는 참조할 공간을 만들고,
mapArray라는 맵의 위치를 정할 이차원 배열을 만들었다.
그리고 9개의 맵을 배치해주고 (맵끼리의 거리 : 180)
좌측 상단의 맵부터 maps에 넣어주었다.

Map Prefab에 콜라이더를 넣어 플레이어의 위치를 확인하려 했지만 맵의 중앙이 이상해서

Center라는 이름으로 맵의 중앙을 만들어준 후 콜라이더를 맵을 다 가릴정도의 크기로 생성 시킨뒤, tag를 Map이라고 지정해 주었다.

내가 이제 스크립트로 만들어 볼 것은, MapManager에서 맵에 번호를 부여하고, 맵은 캐릭터와 닿았을 때 MapManager에 번호를 매개변수로 함수를 호출시켜 맵의 삭제와 생성을 실행하게 만들 것이다.

Map 스크립트

이 스크립트는 Center오브젝트에 부착시키고, 캐릭터와 접촉했다면 MapManager의 함수를 호출시킨다.

MapManager 스크립트

먼저 Map에서 접근하기 수월하게끔 싱글톤패턴을 사용했고, Start함수에서 maps에 있는 GameObject들을 mapsArray에 정렬시켰다. 정렬을 시키며 Map의 number에 값을 넣어 주었다.

(밑에 GetComponent로 적으면 center의 Map에 접근하지 못하니 GetComponentInChildren 으로 수정..)

살짝 후회가 드는건 뭔가 싱글톤으로 안만들어도 괜찮을 것 같았다.? 그정도이다.

진행중인 MapUpdate함수이다.

아직 정리는 하지않았고, 우선적으로 결과를 이끌어내기 위해 작성중이다.
number 를 switch문으로 받았고, 맵을 이동시켜준다. 이후, tempMaps에 임시적으로 이동시킬 맵을 넣어주고, 아래 for문에서는 maps의 배열을 3칸씩 뒤로 이동 시켜주었다.

(첫번째 이중for문)

(두번째 이중for문)

두번째 이중 for문 뒤의 코드를 작성하였다.

tempMaps에 있는 맵을 maps에 넣어주었고,
maps에 있는 모든 맵의 number값을 새로 할당해주었다.

이렇게 작성을 해주게 되면 캐릭터의 위치에 따른 맵의 변화 그리고, 맵의 변화에 따른 맵의 number값이 계속해서 변하는 것을 볼수 있다.

(maps배열 주목)

만들고 나니까 든 생각은 이차원 배열은 사용하지 않았다는 점과 이중for문 대신 그냥 for(int i = 0; i < 3; i++) 이런식으로 계속 사용했으면 고민하는 시간이 적었을 거 같았던 점이다.

그래서 사용하지 않은 mapsArray이중배열 관련코드를 모두 삭제시키고,
MapUpdate함수도 최적화를 시켜주었다.

코드를 깔끔하게 정리.

이 코드는 캐릭터가 좌측으로 이동했을때의 코드이다.

캐릭터가 우측으로 이동했을때,

캐릭터가 하단으로 이동했을 때,

이렇게 모두 작성을 하고나면 코드는 더럽지만 실행을 된다.

이 코드를 확인해보려고 계속 실행을 해보았다.

오류

Maps배열을 보게 되면 두번쨰 이동부터 순서가 이상해지는 것을 볼수있다.

때문에 화면에서도 Map이 이상하게 보인다.

이 오류의 이유는 tempMaps의 임시 오브젝트를 Clear 하지 않았기에, 계속해서 처음 받은 임시 오브젝트만 덮어써지는 것이다.

그래서 tempMaps를 Maps에 덮어쓰는 작업 이후에 tempMaps를 Clear 시켜주어야 정상적으로 작동하게된다.

모든 방향의 코드에 tempMaps.Clear()를 시켜준다.

이렇게 MapManager의 스크립트가 완성되었다.

MapUpdate함수를 조금더 최적화 시켜서 코드의 양을 줄일수 있겠지만 힘들기때문에 일단 패스..

MapManager 관련 코드 요약

완성본

계속해서 맵이 무한으로 이어지는 것을 볼수 있다.

개발기간 250415,250416,250420
profile
모든 생각까지

0개의 댓글