Search code examples
javaanimationlibgdxspritescaling

LibGDX - scaling animations


Another day, another problem.

I'm trying to make an animation from TextureRegions, but I need to scale it by some value. I have no problems with scaling still images(sprites made from texture regions) but, I have no idea why, it doesn't work with animation frames.

With still images I do something like that:

    darknessActive = new Sprite(AssetLoaderUI.darknessActive);
    darknessActive.setPosition(50, 20);
    darknessActive.setScale(scaler);

And then I render it in renderer just fine.

With animation I try to do something like this:

    Frame1 = new TextureRegion(texture, 764, 75, 141, -74);
    Frame2 = new TextureRegion(texture, 907, 75, 133, -75);

    Frame1S = new Sprite(Frame1);
    Frame1S.setScale(scaler);
    Frame2S = new Sprite(Frame2);
    Frame2S.setScale(scaler);

    Sprite[] Frames = { Frame1S, Frame2S };

    myAnimation = new Animation(0.06f, Frames);
    myAnimation.setPlayMode(Animation.PlayMode.LOOP);

but the image is still in the original size, "scaler" didn't make any difference.


Solution

  • 2018 Edit: In newer versions of LibGDX, the Animation class isn't limited to TextureRegions. It can animate any generic array of objects, so you could create an Animation<Sprite>, although you'd need to be sure you applied the appropriate scale each time you get a key frame sprite. Personally, I think the Sprite class should be avoided because it conflates a resource (the image) with game state.


    You didn't say how you're drawing the animation, but presumably you are using a method that is unaware of the sprite scales.

    Since the Animation class stores TextureRegions, if you get a frame from the animation to draw like this:

    spriteBatch.draw(animation.getKeyFrame(time), x, y);
    

    then the sprite batch doesn't know it's an instance of Sprite, only that it's an instance of TextureRegion, which doesn't include scaling information.

    One way quick and dirty way to do it is like this:

    Sprite sprite = (Sprite)animation.getKeyFrame(time));
    spriteBatch.draw(sprite, x, y, 0, 0, sprite.width, sprite.height, sprite.scaleX, sprite.scaleY, 0);
    

    But if you want an animation that behaves sort of like a sprite, you can subclass it to give it to store scaling data (and if you like, rotation and position as well) and to draw itself. And then you don't have to worry about Sprite instances at all.

    For example:

    public class SpriteAnimation extends Animation {
    
        float scaleX = 1;
        float scaleY = 1;
    
        /*...duplicate and call through to super constructors here...*/
    
        public void setScaling(float scale){
            scaleX = scale;
            scaleY = scale;
        }
    
        public void draw (float stateTime, Batch batch, float x, float y) {
            TextureRegion region = getKeyFrame(stateTime);
            batch.draw(region, x, y, region.width*scaleX, region.height*scaleY);
        }
    }
    

    You can customize this as you like to store x and y, rotation, origin, etc like a sprite if you like. When you create it, you wouldn't use the Sprite class at all. You would do something like this.

    frame1 = new TextureRegion(texture, 764, 75, 141, -74);
    frame2 = new TextureRegion(texture, 907, 75, 133, -75);
    
    TextureRegion[] frames = { frame1, frame2 };
    
    mySpriteAnimation = new SpriteAnimation(0.06f, frames);
    mySpriteAnimation.setScaling(scaler);
    mySpriteAnimation.setPlayMode(Animation.PlayMode.LOOP);