@@ -443,28 +443,29 @@ test('synchronizes a character world position changed through its parent', async
443443 expect ( state . position . isEqual ( Vector3 . fromCopy3 ( 5 , 2 , - 3 ) ) ) . toBe ( true ) ;
444444} ) ;
445445
446- test ( 'moves once per frame, reports initial grounding without landing , and synchronizes the entity' , async ( ) => {
446+ test ( 'uses the world-clamped timestep, moves once per frame , and synchronizes the entity' , async ( ) => {
447447 await RapierPhysicsStrategy . initialize ( fakeRapier ( ) ) ;
448448 const { entity, state } = fakeEntity ( ) ;
449449 const strategy = new RapierCharacterControllerStrategy ( ) ;
450450 strategy . setup ( entity , capsuleShape ( ) , { maxDeltaTime : 1 } ) ;
451451 strategy . setDesiredHorizontalVelocity ( Vector3 . fromCopy3 ( 2 , 99 , - 1 ) ) ;
452+ const timestep = 1 / 15 ;
452453
453454 RapierPhysicsStrategy . update ( 1 , 0.5 ) ;
454455 RapierPhysicsStrategy . update ( 1 , 0.5 ) ;
455456
456457 expect ( world . stepCount ) . toBe ( 1 ) ;
457458 expect ( strategy . isGrounded ) . toBe ( true ) ;
458- expect ( state . position . x ) . toBeCloseTo ( 1 ) ;
459- expect ( state . position . z ) . toBeCloseTo ( - 0.5 ) ;
459+ expect ( state . position . x ) . toBeCloseTo ( 2 * timestep ) ;
460+ expect ( state . position . z ) . toBeCloseTo ( - timestep ) ;
460461 expect ( strategy . motionState . state ) . toBe ( 'grounded' ) ;
461462 expect ( strategy . motionState . horizontalSpeed ) . toBeCloseTo ( Math . hypot ( 2 , 1 ) ) ;
462- expect ( strategy . motionState . groundedDuration ) . toBeCloseTo ( 0.5 ) ;
463+ expect ( strategy . motionState . groundedDuration ) . toBeCloseTo ( timestep ) ;
463464 expect ( strategy . motionState . landingImpactSpeed ) . toBe ( 0 ) ;
464465
465466 RapierPhysicsStrategy . update ( 2 , 0.5 ) ;
466467 expect ( strategy . motionState . state ) . toBe ( 'grounded' ) ;
467- expect ( strategy . motionState . groundedDuration ) . toBeCloseTo ( 1 ) ;
468+ expect ( strategy . motionState . groundedDuration ) . toBeCloseTo ( timestep * 2 ) ;
468469 expect ( strategy . motionState . landingImpactSpeed ) . toBe ( 0 ) ;
469470} ) ;
470471
@@ -473,13 +474,14 @@ test('does not report landing while settling onto the initial ground', async ()
473474 const { entity } = fakeEntity ( ) ;
474475 const strategy = new RapierCharacterControllerStrategy ( ) ;
475476 strategy . setup ( entity , capsuleShape ( ) , { maxDeltaTime : 1 , gravity : 10 } ) ;
477+ const timestep = 1 / 15 ;
476478
477479 world . controller ! . forceAirborne = true ;
478- RapierPhysicsStrategy . update ( 1 , 0.1 ) ;
480+ RapierPhysicsStrategy . update ( 1 , timestep ) ;
479481 expect ( strategy . motionState . state ) . toBe ( 'falling' ) ;
480482
481483 world . controller ! . forceAirborne = false ;
482- RapierPhysicsStrategy . update ( 2 , 0.1 ) ;
484+ RapierPhysicsStrategy . update ( 2 , timestep ) ;
483485
484486 expect ( strategy . motionState . state ) . toBe ( 'grounded' ) ;
485487 expect ( strategy . motionState . landingImpactSpeed ) . toBe ( 0 ) ;
@@ -490,16 +492,19 @@ test('reports landing after a real airborne movement', async () => {
490492 const { entity } = fakeEntity ( ) ;
491493 const strategy = new RapierCharacterControllerStrategy ( ) ;
492494 strategy . setup ( entity , capsuleShape ( ) , { maxDeltaTime : 1 , gravity : 10 , jumpSpeed : 1.5 } ) ;
495+ const timestep = 1 / 15 ;
493496
494- RapierPhysicsStrategy . update ( 1 , 0.1 ) ;
497+ RapierPhysicsStrategy . update ( 1 , timestep ) ;
495498 expect ( strategy . motionState . state ) . toBe ( 'grounded' ) ;
496499
497500 strategy . requestJump ( ) ;
498- RapierPhysicsStrategy . update ( 2 , 0.1 ) ;
501+ RapierPhysicsStrategy . update ( 2 , timestep ) ;
499502 expect ( strategy . motionState . state ) . toBe ( 'rising' ) ;
500- RapierPhysicsStrategy . update ( 3 , 0.1 ) ;
503+ RapierPhysicsStrategy . update ( 3 , timestep ) ;
501504 expect ( strategy . motionState . state ) . toBe ( 'rising' ) ;
502- RapierPhysicsStrategy . update ( 4 , 0.1 ) ;
505+ RapierPhysicsStrategy . update ( 4 , timestep ) ;
506+ expect ( strategy . motionState . state ) . toBe ( 'rising' ) ;
507+ RapierPhysicsStrategy . update ( 5 , timestep ) ;
503508
504509 expect ( strategy . motionState . state ) . toBe ( 'landing' ) ;
505510 expect ( strategy . motionState . landingImpactSpeed ) . toBeCloseTo ( 0.5 ) ;
@@ -510,15 +515,16 @@ test('jumps only after grounding and releases Rapier resources', async () => {
510515 const { entity, state } = fakeEntity ( ) ;
511516 const strategy = new RapierCharacterControllerStrategy ( ) ;
512517 strategy . setup ( entity , capsuleShape ( ) , { maxDeltaTime : 1 , gravity : 10 , jumpSpeed : 4 } ) ;
513- RapierPhysicsStrategy . update ( 1 , 0.1 ) ;
518+ const timestep = 1 / 15 ;
519+ RapierPhysicsStrategy . update ( 1 , timestep ) ;
514520
515521 strategy . requestJump ( ) ;
516- RapierPhysicsStrategy . update ( 2 , 0.1 ) ;
517- expect ( state . position . y ) . toBeCloseTo ( 0.4 ) ;
522+ RapierPhysicsStrategy . update ( 2 , timestep ) ;
523+ expect ( state . position . y ) . toBeCloseTo ( 4 * timestep ) ;
518524 expect ( strategy . isGrounded ) . toBe ( false ) ;
519525 expect ( strategy . motionState . state ) . toBe ( 'rising' ) ;
520526 expect ( strategy . motionState . verticalSpeed ) . toBeCloseTo ( 4 ) ;
521- expect ( strategy . motionState . airborneDuration ) . toBeCloseTo ( 0.1 ) ;
527+ expect ( strategy . motionState . airborneDuration ) . toBeCloseTo ( timestep ) ;
522528
523529 strategy . teleport ( Vector3 . fromCopy3 ( 3 , 2 , 1 ) ) ;
524530 expect ( state . position . isEqual ( Vector3 . fromCopy3 ( 3 , 2 , 1 ) ) ) . toBe ( true ) ;
0 commit comments