Skip to main content

il2cpp_bridge_rs/structs/components/physics/
physics.rs

1//! Unity Physics helper wrapper
2use crate::structs::components::physics::collider::Collider;
3use crate::structs::components::physics::layer_mask::LayerMask;
4use crate::structs::math::{Ray, RaycastHit, Vector3};
5use std::ffi::c_void;
6
7#[repr(transparent)]
8pub struct Physics;
9
10impl Physics {
11    /// Gets the Physics class definition
12    ///
13    /// # Returns
14    /// * `Option<Class>` - The UnityEngine.Physics class
15    pub fn get_class() -> Option<crate::structs::core::Class> {
16        crate::api::cache::coremodule().class("UnityEngine.Physics")
17    }
18
19    /// Casts a ray against all colliders
20    ///
21    /// # Arguments
22    /// * `origin` - The starting point of the ray
23    /// * `direction` - The direction of the ray
24    /// * `hit_info` - Output structure containing hit information
25    /// * `max_distance` - The maximum distance the ray should check
26    /// * `layer_mask` - A LayerMask that filters which colliders to check
27    ///
28    /// # Returns
29    /// * `bool` - True if the ray hits a collider
30    pub fn raycast(
31        origin: Vector3,
32        direction: Vector3,
33        hit_info: &mut RaycastHit,
34        max_distance: f32,
35        layer_mask: LayerMask,
36    ) -> bool {
37        if let Some(class) = Self::get_class() {
38            if let Some(method) = class.method((
39                "Raycast",
40                [
41                    "UnityEngine.Vector3",
42                    "UnityEngine.Vector3",
43                    "UnityEngine.RaycastHit&",
44                    "System.Single",
45                    "System.Int32",
46                ],
47            )) {
48                let mut origin_cp = origin;
49                let mut direction_cp = direction;
50                let mut max_distance_cp = max_distance;
51                let mut layer_mask_cp = layer_mask.value;
52
53                let params = &mut [
54                    &mut origin_cp as *mut Vector3 as *mut c_void,
55                    &mut direction_cp as *mut Vector3 as *mut c_void,
56                    hit_info as *mut RaycastHit as *mut c_void,
57                    &mut max_distance_cp as *mut f32 as *mut c_void,
58                    &mut layer_mask_cp as *mut i32 as *mut c_void,
59                ];
60
61                let res = unsafe { method.call::<bool>(params) };
62                return res.unwrap_or(false);
63            }
64        }
65        false
66    }
67
68    /// Casts a ray using a Ray struct
69    ///
70    /// # Arguments
71    /// * `ray` - The Ray to cast
72    /// * `hit_info` - Output structure containing hit information
73    /// * `max_distance` - The maximum distance the ray should check
74    /// * `layer_mask` - A LayerMask that filters which colliders to check
75    ///
76    /// # Returns
77    /// * `bool` - True if the ray hits a collider
78    pub fn raycast_ray(
79        ray: Ray,
80        hit_info: &mut RaycastHit,
81        max_distance: f32,
82        layer_mask: LayerMask,
83    ) -> bool {
84        if let Some(class) = Self::get_class() {
85            if let Some(method) = class.method((
86                "Raycast",
87                [
88                    "UnityEngine.Ray",
89                    "UnityEngine.RaycastHit&",
90                    "System.Single",
91                    "System.Int32",
92                ],
93            )) {
94                let mut ray_cp = ray;
95                let mut max_distance_cp = max_distance;
96                let mut layer_mask_cp = layer_mask.value;
97
98                let params = &mut [
99                    &mut ray_cp as *mut Ray as *mut c_void,
100                    hit_info as *mut RaycastHit as *mut c_void,
101                    &mut max_distance_cp as *mut f32 as *mut c_void,
102                    &mut layer_mask_cp as *mut i32 as *mut c_void,
103                ];
104
105                let res = unsafe { method.call::<bool>(params) };
106                return res.unwrap_or(false);
107            }
108        }
109        false
110    }
111
112    /// Casts a sphere along a ray
113    ///
114    /// # Arguments
115    /// * `origin` - The center of the sphere at the start of the sweep
116    /// * `radius` - The radius of the sphere
117    /// * `direction` - The direction into which to sweep the sphere
118    /// * `hit_info` - Output structure containing hit information
119    /// * `max_distance` - The maximum distance the sphere should check
120    /// * `layer_mask` - A LayerMask that filters which colliders to check
121    ///
122    /// # Returns
123    /// * `bool` - True if the sphere hits a collider
124    pub fn sphere_cast(
125        origin: Vector3,
126        radius: f32,
127        direction: Vector3,
128        hit_info: &mut RaycastHit,
129        max_distance: f32,
130        layer_mask: LayerMask,
131    ) -> bool {
132        if let Some(class) = Self::get_class() {
133            if let Some(method) = class.method((
134                "SphereCast",
135                [
136                    "UnityEngine.Vector3",
137                    "System.Single",
138                    "UnityEngine.Vector3",
139                    "UnityEngine.RaycastHit&",
140                    "System.Single",
141                    "System.Int32",
142                ],
143            )) {
144                let mut origin_cp = origin;
145                let mut radius_cp = radius;
146                let mut direction_cp = direction;
147                let mut max_distance_cp = max_distance;
148                let mut layer_mask_cp = layer_mask.value;
149
150                let params = &mut [
151                    &mut origin_cp as *mut Vector3 as *mut c_void,
152                    &mut radius_cp as *mut f32 as *mut c_void,
153                    &mut direction_cp as *mut Vector3 as *mut c_void,
154                    hit_info as *mut RaycastHit as *mut c_void,
155                    &mut max_distance_cp as *mut f32 as *mut c_void,
156                    &mut layer_mask_cp as *mut i32 as *mut c_void,
157                ];
158
159                let res = unsafe { method.call::<bool>(params) };
160                return res.unwrap_or(false);
161            }
162        }
163        false
164    }
165
166    /// Computes and stores colliders touching or inside the sphere
167    ///
168    /// # Arguments
169    /// * `position` - Center of the sphere
170    /// * `radius` - Radius of the sphere
171    /// * `layer_mask` - A LayerMask that filters which colliders to check
172    ///
173    /// # Returns
174    /// * `Vec<Collider>` - A list of colliders that overlap the sphere
175    pub fn overlap_sphere(position: Vector3, radius: f32, layer_mask: LayerMask) -> Vec<Collider> {
176        if let Some(class) = Self::get_class() {
177            if let Some(method) = class.method((
178                "OverlapSphere",
179                ["UnityEngine.Vector3", "System.Single", "System.Int32"],
180            )) {
181                let mut position_cp = position;
182                let mut radius_cp = radius;
183                let mut layer_mask_cp = layer_mask.value;
184
185                let params = &mut [
186                    &mut position_cp as *mut Vector3 as *mut c_void,
187                    &mut radius_cp as *mut f32 as *mut c_void,
188                    &mut layer_mask_cp as *mut i32 as *mut c_void,
189                ];
190
191                let res = unsafe { method.call::<*mut c_void>(params) };
192                if let Ok(ptr) = res {
193                    if !ptr.is_null() {
194                        let array_ptr =
195                            ptr as *mut crate::structs::collections::Il2cppArray<*mut c_void>;
196                        let mut colliders = Vec::new();
197                        let len = unsafe { (*array_ptr).max_length };
198                        for i in 0..len {
199                            let item_ptr = unsafe { (*array_ptr).at(i) };
200                            if !item_ptr.is_null() {
201                                unsafe {
202                                    colliders.push(Collider::from_ptr(item_ptr));
203                                }
204                            }
205                        }
206                        return colliders;
207                    }
208                }
209            }
210        }
211        Vec::new()
212    }
213
214    /// Gets global gravity
215    ///
216    /// # Returns
217    /// * `Vector3` - The gravity vector
218    pub fn get_gravity() -> Vector3 {
219        if let Some(class) = Self::get_class() {
220            if let Some(method) = class.method("get_gravity") {
221                let res = unsafe { method.call::<Vector3>(&[]) };
222                return res.unwrap_or(Vector3::ZERO);
223            }
224        }
225        Vector3::ZERO
226    }
227
228    /// Sets global gravity
229    ///
230    /// # Arguments
231    /// * `value` - The new gravity vector
232    pub fn set_gravity(value: Vector3) {
233        if let Some(class) = Self::get_class() {
234            if let Some(method) = class.method("set_gravity") {
235                let mut value_cp = value;
236                let params = &mut [&mut value_cp as *mut Vector3 as *mut c_void];
237                let _ = unsafe { method.call::<()>(params) };
238            }
239        }
240    }
241}