dora_ssr/dora/physics_world.rs
1/* Copyright (c) 2016-2025 Li Jin <dragon-fly@qq.com>
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9extern "C" {
10 fn physicsworld_type() -> i32;
11 fn physicsworld_query(slf: i64, rect: i64, func0: i32, stack0: i64) -> i32;
12 fn physicsworld_raycast(slf: i64, start: i64, stop: i64, closest: i32, func0: i32, stack0: i64) -> i32;
13 fn physicsworld_set_iterations(slf: i64, velocity_iter: i32, position_iter: i32);
14 fn physicsworld_set_should_contact(slf: i64, group_a: i32, group_b: i32, contact: i32);
15 fn physicsworld_get_should_contact(slf: i64, group_a: i32, group_b: i32) -> i32;
16 fn physicsworld_set_scale_factor(val: f32);
17 fn physicsworld_get_scale_factor() -> f32;
18 fn physicsworld_new() -> i64;
19}
20use crate::dora::IObject;
21use crate::dora::INode;
22impl INode for PhysicsWorld { }
23/// A struct that represents a physics world in the game.
24pub struct PhysicsWorld { raw: i64 }
25crate::dora_object!(PhysicsWorld);
26impl IPhysicsWorld for PhysicsWorld { }
27pub trait IPhysicsWorld: INode {
28 /// Queries the physics world for all bodies that intersect with the specified rectangle.
29 ///
30 /// # Arguments
31 ///
32 /// * `rect` - The rectangle to query for bodies.
33 /// * `handler` - A function that is called for each body found in the query. The function takes a `Body` as an argument and returns a `bool` indicating whether to continue querying for more bodies. Return `false` to continue, `true` to stop.
34 ///
35 /// # Returns
36 ///
37 /// * `bool` - Whether the query was interrupted. `true` means interrupted, `false` otherwise.
38 fn query(&mut self, rect: &crate::dora::Rect, mut handler: Box<dyn FnMut(&dyn crate::dora::IBody) -> bool>) -> bool {
39 let mut stack0 = crate::dora::CallStack::new();
40 let stack_raw0 = stack0.raw();
41 let func_id0 = crate::dora::push_function(Box::new(move || {
42 let result = handler(&stack0.pop_cast::<crate::dora::Body>().unwrap());
43 stack0.push_bool(result);
44 }));
45 unsafe { return physicsworld_query(self.raw(), rect.raw(), func_id0, stack_raw0) != 0; }
46 }
47 /// Casts a ray through the physics world and finds the first body that intersects with the ray.
48 ///
49 /// # Arguments
50 ///
51 /// * `start` - The starting point of the ray.
52 /// * `stop` - The ending point of the ray.
53 /// * `closest` - Whether to stop ray casting upon the closest body that intersects with the ray. Set `closest` to `true` to get a faster ray casting search.
54 /// * `handler` - A function that is called for each body found in the raycast. The function takes a `Body`, a `Vec2` representing the point where the ray intersects with the body, and a `Vec2` representing the normal vector at the point of intersection as arguments, and returns a `bool` indicating whether to continue casting the ray for more bodies. Return `false` to continue, `true` to stop.
55 ///
56 /// # Returns
57 ///
58 /// * `bool` - Whether the raycast was interrupted. `true` means interrupted, `false` otherwise.
59 fn raycast(&mut self, start: &crate::dora::Vec2, stop: &crate::dora::Vec2, closest: bool, mut handler: Box<dyn FnMut(&dyn crate::dora::IBody, &crate::dora::Vec2, &crate::dora::Vec2) -> bool>) -> bool {
60 let mut stack0 = crate::dora::CallStack::new();
61 let stack_raw0 = stack0.raw();
62 let func_id0 = crate::dora::push_function(Box::new(move || {
63 let result = handler(&stack0.pop_cast::<crate::dora::Body>().unwrap(), &stack0.pop_vec2().unwrap(), &stack0.pop_vec2().unwrap());
64 stack0.push_bool(result);
65 }));
66 unsafe { return physicsworld_raycast(self.raw(), start.into_i64(), stop.into_i64(), if closest { 1 } else { 0 }, func_id0, stack_raw0) != 0; }
67 }
68 /// Sets the number of velocity and position iterations to perform in the physics world.
69 ///
70 /// # Arguments
71 ///
72 /// * `velocity_iter` - The number of velocity iterations to perform.
73 /// * `position_iter` - The number of position iterations to perform.
74 fn set_iterations(&mut self, velocity_iter: i32, position_iter: i32) {
75 unsafe { physicsworld_set_iterations(self.raw(), velocity_iter, position_iter); }
76 }
77 /// Sets whether two physics groups should make contact with each other or not.
78 ///
79 /// # Arguments
80 ///
81 /// * `groupA` - The first physics group.
82 /// * `groupB` - The second physics group.
83 /// * `contact` - Whether the two groups should make contact with each other.
84 fn set_should_contact(&mut self, group_a: i32, group_b: i32, contact: bool) {
85 unsafe { physicsworld_set_should_contact(self.raw(), group_a, group_b, if contact { 1 } else { 0 }); }
86 }
87 /// Gets whether two physics groups should make contact with each other or not.
88 ///
89 /// # Arguments
90 ///
91 /// * `groupA` - The first physics group.
92 /// * `groupB` - The second physics group.
93 ///
94 /// # Returns
95 ///
96 /// * `bool` - Whether the two groups should make contact with each other.
97 fn get_should_contact(&mut self, group_a: i32, group_b: i32) -> bool {
98 unsafe { return physicsworld_get_should_contact(self.raw(), group_a, group_b) != 0; }
99 }
100}
101impl PhysicsWorld {
102 pub(crate) fn type_info() -> (i32, fn(i64) -> Option<Box<dyn IObject>>) {
103 (unsafe { physicsworld_type() }, |raw: i64| -> Option<Box<dyn IObject>> {
104 match raw {
105 0 => None,
106 _ => Some(Box::new(PhysicsWorld { raw: raw }))
107 }
108 })
109 }
110 /// Sets the factor used for converting physics engine meters value to pixel value.
111 /// Default 100.0 is a good value since the physics engine can well simulate real life objects
112 /// between 0.1 to 10 meters. Use value 100.0 we can simulate game objects
113 /// between 10 to 1000 pixels that suite most games.
114 /// You can change this value before any physics body creation.
115 pub fn set_scale_factor(val: f32) {
116 unsafe { physicsworld_set_scale_factor(val) };
117 }
118 /// Gets the factor used for converting physics engine meters value to pixel value.
119 /// Default 100.0 is a good value since the physics engine can well simulate real life objects
120 /// between 0.1 to 10 meters. Use value 100.0 we can simulate game objects
121 /// between 10 to 1000 pixels that suite most games.
122 /// You can change this value before any physics body creation.
123 pub fn get_scale_factor() -> f32 {
124 return unsafe { physicsworld_get_scale_factor() };
125 }
126 /// Creates a new `PhysicsWorld` object.
127 ///
128 /// # Returns
129 ///
130 /// * A new `PhysicsWorld` object.
131 pub fn new() -> PhysicsWorld {
132 unsafe { return PhysicsWorld { raw: physicsworld_new() }; }
133 }
134}