Search code examples
animationopengl-eslibgdx

Position and rotate animations in Libgdx


I have 20 spites, I want them to be animated when a button is clicked. Two types of animations 1) Position 2) Rotation.

Is there a recommended way to do this? Only way I can think of is recursively call setposition and angle with a delta value on Render method till the desired position and angle are reached.


Solution

  • When you have a start state and an end state, and you want to fill in the middle states, this is known as 'tweening (from inbetween). It comes from cartoon animation, but has come to be used more generally.

    LibGDX makes use of Universal Tween Engine. You can start your journey to animating anything you want here. But, to give a bit more detail on how it works, here is an example from some of my own stuff. A similar usecase with regards to a sprite, but I have my sprites wrapped in a more generic class, a JJRenderNode. Here is how I make my class open to being tweened.

    First you need a TweenAccessor for the class you want to tween.

    public class RenderNodeTweenAccessor implements TweenAccessor<JJRenderNode> {
    
    
    public static final int WIDTH = 1;
    public static final int HEIGHT = 2;
    public static final int WIDTH_HEIGHT = 3;
    public static final int ALPHA = 4;
    public static final int ALPHA_WIDTH_HEIGHT=5;
    
    @Override
    public int getValues(JJRenderNode target, int tweenType, float[] returnValues) {
        switch (tweenType) {
            case WIDTH:
                returnValues[0] = target.getWidth();
                return 1;
            case HEIGHT:
                returnValues[0] = target.getHeight();
                return 1;
            case WIDTH_HEIGHT:
                returnValues[0] = target.getWidth();
                returnValues[1] = target.getHeight();
                return 2;
            case ALPHA:
                returnValues[0] = target.getColour().a;
                return 1;
            case ALPHA_WIDTH_HEIGHT:
                returnValues[0] = target.getColour().a;
                returnValues[1] = target.getWidth();
                returnValues[2] = target.getHeight();
                return 3;
            default:
                assert false;
                return -1;
        }
    }
    
    @Override
    public void setValues(JJRenderNode target, int tweenType, float[] newValues) {
        switch (tweenType) {
            case WIDTH:
                target.setWidth(newValues[0]);
                break;
            case HEIGHT:
                target.setHeight(newValues[0]);
                break;
            case WIDTH_HEIGHT:
                target.setWidth(newValues[0]);
                target.setHeight(newValues[1]);
                break;
            case ALPHA:
                target.getColour().a=newValues[0];
                break;
            case ALPHA_WIDTH_HEIGHT:
                target.getColour().a=newValues[0];
                target.setWidth(newValues[1]);
                target.setHeight(newValues[2]);
            default:
                break;
        }
    }
    }
    

    The constant ints and the 'tweenType' in each of the get and set methods let you tween more than one combination of fields. In this case I have different combinations of width, height and alpha values for my JJRenderNode.

    You have to register this TweenAccessor as follows:

    Tween.registerAccessor(JJRenderNode.class, new RenderNodeTweenAccessor());
    

    And then you are free to tween your class, for example:

    Timeline.createSequence()
                    .push(Tween.set(node, RenderNodeTweenAccessor.WIDTH_HEIGHT).target(START_WIDTH, START_WIDTH))
                    .push(Tween.to(node, RenderNodeTweenAccessor.WIDTH_HEIGHT, 0.4f).target(PuzzleBlockCore.MAX_RENDER_WIDTH, PuzzleBlockCore.MAX_RENDER_WIDTH))
                    .start(JJ.tweenManager);
    

    PS. You also need an instance of a TweenManger, and this needs to be updated with delta for each gameloop. I have a 'singleton' global instance that I use everywhere (JJ.TweenManager).