@@ -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