Skip to main content

gizmo_scripting/
api_physics.rs

1//! Physics API — Lua'ya sunulan fizik sistemi fonksiyonları
2//!
3//! Kuvvet uygulama, raycast ve yerçekimi ayarı gibi işlemler için kullanılır.
4
5use crate::commands::{CommandQueue, ScriptCommand};
6use gizmo_math::Vec3;
7use mlua::prelude::*;
8use std::sync::Arc;
9
10/// Physics API fonksiyonlarını Lua'ya kaydeder
11pub fn register_physics_api(lua: &Lua, command_queue: Arc<CommandQueue>) -> Result<(), LuaError> {
12    let physics_table = lua.create_table()?;
13
14    // === KUVVET UYGULA ===
15    {
16        let cq = command_queue.clone();
17        physics_table.set(
18            "apply_force",
19            lua.create_function(move |_, (id, fx, fy, fz): (u32, f32, f32, f32)| {
20                cq.push(ScriptCommand::ApplyForce(id, Vec3::new(fx, fy, fz)));
21                Ok(())
22            })?,
23        )?;
24    }
25
26    // === İMPULS UYGULA ===
27    {
28        let cq = command_queue.clone();
29        physics_table.set(
30            "apply_impulse",
31            lua.create_function(move |_, (id, ix, iy, iz): (u32, f32, f32, f32)| {
32                cq.push(ScriptCommand::ApplyImpulse(id, Vec3::new(ix, iy, iz)));
33                Ok(())
34            })?,
35        )?;
36    }
37
38    // === RIGIDBODY EKLE ===
39    {
40        let cq = command_queue.clone();
41        physics_table.set(
42            "add_rigidbody",
43            lua.create_function(
44                move |_,
45                      (id, mass, restitution, friction, use_gravity): (
46                    u32,
47                    f32,
48                    f32,
49                    f32,
50                    bool,
51                )| {
52                    cq.push(ScriptCommand::AddRigidBody {
53                        id,
54                        mass,
55                        restitution,
56                        friction,
57                        use_gravity,
58                    });
59                    Ok(())
60                },
61            )?,
62        )?;
63    }
64
65    // === COLLIDER EKLE ===
66    {
67        let cq = command_queue.clone();
68        physics_table.set(
69            "add_box_collider",
70            lua.create_function(move |_, (id, hx, hy, hz): (u32, f32, f32, f32)| {
71                cq.push(ScriptCommand::AddBoxCollider { id, hx, hy, hz });
72                Ok(())
73            })?,
74        )?;
75    }
76
77    {
78        let cq = command_queue.clone();
79        physics_table.set(
80            "add_sphere_collider",
81            lua.create_function(move |_, (id, radius): (u32, f32)| {
82                cq.push(ScriptCommand::AddSphereCollider { id, radius });
83                Ok(())
84            })?,
85        )?;
86    }
87
88    lua.globals().set("physics", physics_table)?;
89
90    Ok(())
91}
92
93/// Her frame güncel fizik olaylarını (Tetikleyiciler, Çarpışmalar) Lua'ya aktarır
94pub fn update_physics_api(
95    lua: &Lua,
96    world: &gizmo_core::World,
97) -> Result<(), LuaError> {
98    let physics_table: LuaTable = lua.globals().get("physics")?;
99    
100    let triggers = lua.create_table()?;
101    let collisions = lua.create_table()?;
102    
103    if let Ok(physics_world) = world.try_get_resource::<gizmo_physics_rigid::world::PhysicsWorld>() {
104        // Trigger (Tetikleyici) Olayları
105        for (i, t_event) in physics_world.trigger_events().iter().enumerate() {
106            let ev = lua.create_table()?;
107            ev.set("trigger_id", t_event.trigger_entity.id())?;
108            ev.set("other_id", t_event.other_entity.id())?;
109            let status = match t_event.event_type {
110                gizmo_physics_core::collision::CollisionEventType::Started => "enter",
111                gizmo_physics_core::collision::CollisionEventType::Persisting => "stay",
112                gizmo_physics_core::collision::CollisionEventType::Ended => "exit",
113            };
114            ev.set("status", status)?;
115            triggers.set(i + 1, ev)?;
116        }
117        
118        // Fiziksel Çarpışma Olayları
119        for (i, c_event) in physics_world.collision_events().iter().enumerate() {
120            let ev = lua.create_table()?;
121            ev.set("entity_a", c_event.entity_a.id())?;
122            ev.set("entity_b", c_event.entity_b.id())?;
123            let status = match c_event.event_type {
124                gizmo_physics_core::collision::CollisionEventType::Started => "enter",
125                gizmo_physics_core::collision::CollisionEventType::Persisting => "stay",
126                gizmo_physics_core::collision::CollisionEventType::Ended => "exit",
127            };
128            ev.set("status", status)?;
129            collisions.set(i + 1, ev)?;
130        }
131    }
132    
133    // Her frame listeleri güncelle
134    physics_table.set("triggers", triggers)?;
135    physics_table.set("collisions", collisions)?;
136    
137    Ok(())
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use gizmo_core::World;
144    use gizmo_physics_rigid::world::PhysicsWorld;
145    use gizmo_physics_core::collision::{TriggerEvent, CollisionEvent, CollisionEventType};
146    use mlua::Lua;
147
148    #[test]
149    fn test_update_physics_api() {
150        let lua = Lua::new();
151        let globals = lua.globals();
152        
153        // build_physics_api initializes the `physics` global table
154        let physics_table = lua.create_table().unwrap();
155        globals.set("physics", physics_table).unwrap();
156
157        let mut world = World::new();
158        let ent1 = world.spawn();
159        let ent2 = world.spawn();
160
161        let mut physics_world = PhysicsWorld::new();
162        physics_world.trigger_events.push(TriggerEvent {
163            trigger_entity: ent1,
164            other_entity: ent2,
165            event_type: CollisionEventType::Started,
166        });
167
168        physics_world.collision_events.push(CollisionEvent {
169            entity_a: ent1,
170            entity_b: ent2,
171            event_type: CollisionEventType::Started,
172            contact_points: Default::default(),
173        });
174
175        world.insert_resource(physics_world);
176
177        update_physics_api(&lua, &world).unwrap();
178
179        let script = r#"
180            local triggers = physics.triggers
181            local collisions = physics.collisions
182            assert(#triggers == 1)
183            assert(triggers[1].status == "enter")
184            assert(#collisions == 1)
185            assert(collisions[1].status == "enter")
186        "#;
187
188        lua.load(script).exec().unwrap();
189    }
190}