# Phase 8-1: AI System — Design Spec ## Overview `voltex_ai` crate를 신규 생성한다. 수동 정의 내비메시, A* 패스파인딩, 스티어링 행동을 구현한다. ## Scope - NavMesh (수동 삼각형 폴리곤, 인접 정보) - A* 패스파인딩 (삼각형 그래프) - 스티어링 행동 (Seek, Flee, Arrive, Wander, FollowPath) ## Out of Scope - 자동 내비메시 생성 (Recast 스타일 복셀화) - String pulling (Funnel algorithm) - 동적 장애물 회피 - ECS 통합 (AI 컴포넌트) - 내비메시 직렬화 ## Module Structure ``` crates/voltex_ai/ ├── Cargo.toml └── src/ ├── lib.rs ├── navmesh.rs — NavMesh, NavTriangle ├── pathfinding.rs — A* find_path └── steering.rs — SteeringAgent, seek/flee/arrive/wander/follow_path ``` ## Dependencies - `voltex_math` — Vec3 ## Types ### NavTriangle ```rust #[derive(Debug, Clone)] pub struct NavTriangle { pub indices: [usize; 3], pub neighbors: [Option; 3], } ``` - `indices` — NavMesh.vertices 인덱스 (CCW) - `neighbors[i]` — edge i↔(i+1) 반대편 삼각형. None이면 경계 에지. ### NavMesh ```rust pub struct NavMesh { pub vertices: Vec, pub triangles: Vec, } ``` **Methods:** - `new(vertices, triangles)` — 생성 - `find_triangle(point: Vec3) -> Option` — XZ 평면 투영으로 점이 속한 삼각형 인덱스 반환 - `triangle_center(tri_idx: usize) -> Vec3` — 삼각형 세 꼭짓점의 중심 - `edge_midpoint(tri_idx: usize, edge: usize) -> Vec3` — 에지 중점 (공유 에지 통과 지점) ### A* Pathfinding ```rust pub fn find_path(navmesh: &NavMesh, start: Vec3, goal: Vec3) -> Option> ``` 1. `find_triangle(start)`, `find_triangle(goal)` — 시작/목표 삼각형 2. 둘 다 찾지 못하면 None 3. 같은 삼각형이면 `vec![start, goal]` 4. A* on triangle graph: - Node = triangle index - Neighbors = triangle.neighbors (Some만) - g cost = 현재까지 실제 거리 (중심점 간) - h cost = 현재 삼각형 중심 → 목표 삼각형 중심 유클리드 거리 5. 결과: 삼각형 체인 → 각 삼각형 중심점으로 경로 생성 6. 경로 시작에 start, 끝에 goal 삽입 ### SteeringAgent ```rust #[derive(Debug, Clone, Copy)] pub struct SteeringAgent { pub position: Vec3, pub velocity: Vec3, pub max_speed: f32, pub max_force: f32, } ``` ### Steering Functions 모두 순수 함수, `Vec3` 조향력 반환 (에이전트 velocity에 더하기 전). ```rust pub fn seek(agent: &SteeringAgent, target: Vec3) -> Vec3 ``` - desired = normalize(target - position) * max_speed - steering = desired - velocity - truncate to max_force ```rust pub fn flee(agent: &SteeringAgent, threat: Vec3) -> Vec3 ``` - seek 반대 방향 ```rust pub fn arrive(agent: &SteeringAgent, target: Vec3, slow_radius: f32) -> Vec3 ``` - distance < slow_radius이면 desired speed = max_speed * (distance / slow_radius) - 목표에 매우 가까우면 (< 0.01) 제로 ```rust pub fn wander(agent: &SteeringAgent, wander_radius: f32, wander_distance: f32, angle: f32) -> Vec3 ``` - agent 전방 wander_distance에 원(wander_radius) 위의 점을 target으로 seek - angle은 호출자가 매 프레임 랜덤 변경 ```rust pub fn follow_path(agent: &SteeringAgent, path: &[Vec3], current_waypoint: usize, waypoint_radius: f32) -> (Vec3, usize) ``` - current_waypoint에 도달하면 다음으로 전진 - 마지막 웨이포인트면 arrive - 아니면 seek - 반환: (steering_force, updated_waypoint_index) ## Test Plan ### navmesh.rs - 정사각형(2 삼각형) 내비메시 생성 - find_triangle: 내부 점 → Some, 외부 점 → None - triangle_center: 정확한 중심 - edge_midpoint: 공유 에지 중점 ### pathfinding.rs - 같은 삼각형: 직선 경로 - 인접 삼각형: 2-step 경로 - 3개 삼각형 체인: 올바른 순서 - 도달 불가: None - start/goal이 navmesh 밖: None ### steering.rs - seek: 목표 방향 - flee: 반대 방향 - arrive: 가까우면 감속, 멀면 max_speed - follow_path: 웨이포인트 전진