Skip to content

Commit c66de56

Browse files
committed
[add] apply_impulse implementation.
1 parent ee81252 commit c66de56

1 file changed

Lines changed: 127 additions & 13 deletions

File tree

crates/lambda-rs/src/physics/rigid_body_2d.rs

Lines changed: 127 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ impl RigidBody2D {
202202
///
203203
/// # Errors
204204
/// Returns `RigidBody2DError` if the input is invalid, the handle is
205-
/// invalid, belongs to a different world, or does not reference a live body.
205+
/// invalid, belongs to a different world, the operation is unsupported for
206+
/// the body type, or does not reference a live body.
206207
pub fn set_velocity(
207208
self,
208209
world: &mut PhysicsWorld2D,
@@ -233,7 +234,8 @@ impl RigidBody2D {
233234
///
234235
/// # Errors
235236
/// Returns `RigidBody2DError` if the input is invalid, the handle is
236-
/// invalid, belongs to a different world, or does not reference a live body.
237+
/// invalid, belongs to a different world, the operation is unsupported for
238+
/// the body type, or does not reference a live body.
237239
pub fn apply_force(
238240
self,
239241
world: &mut PhysicsWorld2D,
@@ -242,7 +244,14 @@ impl RigidBody2D {
242244
) -> Result<(), RigidBody2DError> {
243245
validate_force(fx, fy)?;
244246
self.validate_handle(world)?;
245-
return Err(RigidBody2DError::BodyNotFound);
247+
return world
248+
.backend
249+
.rigid_body_apply_force_2d(
250+
self.slot_index,
251+
self.slot_generation,
252+
[fx, fy],
253+
)
254+
.map_err(map_backend_error);
246255
}
247256

248257
/// Applies an impulse, in Newton-seconds, at the center of mass.
@@ -257,7 +266,8 @@ impl RigidBody2D {
257266
///
258267
/// # Errors
259268
/// Returns `RigidBody2DError` if the input is invalid, the handle is
260-
/// invalid, belongs to a different world, or does not reference a live body.
269+
/// invalid, belongs to a different world, the operation is unsupported for
270+
/// the body type, or does not reference a live body.
261271
pub fn apply_impulse(
262272
self,
263273
world: &mut PhysicsWorld2D,
@@ -266,7 +276,14 @@ impl RigidBody2D {
266276
) -> Result<(), RigidBody2DError> {
267277
validate_impulse(ix, iy)?;
268278
self.validate_handle(world)?;
269-
return Err(RigidBody2DError::BodyNotFound);
279+
return world
280+
.backend
281+
.rigid_body_apply_impulse_2d(
282+
self.slot_index,
283+
self.slot_generation,
284+
[ix, iy],
285+
)
286+
.map_err(map_backend_error);
270287
}
271288

272289
fn validate_handle(
@@ -737,14 +754,7 @@ mod tests {
737754
.build(&mut world)
738755
.unwrap();
739756

740-
world
741-
.backend
742-
.rigid_body_apply_force_2d(
743-
body.slot_index,
744-
body.slot_generation,
745-
[1.0, 0.0],
746-
)
747-
.unwrap();
757+
body.apply_force(&mut world, 1.0, 0.0).unwrap();
748758

749759
world.step();
750760
assert_eq!(body.position(&world).unwrap(), [0.75, 0.0]);
@@ -754,4 +764,108 @@ mod tests {
754764

755765
return;
756766
}
767+
768+
#[test]
769+
fn apply_force_accumulates_and_respects_dynamic_mass() {
770+
let mut world = PhysicsWorld2DBuilder::new()
771+
.with_gravity(0.0, 0.0)
772+
.with_timestep_seconds(1.0)
773+
.build()
774+
.unwrap();
775+
776+
let body = RigidBody2DBuilder::new(RigidBodyType::Dynamic)
777+
.with_dynamic_mass_kg(2.0)
778+
.build(&mut world)
779+
.unwrap();
780+
781+
body.apply_force(&mut world, 2.0, 0.0).unwrap();
782+
body.apply_force(&mut world, 2.0, 0.0).unwrap();
783+
784+
world.step();
785+
786+
assert_eq!(body.position(&world).unwrap(), [2.0, 0.0]);
787+
assert_eq!(body.velocity(&world).unwrap(), [2.0, 0.0]);
788+
789+
return;
790+
}
791+
792+
#[test]
793+
fn apply_impulse_updates_velocity_immediately_for_dynamic_bodies() {
794+
let mut world = PhysicsWorld2DBuilder::new()
795+
.with_gravity(0.0, 0.0)
796+
.with_timestep_seconds(1.0)
797+
.build()
798+
.unwrap();
799+
800+
let body = RigidBody2DBuilder::new(RigidBodyType::Dynamic)
801+
.with_dynamic_mass_kg(2.0)
802+
.build(&mut world)
803+
.unwrap();
804+
805+
body.apply_impulse(&mut world, 2.0, 0.0).unwrap();
806+
assert_eq!(body.velocity(&world).unwrap(), [1.0, 0.0]);
807+
808+
world.step();
809+
assert_eq!(body.position(&world).unwrap(), [1.0, 0.0]);
810+
811+
return;
812+
}
813+
814+
#[test]
815+
fn non_dynamic_apply_force_returns_unsupported_operation() {
816+
let mut world = PhysicsWorld2DBuilder::new().build().unwrap();
817+
818+
let static_body = RigidBody2DBuilder::new(RigidBodyType::Static)
819+
.build(&mut world)
820+
.unwrap();
821+
822+
assert_eq!(
823+
static_body.apply_force(&mut world, 1.0, 2.0),
824+
Err(RigidBody2DError::UnsupportedOperation {
825+
body_type: RigidBodyType::Static,
826+
})
827+
);
828+
829+
let kinematic_body = RigidBody2DBuilder::new(RigidBodyType::Kinematic)
830+
.build(&mut world)
831+
.unwrap();
832+
833+
assert_eq!(
834+
kinematic_body.apply_force(&mut world, 1.0, 2.0),
835+
Err(RigidBody2DError::UnsupportedOperation {
836+
body_type: RigidBodyType::Kinematic,
837+
})
838+
);
839+
840+
return;
841+
}
842+
843+
#[test]
844+
fn non_dynamic_apply_impulse_returns_unsupported_operation() {
845+
let mut world = PhysicsWorld2DBuilder::new().build().unwrap();
846+
847+
let static_body = RigidBody2DBuilder::new(RigidBodyType::Static)
848+
.build(&mut world)
849+
.unwrap();
850+
851+
assert_eq!(
852+
static_body.apply_impulse(&mut world, 1.0, 2.0),
853+
Err(RigidBody2DError::UnsupportedOperation {
854+
body_type: RigidBodyType::Static,
855+
})
856+
);
857+
858+
let kinematic_body = RigidBody2DBuilder::new(RigidBodyType::Kinematic)
859+
.build(&mut world)
860+
.unwrap();
861+
862+
assert_eq!(
863+
kinematic_body.apply_impulse(&mut world, 1.0, 2.0),
864+
Err(RigidBody2DError::UnsupportedOperation {
865+
body_type: RigidBodyType::Kinematic,
866+
})
867+
);
868+
869+
return;
870+
}
757871
}

0 commit comments

Comments
 (0)