1. 사실 게임은 2개월 전에 만들었다.
10월 17일 경에 완성했는데…
게임을 만드는 과정을 따로 정리하지 않아 리마인드 겸 정리하는 내용이다.
사용한 에셋은 Kenny의 무료 에셋이다. Kenny 짱~
2. 제작 순서
2-1. 일단 게임의 분석부터 진행했다.
이 게임을 Unity로 구현하려면 어떤 내용이 들어가야할까?를 가볍게 정리한 문서라고 생각하면 된다.
이 내용을 작성하면서, 이 게임에는 어떤 기능이 들어갔을 지(혹은, 들어가야 이런 기능을 구현할 수 있을지) 고민하며 작성해보았다.
파일은 이쪽
이렇게 박박 쓰고, 처음에는 가장 기본적인 배치를 진행했다.
배경을 깔고, 캐릭터를 놓고…….
그리고 크롬 다이노의 핵심은 결국 계속해서 달려나가는 캐릭터와, 무한이 이어지는 맵이기 때문에, 일단 캐릭터의 애니메이션부터 집어넣었다.
왜?
: 달리기 게임은 사실상 플레이어 캐릭터만 움직이면 되는 게임이니까....
맵은 동일맵 반복이고, 바닥은 계속해서 이어지기만 하면 되니까..
그렇게
차곡차곡
애니메이션이 추가되었다.
달리고 맞고 숙인다! 사실 이것만해도 달리기 게임의 절반은 왔다고 생각했다.
바닥을 인지하기 전까지는…
Q. 무슨 일이 있었나?
: 단순히 범위를 잡아 달리게 만들었더니, 바닥이 더 빨리 생성되며 앞으로 나아가버려 플레이어가 역으로 뒤로 밀려 떨어지는(...) 현상이 발생했다.
타일을 20개 정도로 유지하면서 계속 이어지게 했는데, 그 '20개'는 유지되면서 캐릭터가 쫓아가진 못한 것이다.
사유: 매프레임마다 생성-제거됨. 그러다보니 플레이어가 이동하는 속도보다 타일 생성 속도가 더 빨랐던 것. (이래서 프레임 단위는!)
처음엔 온갖 방법을 다 써봤다. Collider 감지 했을 때만 앞에 생기도록. (난 이거 될 줄 알았어..)
캐릭터 기준으로 TIlemap 위치를 계산해서 그 범위 안에만 계산되도록. (...1,1,1 기준이 아니라 타일맵 사이즈가 바뀌어 있어서 1칸 갔을 때 1.56칸 간 걸로 인지되어 더 빨리 생성됐다. 월드맵->타일맵 셀 사이즈 환산에 실패!)
그래서 tilemap.WorldToCell(player.position).x; 를 이용해서 해결했다. (어차피 x축으로만 타일맵은 늘어나기 때문에...)
public class TilemapExtender : MonoBehaviour
{
[SerializeField] private Tilemap tilemap;
[SerializeField] private TileBase groundTile;
[SerializeField] private Transform player;
[SerializeField] private int extendBuffer = 10;
[SerializeField] private int removeBuffer = 20;
[SerializeField] private int groundY = -5;
private int prevPlayerTileX = int.MinValue;
private int prevStartX = int.MinValue;
private int prevEndX = int.MinValue;
private void Update()
{
// 플레이어의 월드 좌표를 타일맵 셀 좌표로 변환
int playerTileX = tilemap.WorldToCell(player.position).x;
if (playerTileX == prevPlayerTileX)
return;
int startX = playerTileX - removeBuffer;
int endX = playerTileX + extendBuffer;
// Debug.Log($"플레이어 월드X: {player.position.x}, 셀X: {playerTileX}, startX: {startX}, endX: {endX}");
// 1. 현재 프레임에서 유지해야 할 구간의 타일은 모두 생성
for (int x = startX; x < endX; x++)
{
tilemap.SetTile(new Vector3Int(x, groundY, 0), groundTile);
}
// 2. 이전 프레임에서 유지했던 구간 중, 이번 프레임에 벗어난 타일은 모두 제거
if (prevStartX != int.MinValue && prevEndX != int.MinValue)
{
for (int x = prevStartX; x < startX; x++)
tilemap.SetTile(new Vector3Int(x, groundY, 0), null);
for (int x = endX; x < prevEndX; x++)
tilemap.SetTile(new Vector3Int(x, groundY, 0), null);
}
prevPlayerTileX = playerTileX;
prevStartX = startX;
prevEndX = endX;
}
}
그렇게 만들어진 무한 증식 배경+바닥
이후 UI를 붙이고, '게임오버' 로직도 미리 만들어두어 테스트했다.
Trigger Game Over로 디버그 툴을 만들어 1차 테스트. (기능이 잘 작동하는지 확인하기 위함)
디버그 툴 장점: 별도의 조건을 만들기 전(예: 에너미에게 3회 부딪히기), 버튼 하나로 언제든지 테스트 해볼 수 있다.
무엇을 테스트했나: 게임오버가 되면 다시 시작 버튼과 함께, 캐릭터가 '기본'자세로 완전 정지 상태로 있어야함
이후의 작업
1. 일단 적을 만들고…
(적에 크게 들어갈 로직은 없다. 제일 복잡한 게 소환 로직인 수준. 콜라이더끼리 서로 부딪히면 체력만 까주면 되고, 애니메이션 좀 넣어주면 되기 때문이다.)
적은 컴퓨터에 너무 부담을 주지 않도록 하기 위해, 오브젝트 풀링을 사용했다. 파괴하지 않고 껐다가 켜길 반복하면서, 1개~3개가 한 번의 소환에 랜덤하게 적용되도록.
2. 점수도 적용하고…
: 복잡한 내용을 저장할 필요가 없기 때문에, 간단하게 PlayerPrefs로 저장했다. HighScore가 나오면 뒤집어 씌워진다.
3. 소리도 넣었다.
조금씩 잔잔히 하다보니 시간이 오래 걸린 것 같다.
캐주얼 게임이라 단순하면서도, 버그를 피하기 위한 세세한 점검을 진행해야 했다.
3. 아쉬운 점
1. 밸런싱 미숙: 모든 장애물들 중에서 유일하게 '벌' 만이 플레이어 방향으로 '이동'하는데, 이 '이동'과정에서 무당벌레와 동선이 겹치면 피할 수 없어지는 사태가 발생한다. 아예 벌을 멈추고, y 좌표만 바꾸는 형식으로 진행하는 것도 괜찮을 것 같다.
2. 맵의 일관성: 맵을 여러 색상으로 바꾸는 등의 요소는 넣지 않았다. 물론 이는 충분히 구현하고자 하면 가능한 일이다.
'작업_자습' 카테고리의 다른 글
| [내일배움캠프 휴일차] 어떻게든 쿼터뷰를 만들겠다는 몸부림 (0) | 2025.05.07 |
|---|---|
| [자습] 행맨 번외 (0) | 2025.03.28 |
