Interpolating sprites in update with physics in fixed_update

I’m putting together an interpolation script to track the difference between the accumulated physics (“fixed”) dt and the accumulated render dt - not sure if this is really going to work since it depends on some engine-level timings that I haven’t investigated. Figure I’ll just try it and see.

But of course first I searched to see what best practices are / which tools exist, and it looks like @aglitchman is working on a friendly interpolation component! I’m curious if this will come “out of the box,” be something I need to install, and when it’ll land. If there’s something in alpha/beta I could try right now, I’d prefer that over my homemade thing!

https://www.reddit.com/r/defold/comments/1ky9hwd/wip_new_component_for_interpolating_fixed_update/

Cheers

2 Likes

Available as a preview, but the API is already final and can be used with no concerns:

All that remains is to improve the documentation and perhaps come up with a better example (it’s more like a test now).

9 Likes

Beautiful & easy to integrate! Works perfectly; here’s a game running at 30 Hz on a 120 Hz display:

https://imgur.com/a/MuwirDj

A feature that would be nice is a mode (in addition to “None” and “Target Object”) called something like “Immediate” that makes the target object always match the uninterpolated position & rotation of the source object. Essentially, interpolation time t == 1. That would make interpolation easy to toggle on & off (vs “None”, where the visuals for your game object will just hang out statically without moving).

This actually helped me fix a bug - I’d set the physics tickrate to absurdly high (180Hz) to get smooth rendering on gaming monitors, and that high rate masked a tunneling issue in my physics code.

4 Likes

No problem—I’m happy to add anything that will simplify game development on the engine.

The question is, is it like the third mode in ‘Apply Transform’ or like a checkbox in ‘Target Object’ mode, or something else? I need to think about it and make the right decision right away, because this is my first component and I’m still struggling to figure out how to do migrations when there are significant changes in the component data format.

1 Like

Good thought - from this perspective, the feature I’m requesting is really to be able to customize the interpolation function used. Right now the only one available is lerp. A t==1 interpolation function might be called “immediate.” And of course one can also imagine others: bezier curves based on the most recent path points, springs, etc.

Okay!

It seems more likely that you want to use my component to achieve indirect parenting of game objects :eyes: Then it turns out that someone will need the fourth mode, ‘Clone Transform,’ which will simply copy the position/rotation/scale in before/after update, fixed update. Just kidding :grinning_face_with_smiling_eyes:

Hah! I think that is a viable use-case for the feature, similar to godot’s remote transform node, but it’s not really what I would use it for. I would like to be able to temporarily disable the interpolation (set t==1) so that I can test the game without interpolation masking any physics issues. It’s nice to be able to see the raw physics frames.

I like to, for instance, test a system at 20, 60, and 120 Hz to make sure it’s reasonably stable across those things (I don’t have tick-dependent physics) and also to detect & fix bugs like tunneling. Right now there’s no good way to turn off interpolation (since the sprite lives in a different game object).

Since this is for testing and you just need a global flag, maybe this option will work? It already exists:

  • object_interpolation.set_enabled(enabled) - Default is true, and when false, transformation will be applied to objects immediately as if you just copy position and rotation values from the source object to the target object.
  • object_interpolation.is_enabled() - Check if the enabled flag is set.

I would like to note that the component has a lower priority than all other engine components, and therefore, even with the set_enabled(false) flag, the position of the target object will lag exactly 1 frame (for 120hz this is 1/120 ms) from the position set in the last fixed update cycle (for example, if you enable physics debug view, you will notice this).

Or do you need separate control for each instance of the component?

Nice, that simple flag will work great for what I need, thanks!

I’m curious to learn more about the lower priority. With interpolation, one of the things you give up is immediacy, so the closer to the latest real physics state you can get, the better (especially for quick player input responses like “attack,” “dash,” “jump,” etc). It seems like the ideal priority for the component would be very high, so that it would run at the end when all the physics transformations have completed.

It seems so. But the interpolation component is designed with respect to the specifics of the engine’s game loop and the order of updates to the engine’s systems (components).

To describe it very simply, without taking proxy collections into account, the game loop in Defold is as follows:

  • input
  • update
  • fixed update (if any)
  • render

(repeat)

At each stage, each of the systems updates all instances of its components in for-loops, and not all systems do this in ‘update’ step and not all in the ‘fixed update’ step.

It is important that the camera component, its matrices, and so on are updated in the update step, so any changes to the position of an object with the camera component must in update step (this also applies to Lua scripts!). Changing the camera position in fixed update does not make much sense, since you will only see these changes in the next frame (this is why Defold game devs sometimes have jittering and do not understand why).

In order to avoid lag in 1 render frame in my component, the engine needs to either change the game loop (replacing the order: fixed update, then update), or add a late update step. I am a regular developer and work with what I have, which is why the component has this design.

PS A couple of years ago, during the release of Scene3D, I tried to do some hacks and workarounds, but then I ran into difficulties with the maintainability of such code and realised that I needed to accept the rules of the engine and work with what I had. And now, everything works great, and we started using my interpolation component in all of our games.

2 Likes

Thanks for filling in those details for me! The 1-frame-behind approach seems like a good compromise for simplicity / going with the grain of the engine.

Do you know of any discussions underway about the loop order? I’d lobby for:

  1. input
  2. (0-N) fixed update ticks
  3. update
  4. render

…since it aligns with how you’d typically implement a time accumulation buffer for a physics tick, the results of which are then reflected in the update & render (like in the classic “Fix Your Timestep!” article).

This might be a good note in the readme of your component. For instance, I have a “target camera” that follows a player, which was pointing at the physical player body. Once I integrated your component and split the visuals for the player into a separate game object, I noticed some subtle jitter. Then I realized that I needed to target the new sprite-holding game object, since its position and update cycle were now decoupled from the physical body.

1 Like

This is basically what I do too. I implemented a lua version of the interpolation a while back where I separate the visual and physical body. Then I update the camera which is targeting the visual body in a late update message. It’s been working pretty well, but it’s much easier to work with this component.

After digging into the update loop a little, I now understand why update() might proceed any fixed_update()s for the current frame: it’s the only way to notify the object that “a new frame is starting” which is necessary for certain setups. Then, the user can opt to self-post a message if they need a post-physics update.