[2025_12_16] 오토배틀 게임 유닛 AI 구현하며 마주친 문제들
2025. 12. 16. 21:37ㆍTIL
TIL: 오토배틀 유닛 AI 구현 문제들
문제 1: 전투 중인 유닛이 밀려난다
뒤에서 오는 유닛들이 전투 중인 유닛을 계속 밀어냈다.
해결: 전투 위치를 완전 고정 + IsInCombat 플래그
csharp
// AttackState.cs
public void Enter(UnitFSM unitFSM)
{
combatPosition = unit.transform.position; // 위치 저장
unit.SetCombatState(true);
}
public void PhysicsExecute(UnitFSM unitFSM)
{
unit.transform.position = combatPosition; // 매 프레임 강제 고정
}
```
IsInCombat 플래그로 다른 유닛들이 전투 유닛을 감지하고 강하게 회피한다.
---
## 문제 2: 유닛들이 지그재그로 왔다갔다
0.5초마다 우회 방향을 체크하니 계속 방향이 바뀌었다.
```
t=0.0: 정면 막힘 → 우상 우회
t=0.5: 우상 막힘 → 좌상 우회
t=1.0: 좌상 막힘 → 우상 우회
→ 유닛이 1→2→1→2 왔다갔다
해결: 8방향 체크 + 방향 고정 시간
csharp
private void CheckAndFindDetour()
{
// 8방향 체크 (정면, 좌상, 좌, 좌하, 후, 우하, 우, 우상)
bool frontBlocked = IsDirectionBlockedByCombat(directions[0]);
// 정면 뚫렸으면 즉시 복귀
if (!frontBlocked)
{
hasDetour = false;
return;
}
// 이미 우회 중이고 1초 안 지났으면 방향 유지
if (hasDetour && detourTimer < 1f)
{
return;
}
// 빈 공간 찾아서 우회
for (int i = 0; i < 8; i++)
{
if (!IsDirectionBlockedByCombat(directions[i]))
{
detourDirection = directions[i];
hasDetour = true;
break;
}
}
}
```
---
## 문제 3: 궁수가 조금씩 전진한다
적 처치 후 다음 적을 찾는 0.3초 동안 기본 방향(위쪽)으로 전진했다.
```
t=0.0: 적 처치 → MoveState
타겟 없음 → 위로 전진 X
t=0.3: 적 발견 → 타겟 설정
→ 0.3초 × 2m/s = 0.6m 불필요하게 전진
해결: 타겟 없으면 정지 + AttackState 종료 시 즉시 탐색
csharp
// MoveState.cs
public void Execute(UnitFSM unitFSM)
{
if (currentTarget != null)
{
moveDirection = (currentTarget.transform.position - unit.transform.position).normalized;
}
else
{
moveDirection = Vector3.zero; // 정지
}
}
// AttackState.cs
public void Exit(UnitFSM unitFSM)
{
unit.SetCombatState(false);
// 즉시 다음 적 탐색
UnitBase nextEnemy = unit.FindNearestEnemy();
if (nextEnemy != null)
{
unit.SetCurrentTarget(nextEnemy);
}
}
문제 4: 중복 코드
MoveState와 AttackState 모두 적 탐색 코드가 필요했다.
해결: UnitBase로 공통 메서드 추출
csharp
// UnitBase.cs
public UnitBase FindNearestEnemy()
{
float detectionRange = Data.unitDetectionRange ?? 5f;
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, detectionRange);
// 가장 가까운 적 반환
}
// State에서 사용
UnitBase enemy = unit.FindNearestEnemy();
배운 점
- 단순함이 최고: 복잡한 3단계 포위 시스템보다 8방향 체크가 더 자연스러웠다
- 플래그의 힘: IsInCombat 하나로 여러 시스템에서 활용
- 즉시 vs 주기적: 중요한 건 즉시(정면 뚫림), 덜 중요한 건 주기적(0.3초마다 적 감지)
남은 과제
- 우선순위 타겟팅: 가까운 적이 아니라 HP 낮은 적 먼저 공격
- 대형 유지: 일정한 간격 유지하며 전진
- 유닛 생성시 Instantiate가 아니라 ObjectPooling 활용하기
'TIL' 카테고리의 다른 글
| [2025_12_18] Factory패턴의 실적용 여부 (0) | 2025.12.18 |
|---|---|
| [2025_12_17] 유닛 이동 관련 최적화 (0) | 2025.12.17 |
| [2025_12_15] SpreadSheet에서 배열 파싱 오류 (0) | 2025.12.15 |
| [2025_12_12]FSM에서 StatePattern사용 (0) | 2025.12.12 |
| [2025_12_11] 변동된 데이터 테이블 확인의 중요 (0) | 2025.12.11 |