[UNITY]중간점검 보고서
목차
- 프로젝트 개요
개발 시스템 구성
2.1 플레이어 시스템
2.2 스탯 시스템
2.3 레벨업 및 경험치
2.4 퀘스트 시스템
2.5 인벤토리 및 아이템
2.6 상점 시스템
2.7 강화 시스템
2.8 버프 시스템
2.9 포탈 및 씬 전환
2.10 몬스터 자동 리젠
2.11 세이브 및 로드 시스템
2.12 크리티컬 시스템
코드 리뷰
3.1 구조 설계
3.2 기능 구현
3.3 개선 사항
- 결론 및 향후 개발 계획
1. 프로젝트 개요
이 프로젝트는 Unity를 기반으로 제작된 로그라이크 스타일의 2D 게임으로, 전투, 강화, 퀘스트, 인벤토리, 스탯, 포탈 이동, 세이브 및 로드 등의 시스템을 통합하여 제작되었다.
플레이어는 키보드를 이용해 다양한 스킬과 상호작용을 통해 성장하고, 적을 처치하며 게임을 진행한다.
2. 개발 시스템 구성
2.1 플레이어 시스템
- 이동, 점프, 대시, 공격 및 스킬 사용이 가능하다.
- 애니메이션 기반의 콤보 공격과 스킬 공격은 애니메이션 이벤트와 히트박스를 통해 구현된다.
Player.cs에서 대부분의 로직이 통합되어 있으며, 스킬 사용 시 잔상 이펙트, 카메라 흔들림, 초상화 연출도 구현되어 있다.
https://github.com/user-attachments/assets/29f3bd72-ff18-4a0d-81e3-c20ffc937d1a
https://github.com/user-attachments/assets/e4621f35-e4d0-4b4c-a281-b2b1bdfddfc9
2.2 스탯 시스템
PlayerStat.cs를 통해 HP, MP, 힘, 덱스, 치명타 등의 스탯을 관리한다.- 장비나 레벨업을 통해 스탯이 증가하며,
StatUI.cs에서 UI로 표시된다.S키를 통해 스탯 패널을 토글할 수 있다.
STAT UI창
2.3 레벨업 및 경험치
- 적을 처치하면 경험치를 획득하며, 일정량 이상 모이면 자동으로 레벨업한다.
- 경험치 공식은 성장 계수 기반이며,
PlayerLevel.cs에 구현되어 있다. - 레벨업 시 스탯 보너스가 자동으로 적용된다.
레벨업시 추가 스텟 지정
2.4 퀘스트 시스템
- NPC와 상호작용하면 퀘스트 수락 및 진행이 가능하다.
- 퀘스트는
QuestData라는 ScriptableObject 기반으로 관리되며,QuestManager에서 상태를 추적한다. - 조건을 만족하면 자동으로 완료 처리되고, 골드와 경험치를 보상으로 받을 수 있다.
2.5 인벤토리 및 아이템
- 아이템은 ScriptableObject 기반의
ItemData로 정의되어 있으며, 포션, 장비, 퀘스트 아이템 등으로 나뉜다. - 인벤토리는 슬롯 기반 UI로 구성되어 있으며, 상점에서 구매 시 자동으로 인벤토리에 추가된다.
INVENTORY 구현
물약 획득 전
인벤토리 UI 세팅부분
획득 후
2.6 상점 시스템
- NPC 대화 중 상점을 열 수 있으며, 상점 창과 인벤토리가 동시에 열리는 구조다.
- 골드가 부족하면 구매가 불가능하고, 성공 시 인벤토리에 아이템이 추가된다.
- UI는
ShopManager및ShopItemSlot으로 구성되어 있으며, 각 슬롯은 동적으로 생성된다.
대화창
상점 열렸을떄의 동적할당 사진
선택지
2.7 강화 시스템
- 각 장비 부위를 강화할 수 있으며, 강화 확률과 비용이 존재한다.
- 강화 성공 시 스탯에 반영되고, 실패 시 골드만 차감된다.
- 강화 UI는
UpgradePanelToggle과UpgradeUI로 구현되어 있다.
강화성공시 스텟 변화
2.8 버프 시스템
F1~F5키를 통해 공격력, 이동속도 등의 버프를 부여할 수 있다.- 현재는 하나의 버프만 활성화 가능하며, 새로운 버프를 사용하면 기존 버프는 해제된다.
- 버프 아이콘과 타이머는 UI 상단에 표시된다.
https://github.com/user-attachments/assets/e7b809d4-44eb-4121-87ef-d4d206221b61
https://github.com/user-attachments/assets/43ba4717-0b0c-47da-8881-9fa37b897540
2.9 포탈 및 씬 전환
- 포탈에 접촉 시 해당 포탈의 ID에 따라 씬이 전환된다.
- 포탈 이동 시
PlayerPrefs를 이용해 스폰 지점을 저장하며, 다음 씬에서 자동 복원된다. PortalManager.cs와PortalTrigger.cs로 구현되어 있
이동 전
시작시 스폰위치 지정
이동 후
스포너의 위치
2.10 자동 리젠 시스템
- 게임의 몬스터는 특정
SpawnPoint위치를 기준으로 자동으로 생성되며, 일정 시간 간격 **으로 부족한 수량만큼 보충되는 방식으로 리젠된다. - 이 시스템은 리소스 낭비 없이 지속적인 몬스터 배치 유지를 목적으로 설계되었으며, 일정 범위 내 랜덤 위치에 적을 생성할 수 있도록 구현되었다.
https://github.com/user-attachments/assets/b602a1ae-4c81-4a71-b8fd-954ea6786c41
자동리젠 동영상
젠 이후
2.11 세이브 및 로드 시스템
ESC메뉴를 통해 게임 상태 저장 및 불러오기가 가능하다.- 저장 항목: 씬 이름, 플레이어 위치, 레벨, 경험치 등
- 향후 인벤토리, 퀘스트 상태 저장도 확장 가능
https://github.com/user-attachments/assets/f3e9c9c5-706d-4e9a-ab57-e216a0cf01f2
2.12 크리티컬 시스템 (데미지*1.8)
PlayerStat.critical: 치명타 확률 (%)PlayerStat.GetCriticalMultiplier(): 크리티컬 발생 시 데미지 배율
https://github.com/user-attachments/assets/15c8082f-0333-4b5f-95ba-476102fd34a9
코드 리뷰 (세부 분석 및 확장 가능성 포함)
1. Player.cs (플레이어 행동 통합 스크립트)
주요 특징
Update()에 이동, 점프, 대시, 스킬, 애니메이션이 모두 들어 있음- 스킬은
Q,W로 분기되어 있으며 각각 별도 쿨타임, MP 체크를 진행 CameraShake,AfterImage,Animator Trigger를 통합적으로 사용하여 연출 강화
특이점
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (Input.GetKeyDown(KeyCode.Q)) {
bool enoughMana = StatMana.instance.currentMP >= specialSkillCost;
bool cooldownReady = Time.time >= lastSkillTime + SkillCooldown;
if (enoughMana && cooldownReady) {
StatMana.instance.UseMana(specialSkillCost);
anim.SetTrigger(specialTriggerName);
lastSkillTime = Time.time;
StartCoroutine(StartSkillAfterImages());
rb.AddForce(Vector2.up * 20f, ForceMode2D.Impulse);
}
}
- 애니메이션과 물리 반응, 마나 시스템을 자연스럽게 엮어 연출이 좋음
- 스킬 구조가 상수 기반이므로, 향후 스킬 데이터를
ScriptableObject로 분리하면SkillData.cs기반의 스킬 시스템 확장 가능
확장성 제안
1
2
3
4
5
6
7
8
9
10
[CreateAssetMenu(menuName = "Skill/SkillData")]
public class SkillData : ScriptableObject {
public string skillName;
public int manaCost;
public float cooldown;
public float forceY;
public AnimationClip anim;
}
- 스킬 선택 및 업그레이드가 가능한 시스템으로 전환 가능
PlayerSkillManager에서 키 매핑이나 슬롯 시스템 도입도 가능
2. BuffManager.cs
주요 특징
- 하나의 버프만 유지 가능
- 새 버프 사용 시 기존 버프 제거 후 새로운 버프 적용
특이점
1
2
3
4
5
6
if (currentBuffRoutine != null)
StopCoroutine(currentBuffRoutine);
if (currentUI != null)
Destroy(currentUI);
- 단일 버프만 처리 가능하며,
Coroutine과UI모두 하나씩만 유지 - UI는
buffUIPrefab인스턴스를 동적으로 생성
개선 및 확장 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Dictionary<BuffType, Coroutine> activeBuffs = new();
Dictionary<BuffType, GameObject> activeUIs = new();
public void ApplyBuff(BuffType type, float duration, float value) {
if (activeBuffs.ContainsKey(type)) {
StopCoroutine(activeBuffs[type]);
Destroy(activeUIs[type]);
}
Coroutine routine = StartCoroutine(BuffRoutine(type, duration, value));
GameObject ui = Instantiate(buffUIPrefab, buffUIParent);
activeBuffs[type] = routine;
activeUIs[type] = ui;
}
BuffType별로 동시 유지 가능 → 다중 버프 처리 가능- 이 구조는 나중에 디버프나 상태이상도 함께 처리할 수 있음
3. Hitbox.cs / Enemy.cs / DamageTextSpawner.cs
주요 특징
- 전투는
Hitbox → IDamageable → Enemy.cs흐름으로 연결됨 - 데미지 처리, 회피, 방어, 크리티컬 처리 포함
특이점
1
2
3
4
5
6
7
bool isEvaded = playerAccuracy < evade;
if (isEvaded) {
DamageTextSpawner.I.SpawnText("Miss", transform.position + Vector3.up * 1.2f);
return;
}
- 회피를 단순 비교로 처리함 → 이후
랜덤화나공식 기반 확률로 확장 가능 - 데미지, 치명타, 방어력이 잘 분리되어 있음
확장 가능성
DamageInfo구조체 도입
1
2
3
4
5
6
7
8
public struct DamageInfo {
public int amount;
public bool isCrit;
public bool isMiss;
public Vector2 knockback;
}
- 이후 다양한 공격 유형(화염, 빙결, 중독 등) 확장 시 유용
4. QuestManager.cs + Quest.cs + QuestUIUpdater.cs
특징
- 퀘스트는
QuestData(SO) → Quest(instance)로 매핑 - 퀘스트는 진행형과 완료형 2가지 상태만 처리
- 모든 퀘스트 진행은 문자열 기반
targetName비교
특이점
1
2
3
4
5
6
if (target == data.targetName) {
currentAmount++;
if (currentAmount >= data.requiredAmount) Complete();
}
target문자열 기반이라 타이포에 취약target을 GameObject의 이름으로만 사용함 → ID 기반 비교가 더 안전
확장 제안
1
2
3
4
5
6
7
[System.Serializable]
public class QuestTarget {
public string id;
public int requiredAmount;
}
List<QuestTarget>을 활용해 다중 목표 퀘스트 구성 가능- 퀘스트 타입이 단일 enum 기반이라 확장시
interface IQuestCondition패턴 도입 가능
5. UpgradePanelToggle.cs + UpgradeUI.cs
주요 특징
U키로 강화 UI 토글- 부위별 아이템을 선택 → 강화 버튼 클릭 → 강화 확률 계산 → 성공/실패 처리
특이점
1
2
3
4
5
6
7
float successRate = currentItem.GetSuccessRate();
float roll = Random.value;
if (roll < successRate) {
currentItem.level++;
}
- 강화 확률을 직접적으로
Random.value로 처리 - 강화 수치나 확률이
ItemData에 전부 포함되어 있음
개선 제안
UpgradeRuleData같은 규칙 데이터 분리- UI 강화 결과에 따른 효과음, 연출 추가
6. GameSaveManager.cs
주요 특징
PlayerPrefs를 활용한 저장- 현재 씬, 위치, 레벨, 경험치 저장
특이점
1
2
3
4
PlayerPrefs.SetFloat("PlayerX", player.position.x);
PlayerPrefs.SetInt("PlayerLevel", PlayerLevel.instance.currentLevel);
- 매우 빠르게 구현 가능한 구조지만, 저장 항목 추가 시 확장성이 떨어짐
확장 가능성
1
2
3
4
5
6
7
8
9
10
11
[System.Serializable]
public class SaveData {
public string scene;
public Vector3 playerPos;
public int level;
public float exp;
public List<string> completedQuests;
public List<ItemSaveData> inventory;
}
- JSON으로 직렬화해서
Application.persistentDataPath에 저장하면 유연하게 확장 가능
7. ShopManager.cs
특징
- 상점은 동적으로 슬롯을 생성 (
Instantiate) - 골드 확인 후 구매 → 인벤토리 추가
특이점
1
2
3
4
5
6
7
8
9
foreach (Transform child in itemSlotParent)
Destroy(child.gameObject);
foreach (var item in shopItems) {
GameObject slot = Instantiate(itemSlotPrefab, itemSlotParent);
shopSlot.Setup(item);
}
- 매번 새로 만들기 때문에 성능적으로 부담 가능성 있음 → 오브젝트 풀링이 필요함
확장성
ObjectPool<ShopItemSlot>을 도입해 슬롯을 재사용하는 방식으로 전환 가능- 판매 시스템, 장비 비교 기능까지 확장 가능
마무리 정리
| 영역 | 평가 | 확장 방향 |
|---|---|---|
| 플레이어 전투 | 안정적 구조 | 스킬 데이터를 ScriptableObject로 분리 |
| 버프 시스템 | 단일 버프만 가능 | 다중 버프 구조(Dict 기반)로 확장 |
| 퀘스트 | 간단한 조건 처리 | 다중 목표/조건 클래스화 |
| 강화 | 명확한 흐름 | 확률/레벨별 규칙 분리 및 연출 추가 |
| 세이브 | 빠른 구현 | JSON 기반으로 구조화 확장 |
| 상점 | 기능적 완성 | 풀링, 판매, 장비비교 등 기능 확장 |

