docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
This commit is contained in:
@@ -0,0 +1,479 @@
|
||||
---
|
||||
id: wiki-2026-0508-ai-추적-논리-ai-pursuit-logic
|
||||
title: AI Pursuit Logic (AI 추적 논리)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [AI 추적, pursuit logic, aggro, threat detection, leash range, NPC chase]
|
||||
duplicate_of: none
|
||||
source_trust_level: B
|
||||
confidence_score: 0.85
|
||||
verification_status: conceptual
|
||||
tags: [game-ai, pursuit, aggro, threat-system, npc-design, baiting, leash, fsm, behavior-tree]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-09
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (manual cleanup 2026-05-09)
|
||||
tech_stack:
|
||||
language: game design / Unity / Unreal
|
||||
applicable_to: [Game Design, Combat AI, RTS, MMO, FPS]
|
||||
---
|
||||
|
||||
# AI Pursuit Logic (AI 추적 논리)
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> **"매 enemy 의 어떤 target 의 chase?"**. Aggro / threat / line-of-sight / leash 의 4 component. 매 RTS / MMO / FPS 의 fundamental. **매 deterministic = baiting exploitable, 매 random = unpredictable feel**.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
|
||||
### 매 component
|
||||
1. **Detection**: 매 enemy 의 sight cone / sound / threat radius.
|
||||
2. **Threat / aggro**: 매 player 의 weight (proximity, damage dealt, special).
|
||||
3. **Pursuit decision**: 매 stance / state 의 chase / hold.
|
||||
4. **Leash**: 매 chase 의 max distance.
|
||||
5. **De-aggro**: 매 reset condition.
|
||||
|
||||
### 매 stance / state
|
||||
|
||||
#### Active pursuit (Fire at Will / Aggressive)
|
||||
- 매 enemy detect → chase to engage.
|
||||
- 매 wide pursuit radius.
|
||||
- Vulnerable to baiting.
|
||||
|
||||
#### Defensive (Hold Position / Stand Ground)
|
||||
- 매 stay in spot.
|
||||
- 매 in-range only engage.
|
||||
- Bait 의 immune.
|
||||
|
||||
#### Patrol
|
||||
- 매 fixed route.
|
||||
- 매 detect → pursue 일정 time → return.
|
||||
- 매 player 의 timing exploit.
|
||||
|
||||
#### Guarding
|
||||
- 매 specific target / area.
|
||||
- 매 leash 의 strict.
|
||||
- 매 player 의 line-of-sight break 의 reset.
|
||||
|
||||
#### Conditional (low HP, ally death)
|
||||
- 매 trigger 의 stance change.
|
||||
- Berserk / flee.
|
||||
|
||||
### Aggro / threat system
|
||||
|
||||
#### Proximity-based (simple)
|
||||
- 매 distance 의 inverse 의 weight.
|
||||
- 매 closest = highest priority.
|
||||
|
||||
#### Damage-based
|
||||
- 매 damage dealt 의 cumulative.
|
||||
- 매 healer / DPS 의 high priority.
|
||||
- MMO 의 tank role 의 enable.
|
||||
|
||||
#### Stealth / detection
|
||||
- 매 sight cone (FPS, stealth game).
|
||||
- 매 noise level.
|
||||
- 매 disguise / blend.
|
||||
|
||||
#### Special abilities
|
||||
- 매 taunt / provoke 의 instant aggro.
|
||||
- 매 invisibility / cloak 의 break aggro.
|
||||
- 매 mind control.
|
||||
|
||||
### Leash mechanism
|
||||
- 매 chase 의 max range.
|
||||
- 매 exceed = full reset (heal, return).
|
||||
- 매 cheese 의 prevent (kite + reset attack).
|
||||
|
||||
```
|
||||
Chase distance > maxLeash:
|
||||
- Stop pursuit.
|
||||
- Reset HP to full.
|
||||
- Return to spawn.
|
||||
- 매 player 의 punish.
|
||||
```
|
||||
|
||||
### Wild goose chase 의 exploit
|
||||
1. Player unit (fast / cheap) 의 enemy 의 lure.
|
||||
2. Enemy 의 pursue.
|
||||
3. Player 의 ambush location.
|
||||
4. Enemy 의 trap.
|
||||
|
||||
→ 매 RTS / MMO 의 universal tactic.
|
||||
|
||||
### Modern variants
|
||||
|
||||
#### Adaptive aggro
|
||||
- 매 player behavior 의 learn.
|
||||
- 매 cheese pattern 의 detect.
|
||||
- 매 counter-strategy.
|
||||
|
||||
#### Squad coordination
|
||||
- 매 enemy 의 group communicate.
|
||||
- 매 player 의 line-of-sight 의 share.
|
||||
- 매 flanking maneuver.
|
||||
|
||||
#### Memory / persistence
|
||||
- 매 enemy 의 last known player position.
|
||||
- 매 search 의 specific area.
|
||||
- 매 continued investigation.
|
||||
|
||||
#### Investigation state (stealth)
|
||||
- 매 noise → suspicious → investigate → return / aggro.
|
||||
- 매 partial detection 의 layered.
|
||||
|
||||
### Game examples
|
||||
|
||||
#### Classic RTS (StarCraft, AoE, Warcraft)
|
||||
- A-move = active pursuit.
|
||||
- Stop / Hold = anchor.
|
||||
- 매 leash range.
|
||||
|
||||
#### MMO (WoW, FFXIV)
|
||||
- 매 mob 의 leash range (tunable).
|
||||
- 매 tank 의 threat.
|
||||
- 매 reset 의 full heal (anti-cheese).
|
||||
|
||||
#### Stealth (Splinter Cell, MGS)
|
||||
- 매 detection meter.
|
||||
- 매 sound radius.
|
||||
- 매 alert state cycle.
|
||||
|
||||
#### FPS (Halo, Doom)
|
||||
- 매 enemy 의 cover seeking.
|
||||
- 매 line-of-sight break 의 search.
|
||||
- 매 grenade 의 flush.
|
||||
|
||||
### Player exploit pattern
|
||||
|
||||
#### 1. Bait + lure
|
||||
- 매 cheap unit 의 sacrifice.
|
||||
- 매 enemy 의 chase.
|
||||
- 매 ambush.
|
||||
|
||||
#### 2. Kiting
|
||||
- 매 ranged 의 attack + retreat.
|
||||
- 매 enemy 의 perpetual pursue.
|
||||
- 매 attrition kill.
|
||||
|
||||
#### 3. Line-of-sight break
|
||||
- 매 wall 의 hide.
|
||||
- 매 enemy 의 lose vision.
|
||||
- 매 reset / stealth.
|
||||
|
||||
#### 4. Leash exploit
|
||||
- 매 enemy 의 leash 끝.
|
||||
- 매 attack 후 retreat.
|
||||
- 매 enemy 의 reset (full heal — but separated).
|
||||
|
||||
→ 매 MMO 의 banned (exploit) 또는 intended (skill).
|
||||
|
||||
#### 5. Aggro management
|
||||
- 매 player 의 selective threat.
|
||||
- 매 boss 의 specific target.
|
||||
- 매 strategic positioning.
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
### Threat / aggro table
|
||||
```csharp
|
||||
public class ThreatTable {
|
||||
Dictionary<Player, float> threats = new();
|
||||
|
||||
public void AddThreat(Player p, float amount) {
|
||||
threats[p] = threats.GetValueOrDefault(p, 0) + amount;
|
||||
}
|
||||
|
||||
public Player GetTopThreat() {
|
||||
if (threats.Count == 0) return null;
|
||||
return threats.OrderByDescending(x => x.Value).First().Key;
|
||||
}
|
||||
|
||||
public void Decay(float deltaTime) {
|
||||
foreach (var key in threats.Keys.ToList()) {
|
||||
threats[key] *= Mathf.Pow(0.9f, deltaTime); // 10s half-life
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPlayerDeath(Player p) { threats.Remove(p); }
|
||||
}
|
||||
```
|
||||
|
||||
### Pursuit FSM
|
||||
```csharp
|
||||
public enum AIState { Idle, Patrol, Suspicious, Pursuing, Engaging, Returning }
|
||||
|
||||
public class EnemyAI : MonoBehaviour {
|
||||
public AIState state = AIState.Idle;
|
||||
public Vector3 spawnPoint;
|
||||
public float leashRange = 30f;
|
||||
public float sightRange = 15f;
|
||||
public Transform target;
|
||||
|
||||
void Update() {
|
||||
switch (state) {
|
||||
case AIState.Idle:
|
||||
if (DetectPlayer()) state = AIState.Pursuing;
|
||||
break;
|
||||
|
||||
case AIState.Pursuing:
|
||||
if (Vector3.Distance(transform.position, spawnPoint) > leashRange) {
|
||||
state = AIState.Returning;
|
||||
target = null;
|
||||
} else if (InAttackRange()) {
|
||||
state = AIState.Engaging;
|
||||
} else {
|
||||
MoveToward(target.position);
|
||||
}
|
||||
break;
|
||||
|
||||
case AIState.Engaging:
|
||||
Attack(target);
|
||||
if (!InAttackRange()) state = AIState.Pursuing;
|
||||
break;
|
||||
|
||||
case AIState.Returning:
|
||||
if (ReachedSpawn()) {
|
||||
HealFully(); // anti-cheese
|
||||
state = AIState.Idle;
|
||||
}
|
||||
MoveToward(spawnPoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool DetectPlayer() {
|
||||
Player p = FindNearestPlayer();
|
||||
if (p == null) return false;
|
||||
if (Vector3.Distance(transform.position, p.transform.position) > sightRange) return false;
|
||||
if (!HasLineOfSight(p)) return false;
|
||||
target = p.transform;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Stance-based pursuit (RTS)
|
||||
```csharp
|
||||
public enum Stance { Passive, Defensive, Aggressive, Hold }
|
||||
|
||||
public class RTSUnit : MonoBehaviour {
|
||||
public Stance stance = Stance.Defensive;
|
||||
public float pursuitRadius = 10f;
|
||||
|
||||
void Update() {
|
||||
switch (stance) {
|
||||
case Stance.Passive:
|
||||
// Don't engage. Move only on player command.
|
||||
break;
|
||||
|
||||
case Stance.Defensive:
|
||||
// Engage in attack range only.
|
||||
Enemy nearby = FindEnemyInRange(attackRange);
|
||||
if (nearby != null) Attack(nearby);
|
||||
break;
|
||||
|
||||
case Stance.Aggressive:
|
||||
// Pursue any enemy in radius.
|
||||
Enemy enemy = FindEnemyInRange(pursuitRadius);
|
||||
if (enemy != null) {
|
||||
if (InAttackRange(enemy)) Attack(enemy);
|
||||
else MoveToward(enemy.transform.position);
|
||||
}
|
||||
break;
|
||||
|
||||
case Stance.Hold:
|
||||
// Like Defensive but no movement.
|
||||
Enemy inRange = FindEnemyInRange(attackRange);
|
||||
if (inRange != null) Attack(inRange); // No move.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Sight cone (stealth)
|
||||
```csharp
|
||||
public class SightCone : MonoBehaviour {
|
||||
public float sightRange = 15f;
|
||||
public float sightAngle = 90f;
|
||||
public LayerMask obstacleLayer;
|
||||
|
||||
public bool CanSee(Transform target) {
|
||||
Vector3 dir = (target.position - transform.position).normalized;
|
||||
float dist = Vector3.Distance(transform.position, target.position);
|
||||
|
||||
if (dist > sightRange) return false;
|
||||
if (Vector3.Angle(transform.forward, dir) > sightAngle / 2) return false;
|
||||
|
||||
// Line-of-sight check
|
||||
if (Physics.Raycast(transform.position, dir, dist, obstacleLayer)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### De-aggro / reset
|
||||
```csharp
|
||||
public class DeAggro : MonoBehaviour {
|
||||
public float losTimeout = 5f; // 5s 의 line-of-sight break = reset
|
||||
float lastSeenTime;
|
||||
|
||||
void Update() {
|
||||
if (sight.CanSee(target)) {
|
||||
lastSeenTime = Time.time;
|
||||
} else if (Time.time - lastSeenTime > losTimeout) {
|
||||
ResetAggro();
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAggro() {
|
||||
threatTable.Clear();
|
||||
target = null;
|
||||
state = AIState.Returning;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Squad coordination
|
||||
```csharp
|
||||
public class Squad : MonoBehaviour {
|
||||
List<EnemyAI> members = new();
|
||||
Player sharedTarget;
|
||||
|
||||
public void OnDetect(Player p) {
|
||||
if (sharedTarget == null) {
|
||||
sharedTarget = p;
|
||||
// Alert all members
|
||||
foreach (var m in members) {
|
||||
m.target = p.transform;
|
||||
m.state = AIState.Pursuing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Coordinate() {
|
||||
// 매 member 의 different angle 의 attack.
|
||||
for (int i = 0; i < members.Count; i++) {
|
||||
float angle = (Mathf.PI * 2 * i) / members.Count;
|
||||
Vector3 offset = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * 5;
|
||||
members[i].SetMoveTarget(sharedTarget.transform.position + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Memory / investigation (stealth)
|
||||
```csharp
|
||||
public class GuardAI : MonoBehaviour {
|
||||
public AIState state = AIState.Patrol;
|
||||
Vector3 lastSeenPosition;
|
||||
float investigateTime = 10f;
|
||||
|
||||
void Update() {
|
||||
if (state == AIState.Patrol) {
|
||||
if (DetectPlayer()) {
|
||||
state = AIState.Pursuing;
|
||||
lastSeenPosition = target.position;
|
||||
}
|
||||
} else if (state == AIState.Pursuing) {
|
||||
if (CanSeePlayer()) {
|
||||
lastSeenPosition = target.position;
|
||||
} else {
|
||||
state = AIState.Investigating;
|
||||
}
|
||||
} else if (state == AIState.Investigating) {
|
||||
MoveToward(lastSeenPosition);
|
||||
|
||||
if (ReachedDestination()) {
|
||||
if (CanSeePlayer()) {
|
||||
state = AIState.Pursuing;
|
||||
} else if (timeInState > investigateTime) {
|
||||
state = AIState.Patrol; // Give up.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Anti-cheese (RTS leash + heal)
|
||||
```csharp
|
||||
public class AntiCheese : MonoBehaviour {
|
||||
public float maxLeash = 30f;
|
||||
Vector3 spawnPoint;
|
||||
|
||||
void Update() {
|
||||
if (Vector3.Distance(transform.position, spawnPoint) > maxLeash) {
|
||||
// 매 player 의 kite + reset attack 의 punish.
|
||||
ResetAggro();
|
||||
FullHeal();
|
||||
ReturnHome();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
|
||||
| 상황 | 추천 pursuit logic |
|
||||
|---|---|
|
||||
| RTS unit | Stance-based (player choice) |
|
||||
| MMO mob | Threat table + leash |
|
||||
| FPS enemy | Sight cone + cover seeking |
|
||||
| Stealth game | Sight + sound + investigation state |
|
||||
| Boss fight | Phased + threat + special mechanic |
|
||||
| Roguelike | Simple proximity + variety |
|
||||
|
||||
**기본값**: Threat table + leash + LOS-based reset. Anti-cheese.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **Predictable vs unfair**: 매 deterministic 의 baiting exploit, 매 random 의 frustrating.
|
||||
- **Aggro 의 transparency**: MMO 의 tank role 의 explicit threat. 매 player 의 strategic.
|
||||
- **Leash 의 anti-cheese vs immersion**: 매 reset 의 unrealistic feel.
|
||||
- **AI 의 squad coordination 의 cost**: 매 sophisticated 의 dev expensive.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- 응용: [[AI Exploitation (Game AI 공략)]] · [[Baiting Tactics]]
|
||||
- 매 game: [[War-Commander]]
|
||||
- Adjacent: [[Behavior-Tree]]
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- 매 game 의 enemy AI design.
|
||||
- 매 stance / threat system 의 implement.
|
||||
- 매 stealth game 의 detection.
|
||||
- 매 boss fight 의 mechanic.
|
||||
- 매 player exploit 의 review.
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- Single-player turn-based (different paradigm).
|
||||
- Walking simulator.
|
||||
- 매 LLM agent (different domain — partial overlap).
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
- **No leash + open world**: 매 cheese 의 enable.
|
||||
- **Pure proximity threat**: 매 healer / DPS 의 unfair.
|
||||
- **No LOS reset**: 매 wall 의 follow 의 unrealistic.
|
||||
- **No memory**: 매 player 의 hide 후 의 instant forget.
|
||||
- **No squad coordination**: 매 1 vs 1 의 weak.
|
||||
- **Fully deterministic**: 매 첫 try 후 trivialize.
|
||||
- **Excessive randomness**: 매 player 의 frustrating.
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
- **정보 상태:** verified (concept-level).
|
||||
- **출처 신뢰도:** B (Game AI Programming Wisdom series, Unity / Unreal documentation, GDC talks).
|
||||
- **검토 이유:** Manual cleanup. 매 specific game 의 implementation 가 design choice.
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
- **기존 유사 문서:** [[AI Exploitation (Game AI 공략)]] (related), [[Game-AI-Behavior-Tree]] (parent), [[Combat-AI]] (parent).
|
||||
- **처리 방식:** KEEP (specific focus on pursuit).
|
||||
- **처리 이유:** Pursuit logic 가 specific component.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 | UPDATE | A |
|
||||
| 2026-05-09 | Manual cleanup — Unity code + 4 component + 매 game example + 안티패턴 추가 | UPDATE | B |
|
||||
Reference in New Issue
Block a user