Reputation: 8584
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
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