Skip to main content

vimp_engine_core/
physics.rs

1/// Метка тела в user_data Rapier (аналог body.userData JS-версии).
2/// Кодируется в u128: тип в младшем байте. Движок знает только про статику
3/// карты; игровые теги (танк/снаряд) кодируются в игровом crate и обязаны
4/// использовать значения младшего байта, отличные от `MAP_OBJECT_TAG`
5/// (зарезервированный диапазон движка — только `1`; игра начинает с `2`).
6pub const MAP_OBJECT_TAG: u128 = 1;
7
8/// Кодирует тег статики карты.
9pub fn encode_map_object() -> u128 {
10    MAP_OBJECT_TAG
11}
12
13/// Является ли тело статикой карты.
14pub fn is_map_object(user_data: u128) -> bool {
15    (user_data & 0xff) == MAP_OBJECT_TAG
16}
17
18/// Округление до 2 знаков (lib/formatters.js roundTo2Decimals).
19pub fn round2(v: f32) -> f32 {
20    ((v as f64 * 100.0).round() / 100.0) as f32
21}
22
23/// Округление до 1 знака (+value.toFixed(1) в JS-частях).
24pub fn round1(v: f32) -> f32 {
25    ((v as f64 * 10.0).round() / 10.0) as f32
26}
27
28/// Перевод градусов в радианы (lib/math.js degToRad).
29pub fn deg_to_rad(degrees: f32) -> f32 {
30    degrees * (core::f32::consts::PI / 180.0)
31}
32
33/// Линейная интерполяция (lib/math.js lerp).
34pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
35    a + (b - a) * t
36}
37
38/// Ограничение в диапазоне (lib/math.js clamp).
39pub fn clamp(value: f32, min: f32, max: f32) -> f32 {
40    value.min(max).max(min)
41}
42
43/// Интерполяция угла по кратчайшему пути (lib/math.js lerpAngle).
44pub fn lerp_angle(a: f32, b: f32, t: f32) -> f32 {
45    let mut diff = b - a;
46
47    while diff > core::f32::consts::PI {
48        diff -= core::f32::consts::PI * 2.0;
49    }
50
51    while diff < -core::f32::consts::PI {
52        diff += core::f32::consts::PI * 2.0;
53    }
54
55    a + diff * t
56}
57
58/// Нормализация угла к диапазону [-PI, PI] (lib/math.js normalizeAngle).
59pub fn normalize_angle(mut angle: f32) -> f32 {
60    while angle > core::f32::consts::PI {
61        angle -= core::f32::consts::PI * 2.0;
62    }
63
64    while angle < -core::f32::consts::PI {
65        angle += core::f32::consts::PI * 2.0;
66    }
67
68    angle
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn map_object_roundtrip() {
77        assert!(is_map_object(encode_map_object()));
78    }
79
80    #[test]
81    fn non_map_object_returns_false() {
82        assert!(!is_map_object(0));
83        assert!(!is_map_object(0xff));
84    }
85
86    #[test]
87    fn rounding_matches_js() {
88        assert_eq!(round2(10.567), 10.57);
89        assert_eq!(round2(-3.14159), -3.14);
90        assert_eq!(round1(10.567), 10.6);
91    }
92}