0
\$\begingroup\$

I am a complete newbie, making an app in libgdx for which I have this actor that I want to animate on button click. Here is the code for that:

public class Boss extends Actor {
    protected Animation animation = null;
    private float stateTime = 0;
    private float width, height;
    private Texture bossTexture;
    private boolean acting, reset;

    public Boss(Animation animation) {
        bossTexture=new Texture("calm.png");
        width=Gdx.graphics.getWidth();
        height=Gdx.graphics.getHeight();
        acting=false;
        this.animation = animation;
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        batch.draw(bossTexture, 200, 100);
        if(acting!=false) {
            TextureRegion currentFrame = animation.getKeyFrame(stateTime);
            batch.draw(currentFrame, 200, 100);
            acting=false;
        }
        if(reset==true){
            batch.draw(bossTexture, 200, 100);
        }
    }

    @Override
    public void act(float delta)
    {
        super.act(delta);
        if(PlayScreen.slapped==true){
            acting=true;
        }
        stateTime+=delta;
    }

    public void reset()
    {
        reset=true;
        stateTime = 0;
    }
}

This is the workaround I have for resetting the actor to the default state, but I'm sure there must be another better way. Any suggestions?

**UPDATE : **

I am trying this now. package com.storm.game;

public class Boss extends Actor {
protected Animation animation = null;
private float stateTime = 0;
private float width, height;
private Texture bossTexture;
private boolean slapping, reset, react;
TextureRegion currentFrame;

public Boss(Animation animation) {
    bossTexture=new Texture("calm.png");
    width=Gdx.graphics.getWidth();
    height=Gdx.graphics.getHeight();
    slapping=react=reset=false;
    this.animation = animation;
    currentFrame = animation.getKeyFrame(0);
}

public void setAnimation(Animation anim){
    this.animation=anim;
}

@Override
public void draw(Batch batch, float parentAlpha) {
    if(slapping) {
        currentFrame=animation.getKeyFrame(stateTime);
        batch.draw(currentFrame, 200, 100);
        slapping=false;
        //react();
    }
    else{
        batch.draw(currentFrame, 200, 100);
    }
    if(reset){
        currentFrame=animation.getKeyFrame(0);
        batch.draw(currentFrame, 200, 100);
    }
}

@Override
public void act(float delta)
{
    super.act(delta);
    slapping=PlayScreen.slapped;
    stateTime+=delta;
}

public void reset()
{
    reset=true;
    stateTime = 0;
}

}

And what happens is the first frame is drawn and that frame is on the top of every other frame that is drawn in the Slapping condition.

Which is why, i get a glitched animation showing first frame overlaying every other frame i draw.

This is the playscreen class fom where i draw this actor on screen

public class PlayScreen implements Screen{

public static boolean slapped, punched;

//init variables
Punish game;

//others
Stage buttonStage;
Sprite bossSprite, backgroundSprite;
Texture bossTexture, backgroundTexture;
TextureRegion bossRegion;
Table buttonTable;
ImageButton slapButton, punchButton;
ImageButton.ImageButtonStyle slapButtonStyle, punchButtonStyle;
TextureAtlas slapButtonAtlas, bossSlapAtlas, punchButtonAtlas, bossPunchAtlas;
Skin slapSkin, punchSkin;
Animation bossSlapAnimation, bossPunchAnimation;
Boss boss;

public PlayScreen(Punish game){
    slapped=punched=false;

    this.game=game;
    buttonStage =new Stage();
    buttonTable=new Table();

    backgroundTexture=new Texture("background.jpg");
    bossTexture=new Texture("calm.png");
    backgroundSprite=new Sprite(backgroundTexture);

    slapButtonAtlas=new TextureAtlas(Gdx.files.internal("button.pack"));
    punchButtonAtlas=new TextureAtlas(Gdx.files.internal("punchButton.atlas"));
    bossSlapAtlas=new TextureAtlas(Gdx.files.internal("boss.pack"));
    bossPunchAtlas=new TextureAtlas(Gdx.files.internal("punchAnimation.pack"));

    slapSkin=new Skin();
    punchSkin=new Skin();

    //make buttons
    slapSkin.addRegions(slapButtonAtlas);
    punchSkin.addRegions(punchButtonAtlas);

    //adding style to slap button
    slapButtonStyle=new ImageButton.ImageButtonStyle();
    slapButtonStyle.down=slapSkin.getDrawable("handhit");
    slapButtonStyle.up=slapSkin.getDrawable("hand");
    slapButtonStyle.over=slapSkin.getDrawable("handhit");

    punchButtonStyle=new ImageButton.ImageButtonStyle();
    punchButtonStyle.down=punchSkin.getDrawable("punchHit");
    punchButtonStyle.up=punchSkin.getDrawable("punch");
    punchButtonStyle.over=punchSkin.getDrawable("punchHit");

    //apply style to slap button
    slapButton=new ImageButton(slapButtonStyle);
    punchButton=new ImageButton(punchButtonStyle);


    bossSlapAnimation=new Animation(1/10f, bossSlapAtlas.getRegions());
    bossPunchAnimation=new Animation(1/10f, bossPunchAtlas.getRegions());

    boss=new Boss(bossSlapAnimation);
    boss.setPosition(200,100);

    //Image img=new Image(new Texture("plus.png"));

    //make UI
    buttonTable.left().bottom();
    buttonTable.add(slapButton);
    buttonTable.row();
    buttonTable.add(punchButton);
    buttonTable.add();
    //buttonTable.setBounds(50,50,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
    buttonStage.addActor(buttonTable);
    buttonStage.addActor(boss);

    //add listeners
    slapButton.addListener(new ClickListener(){
        @Override
        public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
            slapped=true;
            boss.setAnimation(bossSlapAnimation);
            boss.act(Gdx.graphics.getDeltaTime());
            Gdx.app.log("debug-app", "touched slap");
            boss.reset();
            return true;
        }

        @Override
        public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
            super.touchUp(event, x, y, pointer, button);
        }
    });

    punchButton.addListener(new ClickListener(){
        @Override
        public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
            punched=true;
            boss.setAnimation(bossPunchAnimation);
            boss.act(Gdx.graphics.getDeltaTime());
            Gdx.app.log("debug-app", "touched punch");
            boss.reset();
            return true;
        }

        @Override
        public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
            super.touchUp(event, x, y, pointer, button);
        }
    });

    Gdx.input.setInputProcessor(buttonStage);

    /*bossTexture=new Texture("boss_large.png");
    bossSprite=new Sprite(bossTexture);*/
}

@Override
public void show() {

}

@Override
public void render(float delta) {

    //Gdx.gl.glClearColor(0,0,1,1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    game.batch.disableBlending();

    game.batch.begin();
    game.batch.draw(backgroundTexture,0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    game.batch.end();


    game.batch.enableBlending();
    game.batch.begin();

    buttonStage.act();
    buttonStage.draw();

    game.batch.end();
}

@Override
public void resize(int width, int height) {
    buttonStage.getViewport().update(width, height, true);
}

@Override
public void pause() {

}

@Override
public void resume() {

}

@Override
public void hide() {

}

@Override
public void dispose() {

}
}

Any advises?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

I don't see big problems in your code since you don't seem to have a problem in the code logic although I'm a little confused in the draw() method. Still, I think you can have another small modification in the draw() method. Also some minor formatting. Boolean values in comparison statements don't need to be compared explicitly. They can be used as themselves.

public class Boss extends Actor {
    protected Animation animation = null;
    private float stateTime = 0;
    private float width, height;
    private Texture bossTexture;
    private boolean acting, reset;

    public Boss(Animation animation) {
        bossTexture=new Texture("calm.png");
        width=Gdx.graphics.getWidth();
        height=Gdx.graphics.getHeight();
        acting=false;
        this.animation = animation;
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        if(acting) {
            TextureRegion currentFrame = animation.getKeyFrame(stateTime);
            batch.draw(currentFrame, 200, 100);
            acting=false;
        } else { // so that it don't have to draw every frame but still keeps the logic
            batch.draw(bossTexture, 200, 100);
        }
        if(reset){
            batch.draw(bossTexture, 200, 100);
        }
    }

    @Override
    public void act(float delta)
    {
        super.act(delta);
        acting = PlayScreen.slapped;
        stateTime+=delta;
    }

    public void reset()
    {
        reset=true;
        stateTime = 0;
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Thanks for the formatting comments, looks much better now, although the issue with using this method is, i would have to add more animation for the same actor, for which, more booleans will be added, handling which doesnt seem possible to me. \$\endgroup\$
    – Storm
    Commented Jul 31, 2016 at 10:22
  • \$\begingroup\$ How is that a problem? If you have other animations, just assign them to the animation field when needed. The draw() method will render whatever texture it gets. \$\endgroup\$
    – Neerkoli
    Commented Jul 31, 2016 at 18:07
  • \$\begingroup\$ I initialize Boss class before act or draw is called, so i wouldn't know which animation to send. @WeirdElfB0y \$\endgroup\$
    – Storm
    Commented Aug 1, 2016 at 14:46
  • \$\begingroup\$ Oh, okay. But then if you can make a public setter method for the animation, you can change it after you call Boss. \$\endgroup\$
    – Neerkoli
    Commented Aug 1, 2016 at 18:58
  • \$\begingroup\$ Oh yes, why didn't i think of that. Thank u so much, i'll implement it, and let you know. \$\endgroup\$
    – Storm
    Commented Aug 3, 2016 at 23:21
0
\$\begingroup\$

I had the 'same' problem after fading a non-looping actor. I changed the animation to loop and added

myActor.addAction(
  Actions.sequence(
    Actions.delay((frameDuration*framesAnimated), Actions.removeActor())));

this removes the actor after one loop and allows it to be reused

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .