interpolation.script 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. -- This example compares two render paths when physics runs in fixed timestep mode:
  2. -- 1) not_interpolated_block: visual representation copies physics representation transform directly
  3. local not_interpolated_block = {
  4. physics_go = "/block1",
  5. sprite_go = "/block1_sprite",
  6. }
  7. -- 2) interpolated_block: visual representation is interpolated between previous and current fixed states
  8. local interpolated_block = {
  9. physics_go = "/block2",
  10. sprite_go = "/block2_sprite",
  11. }
  12. -- Store fixed update interval in seconds from game.project Fixed Update Frequency.
  13. local fixed_dt = 1 / (sys.get_config_number("engine.fixed_update_frequency") or 20)
  14. function init(self)
  15. -- Render-time remainder inside the current fixed-step interval.
  16. self.render_accumulator = 0
  17. -- Two-sample buffer for interpolation:
  18. -- previous_* = transform from previous fixed update
  19. -- current_* = transform from current fixed update
  20. -- Initialize both from real physics representation state.
  21. self.previous_fixed_position = go.get_position(interpolated_block.physics_go)
  22. self.current_fixed_position = self.previous_fixed_position
  23. self.previous_fixed_rotation = go.get_rotation(interpolated_block.physics_go)
  24. self.current_fixed_rotation = self.previous_fixed_rotation
  25. end
  26. function fixed_update(self, dt)
  27. -- Shift the transform data from current state to previous state
  28. -- and sample new fixed state from the game object with the dynamic collision object component.
  29. self.previous_fixed_position = self.current_fixed_position
  30. self.previous_fixed_rotation = self.current_fixed_rotation
  31. self.current_fixed_position = go.get_position(interpolated_block.physics_go)
  32. self.current_fixed_rotation = go.get_rotation(interpolated_block.physics_go)
  33. end
  34. function update(self, dt)
  35. -------------------------------------------------------------------------------------
  36. -- For not interpolated object:
  37. -------------------------------------------------------------------------------------
  38. -- Copy physics transform directly to the visual representation.
  39. local not_interpolated_position = go.get_position(not_interpolated_block.physics_go)
  40. local not_interpolated_rotation = go.get_rotation(not_interpolated_block.physics_go)
  41. go.set_position(not_interpolated_position, not_interpolated_block.sprite_go)
  42. go.set_rotation(not_interpolated_rotation, not_interpolated_block.sprite_go)
  43. -------------------------------------------------------------------------------------
  44. -- For interpolated object:
  45. -------------------------------------------------------------------------------------
  46. -- Keep accumulator inside [0, fixed_dt) using modulo wrap.
  47. self.render_accumulator = math.fmod(self.render_accumulator + dt, fixed_dt)
  48. -- Base alpha from render progress between fixed samples:
  49. -- alpha=0 -> previous sample, alpha=1 -> current sample.
  50. local alpha = self.render_accumulator / fixed_dt
  51. -- Calculate the difference between the current and previous fixed positions.
  52. local position_difference = self.current_fixed_position - self.previous_fixed_position
  53. -- Position interpolation is linear (lerp).
  54. local interpolated_position = self.previous_fixed_position + position_difference * alpha
  55. -- Rotation interpolation is spherical (slerp).
  56. local interpolated_rotation = vmath.slerp(alpha, self.previous_fixed_rotation, self.current_fixed_rotation)
  57. -- Render blended transform.
  58. go.set_position(interpolated_position, interpolated_block.sprite_go)
  59. go.set_rotation(interpolated_rotation, interpolated_block.sprite_go)
  60. end