Skip to main content

kengaai_navigation/
lib.rs

1use glam::{Vec3, Vec2};
2use serde::{Deserialize, Serialize};
3use anyhow::Result;
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
6struct Vec3Ser {
7    x: f32,
8    y: f32,
9    z: f32,
10}
11
12impl From<Vec3> for Vec3Ser {
13    fn from(v: Vec3) -> Self {
14        Self { x: v.x, y: v.y, z: v.z }
15    }
16}
17
18impl From<Vec3Ser> for Vec3 {
19    fn from(v: Vec3Ser) -> Self {
20        Vec3::new(v.x, v.y, v.z)
21    }
22}
23
24/// Треугольник навигационной сетки
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct NavTriangle {
27    #[serde(with = "serde_vertices")]
28    pub vertices: [Vec3; 3],
29    pub neighbors: Vec<usize>, // Индексы соседних треугольников
30    #[serde(with = "serde_vec3")]
31    pub center: Vec3,
32    pub area: f32,
33}
34
35mod serde_vec3 {
36    use super::*;
37    use serde::{Deserialize, Deserializer, Serialize, Serializer};
38
39    pub fn serialize<S>(v: &Vec3, serializer: S) -> Result<S::Ok, S::Error>
40    where
41        S: Serializer,
42    {
43        Vec3Ser::from(*v).serialize(serializer)
44    }
45
46    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec3, D::Error>
47    where
48        D: Deserializer<'de>,
49    {
50        Vec3Ser::deserialize(deserializer).map(Vec3::from)
51    }
52}
53
54mod serde_vertices {
55    use super::*;
56    use serde::{Deserialize, Deserializer, Serialize, Serializer};
57
58    pub fn serialize<S>(v: &[Vec3; 3], serializer: S) -> Result<S::Ok, S::Error>
59    where
60        S: Serializer,
61    {
62        let ser: [Vec3Ser; 3] = [Vec3Ser::from(v[0]), Vec3Ser::from(v[1]), Vec3Ser::from(v[2])];
63        ser.serialize(serializer)
64    }
65
66    pub fn deserialize<'de, D>(deserializer: D) -> Result<[Vec3; 3], D::Error>
67    where
68        D: Deserializer<'de>,
69    {
70        let ser: [Vec3Ser; 3] = Deserialize::deserialize(deserializer)?;
71        Ok([Vec3::from(ser[0]), Vec3::from(ser[1]), Vec3::from(ser[2])])
72    }
73}
74
75impl NavTriangle {
76    pub fn new(vertices: [Vec3; 3]) -> Self {
77        let center = (vertices[0] + vertices[1] + vertices[2]) / 3.0;
78        let v1 = vertices[1] - vertices[0];
79        let v2 = vertices[2] - vertices[0];
80        let area = v1.cross(v2).length() / 2.0;
81        
82        Self {
83            vertices,
84            neighbors: Vec::new(),
85            center,
86            area,
87        }
88    }
89
90    /// Проверяет, находится ли точка внутри треугольника (в 2D, по XZ плоскости)
91    pub fn contains_point_2d(&self, point: Vec3) -> bool {
92        let p = Vec2::new(point.x, point.z);
93        let v0 = Vec2::new(self.vertices[0].x, self.vertices[0].z);
94        let v1 = Vec2::new(self.vertices[1].x, self.vertices[1].z);
95        let v2 = Vec2::new(self.vertices[2].x, self.vertices[2].z);
96        
97        // Используем cross product для проверки ориентации
98        let sign1 = (p - v0).dot(Vec2::new(-(v1 - v0).y, (v1 - v0).x));
99        let sign2 = (p - v1).dot(Vec2::new(-(v2 - v1).y, (v2 - v1).x));
100        let sign3 = (p - v2).dot(Vec2::new(-(v0 - v2).y, (v0 - v2).x));
101        
102        (sign1 >= 0.0 && sign2 >= 0.0 && sign3 >= 0.0) || (sign1 <= 0.0 && sign2 <= 0.0 && sign3 <= 0.0)
103    }
104}
105
106/// Навигационная сетка
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct NavMesh {
109    pub triangles: Vec<NavTriangle>,
110    #[serde(with = "serde_vec3")]
111    pub bounds_min: Vec3,
112    #[serde(with = "serde_vec3")]
113    pub bounds_max: Vec3,
114}
115
116impl NavMesh {
117    pub fn new() -> Self {
118        Self {
119            triangles: Vec::new(),
120            bounds_min: Vec3::splat(f32::MAX),
121            bounds_max: Vec3::splat(f32::MIN),
122        }
123    }
124
125    /// Добавляет треугольник в сетку
126    pub fn add_triangle(&mut self, triangle: NavTriangle) {
127        // Обновляем границы
128        for vertex in &triangle.vertices {
129            self.bounds_min = self.bounds_min.min(*vertex);
130            self.bounds_max = self.bounds_max.max(*vertex);
131        }
132        self.triangles.push(triangle);
133    }
134
135    /// Находит треугольник, содержащий точку
136    pub fn find_triangle(&self, point: Vec3) -> Option<usize> {
137        for (i, triangle) in self.triangles.iter().enumerate() {
138            if triangle.contains_point_2d(point) {
139                return Some(i);
140            }
141        }
142        None
143    }
144
145    /// Находит ближайший треугольник к точке
146    pub fn find_nearest_triangle(&self, point: Vec3) -> Option<usize> {
147        let mut nearest_index = None;
148        let mut nearest_distance = f32::MAX;
149
150        for (i, triangle) in self.triangles.iter().enumerate() {
151            let distance = triangle.center.distance(point);
152            if distance < nearest_distance {
153                nearest_distance = distance;
154                nearest_index = Some(i);
155            }
156        }
157
158        nearest_index
159    }
160}
161
162impl Default for NavMesh {
163    fn default() -> Self {
164        Self::new()
165    }
166}
167
168/// Система поиска пути (упрощенная версия A*)
169pub struct Pathfinder {
170    nav_mesh: NavMesh,
171}
172
173impl Pathfinder {
174    pub fn new(nav_mesh: NavMesh) -> Self {
175        Self { nav_mesh }
176    }
177
178    /// Находит путь от начальной точки до конечной
179    pub fn find_path(&self, start: Vec3, end: Vec3) -> Result<Vec<Vec3>> {
180        let start_triangle = self.nav_mesh.find_triangle(start)
181            .or_else(|| self.nav_mesh.find_nearest_triangle(start))
182            .ok_or_else(|| anyhow::anyhow!("Start point not on nav mesh"))?;
183        
184        let end_triangle = self.nav_mesh.find_triangle(end)
185            .or_else(|| self.nav_mesh.find_nearest_triangle(end))
186            .ok_or_else(|| anyhow::anyhow!("End point not on nav mesh"))?;
187
188        if start_triangle == end_triangle {
189            return Ok(vec![start, end]);
190        }
191
192        // Упрощенный поиск пути через соседние треугольники
193        let mut path = vec![start];
194        let mut current = start_triangle;
195        let mut visited = std::collections::HashSet::new();
196        visited.insert(current);
197
198        // Простой жадный алгоритм движения к цели
199        while current != end_triangle {
200            let current_triangle = &self.nav_mesh.triangles[current];
201            let mut best_neighbor = None;
202            let mut best_distance = f32::MAX;
203
204            for &neighbor_idx in &current_triangle.neighbors {
205                if visited.contains(&neighbor_idx) {
206                    continue;
207                }
208
209                let neighbor = &self.nav_mesh.triangles[neighbor_idx];
210                let distance = neighbor.center.distance(end);
211                if distance < best_distance {
212                    best_distance = distance;
213                    best_neighbor = Some(neighbor_idx);
214                }
215            }
216
217            if let Some(next) = best_neighbor {
218                path.push(self.nav_mesh.triangles[next].center);
219                current = next;
220                visited.insert(current);
221            } else {
222                // Не можем найти путь
223                break;
224            }
225        }
226
227        path.push(end);
228        Ok(path)
229    }
230}
231