타워 디펜스 게임
일식일식 ·
개요
개발 목표
AI Agent로 만들기.
더미 테스트 진행.
AI로 바이브 코딩을 했을 때 아키텍처를 설명하고 구조를 설명하면 완벽한 디버깅과 성능 최적화가 가능한지에 대해 테스트.
유니티 엔진과의 연동이 원활한지 테스트
AI로 에셋 제작 및 적용 과정 경험
기획
- 운빨존망겜 스타일의 타워 디펜스 게임
- 조선시대 라는 시대적 배경을 가미해서 포인트
- 2D 픽셀 아트 디자인
- 성 위에 캐릭터들을 두고 나오는 몬스터를 왜군과 청나라군으로 설정
- 여러가지 맵 설정 : 행주산성 등등의 조선시대 성을 배경으로 함
- 여기에 추가적으로 거북선으로 하는 수전 등등의 특이 맵 추가 가능
- 조선시대 장수들을 신화 캐릭터로 두는 방식으로 운영 가능
개발 과정
260509
유니티 설치 및 세팅(제미나이)
Step 1. 유니티 허브(Unity Hub) 및 에디터 준비
(이미 유니티가 설치되어 있다면 이 단계는 건너뛰셔도 됩니다.)
Unity Hub 다운로드: 유니티 공식 홈페이지에서 'Unity Hub'를 다운로드하고 설치합니다.
로그인 및 라이선스: Unity Hub를 실행하고 로그인한 뒤, Personal(무료) 라이선스를 발급받습니다.
에디터 설치: 좌측 Installs(설치) 탭에서 Install Editor(에디터 설치)를 누르고, 가장 최신 LTS (Long Term Support) 버전을 설치합니다. (예: 2022.3.x LTS)
Step 2. 새로운 2D 프로젝트 생성
Unity Hub 좌측 탭에서 Projects(프로젝트)를 클릭합니다.
우측 상단의 파란색 New project(새 프로젝트) 버튼을 누릅니다.
화면 중앙의 템플릿 목록 중 2D Core를 선택합니다. (우리는 2D 픽셀 아트 게임을 만들 거니까요!)
우측 설정 창에서 정보를 입력합니다:
Project name: JoseonDefense (또는 원하시는 이름)
Location: 프로젝트가 저장될 폴더 경로 지정
Create project(프로젝트 생성) 버튼을 누릅니다.
(유니티가 이것저것 세팅하느라 몇 분 정도 걸릴 수 있습니다. 커피 한잔하고 오세요!)
Step 3. 유니티와 Antigravity 연결하기 (매우 중요 ⭐️)
프로젝트가 열리면, 이제 유니티가 코드를 열 때 기본적으로 Antigravity를 사용하도록 설정해야 합니다.
유니티 에디터 상단 메뉴에서 Edit > Preferences... 를 클릭합니다. (Mac의 경우 Unity > Settings...)
왼쪽 메뉴 탭에서 External Tools를 선택합니다.
가장 위에 있는 External Script Editor의 드롭다운 메뉴를 클릭하고 Browse...를 선택합니다.
컴퓨터에 설치된 Antigravity 실행 파일을 찾아서 선택해 줍니다.
Windows: 주로 C:\Users\사용자이름\AppData\Local\Programs\Antigravity\Antigravity.exe
Mac: Applications(응용 프로그램) 폴더 내의 Antigravity.app
(선택) 같은 화면 바로 아래 Generate .csproj files for: 항목에 있는 체크박스(Local packages 등)를 모두 체크한 뒤, Regenerate project files 버튼을 한 번 눌러줍니다. (자동 완성 기능이 더 잘 작동하게 해줍니다.)
Step 4. 첫 스크립트 만들고 Antigravity 열기
이제 연동이 잘 되었는지 테스트해 볼 차례입니다.
유니티 에디터 하단의 Project 창에서 Assets 폴더 빈 공간을 우클릭합니다.
Create > Folder를 클릭하고 폴더 이름을 Scripts로 변경합니다.
만들어진 Scripts 폴더를 더블클릭해서 들어갑니다.
다시 빈 공간을 우클릭 후 Create > C# Script를 클릭합니다.
스크립트 이름이 파랗게 선택된 상태에서 GameManager라고 타이핑하고 엔터(Enter)를 칩니다.
방금 만든 GameManager 스크립트를 더블클릭합니다.
🎉 짜잔! 이때 Antigravity가 자동으로 실행되면서 GameManager.cs 코드가 열리면 성공입니다.
전달할 초기 세팅 프롬프트
1단계: 마스터 프롬프트 (프로젝트 초기화 및 뼈대 잡기)
가장 먼저 빈 유니티 프로젝트(2D)를 열고 Antigravity에 아래 내용을 입력하세요.
Plaintext
너는 지금부터 10년 차 유니티(Unity) 클라이언트 및 C# 백엔드 개발자야. 나와 함께 'JoseonDefense'라는 이름의 2D 픽셀 아트 타워 디펜스 게임을 바닥부터 개발할 거야.
[게임 기획 요약]
- 장르: 랜덤 머지(Merge) 타워 디펜스 (ex. 운빨존망겜, 랜덤다이스 스타일)
- 배경: 조선시대 (왜군, 청나라군 디펜스)
- 코어 맵: 행주산성 (기본), 거북선 수전 (특수 맵)
- 캐릭터: 일반 병졸부터 신화급(이순신, 권율 등 조선시대 장수) 캐릭터까지 랜덤 소환 및 합성
- 서버: Stateless 구조의 C# 서버 (게임 종료 시 결과, 웨이브 도달 기록, 재화만 검증 및 DB 저장)
[아키텍처 및 코딩 규칙 - 엄격하게 지킬 것]
1. 데이터 관리: 캐릭터 스탯, 몬스터 정보, 웨이브 데이터는 반드시 `ScriptableObject`를 사용하여 기획자가 수정하기 쉽게 구성할 것.
2. 최적화: 수많은 몬스터와 발사체가 등장하므로, 반드시 `ObjectPooling` 시스템을 기본 모듈로 먼저 작성할 것.
3. 패턴: 싱글톤(Singleton)은 GameManager, SoundManager 등에만 최소한으로 사용하고, 컴포넌트 간 결합도를 낮출 것.
4. 백엔드 통신: `HttpClient` 또는 유니티의 `UnityWebRequest`를 활용하되, 비동기(`async/await` 또는 `UniTask`)로 처리할 것.
작업 지시:
위의 기획과 규칙을 숙지했다면, 가장 먼저 프로젝트의 폴더 구조(Scripts, Prefabs, ScriptableObjects 등)를 어떻게 잡을지 제안해 주고, 게임의 뼈대가 되는 `GameManager.cs`와 범용적으로 쓸 수 있는 `ObjectPoolManager.cs`의 기본 코드를 작성해 줘.
2단계: 코어 로직 구현 (그리드 및 랜덤 소환 시스템)
1단계 코드가 잘 적용된 것을 확인한 후 아래 프롬프트를 입력하세요.
Plaintext
이제 성벽 위에서 캐릭터들이 배치될 그리드(Grid) 시스템과 랜덤 소환 시스템을 만들 거야.
1. GridManager: 3x5 사이즈의 성벽 위 타일(Tile)을 2D 환경에 동적으로 생성하는 코드를 작성해 줘. 각 타일은 유닛이 배치될 수 있는지(IsOccupied) 상태를 가져야 해.
2. UnitSpawner: 플레이어가 재화(ex. 엽전)를 소모하여 빈 타일 중 한 곳에 랜덤한 등급(현재는 임시로 1티어 병졸)의 유닛을 소환하는 로직을 작성해 줘.
3. 데이터 구조: UnitData라는 이름의 `ScriptableObject`를 만들어서 유닛의 이름, 프리팹, 기본 공격력, 공격 속도, 티어(일반/희귀/영웅/신화)를 정의할 수 있게 해줘.
작성된 C# 코드들을 제공해 주고, 하이라키(Hierarchy) 창에 어떻게 배치해야 하는지 설명해 줘.
3단계: 머지(합성) 시스템 구현 (운빨 디펜스의 핵심)
캐릭터가 소환되는 것을 확인한 후 입력하세요.
Plaintext
'운빨존망겜' 스타일의 핵심인 합성(Merge) 로직을 만들 차례야.
1. 마우스 드래그 앤 드롭: 플레이어가 그리드 위에 있는 유닛을 클릭해서 드래그한 뒤, 다른 유닛 위에 놓을 수 있는 로직(`IDragHandler`, `IBeginDragHandler`, `IEndDragHandler` 사용)을 추가해 줘.
2. 합성 로직: 드래그해서 놓은 두 유닛이 '동일한 종류'이고 '동일한 티어'일 경우, 두 유닛을 삭제하고 해당 위치에 한 단계 높은 티어의 유닛을 랜덤하게 소환하는 코드를 작성해 줘.
3. 만약 조건이 맞지 않거나 빈 타일이 아닌 곳에 드래그를 놓으면, 원래 있던 타일 위치로 자연스럽게 돌아가게 해줘.
4단계: 적(왜군) 이동 및 타워 전투 시스템
합성 로직 완료 후 입력하세요.
Plaintext
이제 적군과 전투 로직을 만들 거야.
1. Waypoint System: 적들이 화면 우측에서 스폰되어 성벽(좌측)을 향해 꼬불꼬불한 길을 따라 이동하도록 Waypoint 기반의 이동 스크립트를 작성해 줘.
2. EnemySpawner: 1초마다 왜군 프리팹을 `ObjectPoolManager`를 이용해 스폰하고 웨이포인트를 따라가게 해줘.
3. UnitCombat: 성벽에 배치된 우리 유닛들이 사거리(Range) 내에 들어온 가장 가까운 적을 찾아 설정된 공격 속도에 맞춰 발사체(화살, 총알 등)를 발사하는 코드를 작성해 줘. 발사체 역시 오브젝트 풀링을 사용해야 해.
5단계: Stateless 서버 구축 및 연동
클라이언트 로직이 어느 정도 완성된 후, 백엔드 개발을 위해 입력하세요.
Plaintext
게임이 끝났을 때 결과를 저장할 Stateless 백엔드 서버를 만들 거야.
기술 스택: C# ASP.NET Core Web API (혹은 간단한 Node.js/Express, 네가 가장 빠르고 가볍게 짤 수 있는 걸로 추천해서 짜줘).
1. 서버 로직: 클라이언트로부터 `userId`, `clearedWave`, `gainedGold` 정보를 JSON으로 받는 POST API 엔드포인트(`/api/game/result`)를 만들어 줘.
2. 검증 로직(간단히): 도달한 웨이브 수에 비해 획득한 골드가 비정상적으로 많지 않은지 체크하는 아주 간단한 서버 사이드 검증 로직을 포함해 줘.
3. 유니티 클라이언트: 게임 오버 시 결과창이 뜨면서 방금 만든 API로 결과를 전송하는 `NetworkManager.cs` 코드를 작성해 줘. 성공 시 "기록 저장 완료", 실패 시 재시도 로직을 포함해 줘.
💡 Antigravity 활용 꿀팁:
오류 발생 시: 에러 로그를 복사해서 "이 에러가 발생했어, 원인이 뭘까?" 라고 묻기만 하면 에이전트가 컨텍스트를 파악해 코드를 수정해 줍니다.
기획 변경 시: "신화급 캐릭터 중 '이순신'은 공격할 때 화살 대신 거북선을 소환해서 범위 피해(Splash)를 주게 코드를 수정해 줘"와 같이 구체적으로 지시하면 UnitCombat 스크립트를 스스로 상속받거나 인터페이스를 추가하여 변형해 줍니다.
개발 과정에서의 생각
- 유니티 툴을 아예 모르다 싶이 하니까 정말 감이 잘 안온다.
- prefab : prefabricated(조립식의)의 줄임말. 규격화된 블록들을 표현. 어떤 특정 틀의 기계가 있고 거기서 찍어내는 것과 비슷하다. hierarchy에 배치하면 생성이 되고 프리팹의 어떤 데이터를 바꾸면 한번에 변경 된다.
-ScriptableObject(SO) : prefab이 몸체라면 SO는 스펙, 설명서이다. 캐릭터의 공격력, 방어력 등 숫자로 된 데이터들이다.
근데 이렇게 유니티에서 내가 뭘 조작해야되나 ? 싶어서 프롬프트로 유니티 엔진을 안 건드리고 싶다고 했다. 그랬더니
지금 유니티 에디터에서 마우스로 일일이 프리팹을 만들고, 컴포넌트를 붙이고, SO(ScriptableObject)를 빈칸에 드래그 앤 드롭으로 연결하는 과정이 너무 비효율적이야.
나는 앞으로 마우스 조작을 최소화하고 100% 코드로만 통제하고 싶어. 구조를 아래와 같이 변경해 줘.
1. UnitFactory 패턴 도입:
미리 프리팹을 만들어두는 게 아니라, `UnitSpawner`가 유닛을 소환할 때 코드로 직접 `new GameObject()`를 생성하고, 여기에 `SpriteRenderer`, `BoxCollider2D`, `Unit.cs`를 `AddComponent`로 부착하는 동적 생성(Dynamic Generation) 방식으로 코드를 전부 다시 짜줘.
2. Resources 로드:
유닛 데이터(SO)나 기본 이미지 리소스는 유니티 인스펙터에서 연결하지 않을 거야. `Resources.Load<UnitData>("Characters/Tier1")` 방식으로 코드가 직접 폴더를 뒤져서 데이터를 가져와서 유닛에 주입(Inject)하도록 변경해 줘.
3. 목표:
이 구조를 적용해서, 내가 유니티 에디터 화면에서는 아무것도 클릭하거나 드래그할 필요 없이 오직 '코드 저장 후 플레이(▶)'만 눌러도 게임이 똑같이 작동하게 만들어 줘. 필요한 전체 수정 코드를 줘.
이런 스크립트를 받아서 적용해봤다.
이미지 생성도 이미지를 니가 직접 생성해서 그 자리에 넣어줘. 라고 프롬프트를 전달하면 잘 만들어준다. 다만 이미지 생성 한도가 또 따로 있다
에셋 이미지 생성기 제작
에셋 이미지를 어떻게 생성할까 하다가 [제미나이로 이미지 생성 -> 힉스필드로 애니메이션 생성 -> 그걸 프레임별로 뽑아서 넣기]의 작업을 거치기로 했다. 그를 위해서 애니메이션 영상을 받으면 그걸 프레임별로 이미지를 뽑아주고 배경도 날려주는 프로그램이 필요했다. 물론 유니티에서 쓰는 폼으로 뽑기도 하고 말이다. 이에 대한 기획은 매니페스트로 해보려고 한다. 매니페스트로 기획 -> 기능 명세서를 이용한 앱 구현 이 과정을 거쳐서 만들어보려고 한다.
유니티에서 스프라이트 시트 사용하기
🛠️ 유니티에서 스프라이트 시트 사용하는 4단계
1단계: 에셋 설정 바꾸기 (가장 중요)
이미지를 유니티 프로젝트 창(Project Window)에 넣은 후, 그 이미지를 클릭하고 우측 인스펙터(Inspector) 창을 보세요.
Texture Type: Sprite (2D and UI)로 변경합니다.
Sprite Mode: 기존 Single에서 Multiple로 꼭 변경해 주셔야 합니다. (여러 장이 뭉쳐있다는 뜻)
설정 후 맨 아래 Apply 버튼을 누릅니다.
2단계: 이미지 쪼개기 (Sprite Editor)
인스펙터 창 중간에 있는 Sprite Editor 버튼을 누릅니다. (창이 새로 뜹니다.)
💡 만약 Sprite Editor 버튼이 안 보이거나 에러가 나나요?
상단 메뉴 Window -> Package Manager로 가서 2D Sprite 패키지가 설치되어 있는지 확인하고 설치해 주세요!
에디터 창 상단의 Slice 메뉴를 누릅니다.
Type을 정해줍니다.
Automatic: 유니티가 투명도(Alpha)를 인식해서 자동으로 쪼개줍니다. (프레임 크기가 제각각일 때 사용)
Grid By Cell Size / Count: 프레임이 정확히 일정한 크기(예: 64x64, 128x128)로 등분되어 있다면, 가로세로 픽셀 크기나 칸수를 입력해 정확히 자를 수 있습니다. (추천)
Slice 버튼을 누르면 이미지에 초록색 네모 선이 생기며 쪼개집니다.
마음에 들게 잘렸다면 우측 상단의 Apply를 누르고 창을 닫습니다.
3단계: 쪼개진 이미지 확인
이제 프로젝트 창으로 돌아와서 해당 이미지 파일 옆에 있는 작은 화살표(▶)를 누르면, 한 장이었던 파일 아래로 쪼개진 개별 프레임 이미지들이 주르륵 펼쳐지는 것을 볼 수 있습니다.
4단계: 드래그 앤 드롭으로 애니메이션 만들기
이게 제일 신기한 부분입니다.
쪼개진 프레임 이미지들을 Shift 키나 Ctrl 키를 누른 채 전부 선택(블록 지정)합니다.
그대로 하이hierarchy(하이라키) 창이나 씬(Scene) 뷰로 드래그 앤 드롭합니다.
유니티가 자동으로 *"애니메이션 파일(.anim)을 어디에 저장할까요?"*라고 창을 띄웁니다.
원하는 이름(예: Player_Walk.anim)으로 저장하면 끝입니다!
결과물은 어떻게 되나요?
이 과정을 마치면 씬에 자동으로 Sprite Renderer와 Animator 컴포넌트가 붙은 게임 오브젝트가 생성되고, 재생(Play) 버튼을 누르면 추출했던 영상처럼 애니메이션이 예쁘게 재생됩니다.
프레임이 너무 많아서 속도가 빠르거나 느리다면 상단 메뉴 Window -> Animation -> Animation 창을 열어서 Samples(초당 프레임 수) 값을 조절하시면 됩니다. 막히는 부분 있으면 언제든 말씀하세요!