Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First frame takes on appearance of second frame in Spritesheets created from trimmed Texture Atlas Frames #4088

Closed
Cirras opened this issue Oct 4, 2018 · 1 comment

Comments

@Cirras
Copy link
Contributor

Cirras commented Oct 4, 2018

Version

  • Phaser Version: v3.14.0-FB
  • Operating system: Windows 10
  • Browser: Not applicable

Description

In SpriteSheets created from a texture atlas with TextureManager.addSpriteSheetFromAtlas(), the first frame becomes identical to the second frame. In all usage, including animations, the first frame will appear as the second frame instead.

Example Test Code

The following code is pulled directly from the following Phaser 3 Example. I have modified all the animation configurations to only use the first 2 frames in order to demonstrate that the animations derived from the trimmed texture atlases will appear to "freeze" because both frames are identical due to this bug, while their untrimmed counterparts will rapidly display the first 2 frames as expected.

var config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

function preload ()
{
    this.load.path = 'http://labs.phaser.io/assets/atlas/trimsheet/';

    this.load.atlas('testanims', 'trimsheet.png', 'trimsheet.json');
}

function create ()
{
    var t1 = this.textures.addSpriteSheetFromAtlas(
        'boom1',
        {
            atlas: 'testanims',
            frame: 'explosion-notrim',
            frameWidth: 64,
            frameHeight: 64,
            endFrame: 23
        });


    var t2 = this.textures.addSpriteSheetFromAtlas(
        'boom2',
        {
            atlas: 'testanims',
            frame: 'explosion',
            frameWidth: 64,
            frameHeight: 64,
            endFrame: 23
        });

    var b1 = this.textures.addSpriteSheetFromAtlas(
        'bubble1',
        {
            atlas: 'testanims',
            frame: 'bubble-notrim',
            frameWidth: 34,
            frameHeight: 68
        });


    var b2 = this.textures.addSpriteSheetFromAtlas(
        'bubble2',
        {
            atlas: 'testanims',
            frame: 'bubble',
            frameWidth: 34,
            frameHeight: 68
        });

    var config1 = {
        key: 'explode1',
        frames: this.anims.generateFrameNumbers('boom1', { start: 0, end: 1 }),
        frameRate: 20,
        repeat: -1
    };

    var config2 = {
        key: 'explode2',
        frames: this.anims.generateFrameNumbers('boom2', { start: 0, end: 1 }),
        frameRate: 20,
        repeat: -1
    };

    var config3 = {
        key: 'bobble1',
        frames: this.anims.generateFrameNumbers('bubble1', { start: 0, end: 1 }),
        frameRate: 10,
        repeat: -1
    };

    var config4 = {
        key: 'bobble2',
        frames: this.anims.generateFrameNumbers('bubble2', { start: 0, end: 1 }),
        frameRate: 10,
        repeat: -1
    };

    this.anims.create(config1);
    this.anims.create(config2);
    this.anims.create(config3);
    this.anims.create(config4);

    this.add.sprite(300, 200).play('explode1');
    this.add.sprite(400, 200).play('explode2');

    this.add.sprite(300, 400).play('bobble1');
    this.add.sprite(400, 400).play('bobble2');
}

Additional Information

I have identified the cause of problem.
For untrimmed texture atlas frames, Parser.SpriteSheet() is used to create the SpriteSheet. This function adds a __BASE texture source entry.
However, for trimmed texture atlases texture atlases, Parser.SpriteSheetFromAtlas() is used, and this function does not add a __BASE texture source entry. This impacts how the texture is handled in Texture.get().

In Texture.get(), there is a check:

  //  null, undefined, empty string, zero
  if (!name)
  {
      name = this.firstFrame;
  }

If a number 0 is passed to this function, this normally would not be a problem for a SpriteSheet because its firstFrame is frame 0 anyway, and everything continues on as expected. However, in the case of a SpriteSheet without a __BASE texture source entry, the firstFrame ends up being the second frame instead due to the following code in Texture.add():

 //  Set the first frame of the Texture (other than __BASE)
  //  This is used to ensure we don't spam the display with entire
  //  atlases of sprite sheets, but instead just the first frame of them
  //  should the dev incorrectly specify the frame index
  if (this.frameTotal === 1)
  {
      this.firstFrame = name;
  }

Therefore the returned firstFrame is in fact the second frame.

I'm going to open a PR with a minimalist fix. The fix for this particular bug should be as simple as modifying the above check to handle the case where a __BASE texture does not exist.
That being said, it may be worth also having a look at why a __BASE texture entry isn't added in Parser.SpriteSheetFromAtlas() in the first place.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

photonstorm added a commit that referenced this issue Apr 8, 2019
Make Texture.add() firstFrame check more explicit (Fix issue #4088)
@photonstorm
Copy link
Collaborator

Thanks for opening this issue, and for submitting a PR to fix it. We have merged your PR into the master branch and attributed the work to you in the Change Log. If you need to tweak the code for whatever reason please submit a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants