Madmenyo
Madmenyo

Reputation: 8584

Animation offset for multiple animations

I am using TexturepackgerGUI to pack multiple animations into a spritesheet. I generate these animations with Spriter. TexturepackerGUI comes with a handy feature that outputs a offset field that can be used to offset the animation so the sprite does not move from left to right when it's larger.

But what about multiple animations? When I move from my walk animation to idle or run it still shifts position because these frames use much larger sprites since I moved and rotated my parts much more in Spriter.

One way to fix this is to output a fixed size in Spriter, but this will waste a ton of texture space since I have to use a rectangle size of the largest sprite.

This is how my pack/atlas file looks:

idle_cycle_heavy
  rotate: false
  xy: 1602, 2
  size: 78, 95
  orig: 124, 121
  offset: 3, 20
  index: 20
idle_cycle_heavy
  rotate: false
  xy: 1682, 2
  size: 78, 95
  orig: 124, 121
  offset: 3, 20
  index: 21
//...
run_cycle_heavy
  rotate: false
  xy: 162, 507
  size: 78, 95
  orig: 116, 113
  offset: 22, 11
  index: 25
run_cycle_heavy
  rotate: false
  xy: 1636, 406
  size: 78, 97
  orig: 116, 113
  offset: 23, 13
  index: 18
//...

And here I use the offset to draw.

public void draw(SpriteBatch batch) {
    TextureRegion currentFrame = getCurrentFrame();
    if (currentFrame == null) Gdx.app.log("Unit.java", "Could not find proper frame.");

    int posX = Math.round(((TextureAtlas.AtlasRegion) currentFrame).offsetX);
    int posY = Math.round(((TextureAtlas.AtlasRegion) currentFrame).offsetY);

    batch.draw(currentFrame, posX, posY);
}

/**
 * Gets the texture region of the current frame taking the unit state into account
 * @return the current TextureRegion
 */
private TextureRegion getCurrentFrame()
{
    frameTime += Gdx.graphics.getDeltaTime();

    if (unitState.equals(UnitState.Idle))
    {
        return idleAnimation.getKeyFrame(frameTime);
    }
    else if (unitState.equals(UnitState.Walking))
    {
        return walkAnimation.getKeyFrame(frameTime);
    }
    else if (unitState.equals(UnitState.Running))
    {
        return runAnimation.getKeyFrame(frameTime);
    }
    else if (unitState.equals(UnitState.Shooting))
    {
        return shootAnimation.getKeyFrame(frameTime);
    }
    return null;
}

I'm kinda hoping there is a option in TexturePackerGui that allows me to set the offset based on the largest image.

Upvotes: 1

Views: 415

Answers (1)

Madmenyo
Madmenyo

Reputation: 8584

After another hour of fiddling with Spriter and TexturePacker I found a solution. The core of the problem lies in Spriter. Spriter is able to export an animation with a rectangle size based on the largest frame in the animation currently exporting. Sadly it is not able to do this for all animations of a entity, which they really should add.

A quick fix is to create a custom rectangle when exporting and make this one huge so your frames won't get cut off. Then export each animation with this rectangle size. TexturePackerGUI has the option to trim whitespace and based on that number it will provide a offset. Since all the original frames where in the correct place within the initial rectangle/image this fixed the problem. I now have a tightly packed spritesheet.

I would really like to see a feature for Spriter that would actually do this automatically. It provides the option for this on the animation currently exporting but that is useless for anyone that wants to export/create multiple animations. Another option that Spriter offers is to set animation export box size and here you are allowed to clone it to all other entities/animations. The problem here is that most of the time you don't know what the largest frame is and have to look up the frame with the largest sprite too otherwise the larger frames will be cut off. This is why I just exported my frames as 512x512 images so I made sure they all fit. This wastes a lot of space if you keep the images but they can be deleted and easily generated when needed again.

Upvotes: 1

Related Questions