One way to achieve this could be to extend the existing Button
class and provide an implementation that sets the up
, down
, checked
and disabled
Drawable
s of the ButtonStyle
to whatever the last key-frame of the animation loaded is.
That way you'd get standard button behavior and the only thing that changes is the (somewhat weird) continuously updating style.
Such a Button
might look something like this;
package com.bornander.sandbox;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
public class AnimatedButton extends Button {
private float elapsed;
// Technically you'll need one of these for each state of the ButtonStyle, but I'll just cover up and down here.
private final Animation<TextureRegion> upAnimation;
private final Animation<TextureRegion> downAnimation;
private final ButtonStyle overrideStyle = new ButtonStyle();
private final TextureRegionDrawable upDrawable = new TextureRegionDrawable();
private final TextureRegionDrawable downDrawable = new TextureRegionDrawable();
public AnimatedButton(Animation<TextureRegion> upAnimation, Animation<TextureRegion> downAnimation) {
this.upAnimation = upAnimation;
this.downAnimation = downAnimation;
}
@Override
public void act(float delta) {
super.act(delta);
elapsed += delta;
upDrawable.setRegion(upAnimation.getKeyFrame(elapsed));
downDrawable.setRegion(downAnimation.getKeyFrame(elapsed));
overrideStyle.up = upDrawable;
overrideStyle.down = downDrawable;
setStyle(overrideStyle);
}
}
And it would be instantiated with a list of animations (possibly created using a GifDecoder
) for each state. Then it is possible to add listeners for clicked just like any other button owned by a Stage
;
package com.bornander.sandbox;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.holidaystudios.tools.GifDecoder;
public class SandboxGame extends ApplicationAdapter {
Stage stage;
@Override
public void create () {
stage = new Stage(new ScreenViewport());
Animation<TextureRegion> upAnimation = GifDecoder.loadGIFAnimation(Animation.PlayMode.LOOP, Gdx.files.internal("throbber.gif").read());
Animation<TextureRegion> downAnimation = GifDecoder.loadGIFAnimation(Animation.PlayMode.LOOP, Gdx.files.internal("throbber.gif").read());
// Instanciate an AnimatedButton, providing animations for up and down states
Button button = new AnimatedButton(upAnimation, downAnimation);
button.setPosition(100, 100);
button.setSize(32, 32);
// Here the click listener is added by passing an anonymous type
button.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
super.clicked(event, x, y);
//Add click handler here!
}
});
// Add the button to the Stage
stage.addActor(button);
// And set the processor of input to be that stage
Gdx.input.setInputProcessor(stage);
}
@Override
public void render () {
// Make sure to update the state of the stage
stage.act(Gdx.graphics.getDeltaTime());
Gdx.gl.glClearColor(1, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Draw the state of the stage
stage.draw();
}
@Override
public void dispose () {
}
}