phaser icon indicating copy to clipboard operation
phaser copied to clipboard

When providing frames with duration to anims.create(), 41.6ms is added to every frame (1 frame time @24 FPS)

Open Nerodon opened this issue 1 year ago • 2 comments

Version

  • Phaser Version: 3.70.0
  • Operating system: Windows 11
  • Browser: Chrome and FF

Description

When providing durations in animations using an array of frames rather than total duration or FPS, the timing is generally slower than it should, sometimes by over several hundreds of ms or more. This is especially noticeable for quick and snappy animations making it impossible to define animation durations per frame this way.

This scales with the number of frames given to anims.create() EXAMPLE:

    this.anims.create({
            key: 'walk',
            frames: [
                { key: 'brawler', frame: 0, duration: 200 },
                { key: 'brawler', frame: 1, duration: 100 },
                { key: 'brawler', frame: 2, duration: 200 },
                { key: 'brawler', frame: 3, duration: 100 },
                ],
            repeat: 0
        });  

For each frame, the time is extended by 40ms. So a 10 frame animation will have a total runtime of about 400ms longer.

Example Test Code

EXAMPLE JsFiddle

Simply refresh, the time displayed on screen should match the total duration for all the frames. In the fiddle is should be 2400ms, but the animation completes in about 3000ms on Chrome or Firefox browser.

Nerodon avatar Jan 13 '24 22:01 Nerodon

I think it's related to the default framerate of 24 FPS and it adds 41.6 ms to each frame. Doing an animation with 1000 frames, duration 1ms per frame I get: 42646ms total remove 1000ms of actual animation and we get 41646ms or pretty close to 41.6ms per frame

Nerodon avatar Jan 14 '24 00:01 Nerodon

A quick look in the animationManager This seems to be fixed for Aseprite imports using createFromAseprite() We find there the following:

      // Fix duration to play nice with how the next tick is calculated.
      var msPerFrame = totalDuration / animFrames.length;

      animFrames.forEach(function (entry)
      {
          entry.duration -= msPerFrame;
      });

Applying this manually before calling create() solved the issue for me, but if durations are provided, I would expect the same behavior as createFromAseprite()

Nerodon avatar Jan 14 '24 01:01 Nerodon

I think that the description for Phaser.Types.Animations.AnimationFrame.duration is wrong and it should be like Phaser.Animations.AnimationFrame#duration.

samme avatar Jan 15 '24 17:01 samme

That is probably a fair point, but It would definitely be nice to set the msPerFrame to be 0 and all durations coming from the supplied frames. Afterall, this is basically required when importing animations from aseprite as the user specifies all frametimes manually, it's odd to not have a built-in way in Phaser to do the same.

Nerodon avatar Jan 16 '24 04:01 Nerodon

To keep it consistent, being that "fix" for Aesprite shouldn't be needed, msPerFrame is no longer added to duration.

Thank you for submitting this issue. We have fixed this and the fix has been pushed to the master branch. It will be part of the next release. If you get time to build and test it for yourself we would appreciate that.

rgk avatar Jan 26 '24 18:01 rgk

I think 2e4b43b is technically a breaking change, because AnimationFrame#duration did correctly describe Phaser's behavior.

samme avatar Jan 29 '24 21:01 samme

All the animations in my game are running faster after upgrading to 3.80. Could it be related to this ? What's the fix ?

sylvainpolletvillard avatar Feb 24 '24 12:02 sylvainpolletvillard

Only when applying a duration to a frame, as it no longer applies an additional msPerFrame, so the duration is the actual length of the frame.

To compare speed of animations you can use this example and change between versions: https://labs.phaser.io/view.html?src=src\animation\show%20animation%20play%20through.js

rgk avatar Feb 24 '24 13:02 rgk