R. White
R. White

Reputation: 13

Moving a sprite (Actor?) in Libgdx using Scene2D

I've been trying to learn scene2d and I'm having trouble getting a sprite/Actor to move when a key is held down. I've tried a few different methods but I can't seem to figure it out. This is the code I currently have, which moves the actor everytime i press the key but not when it is held down.

class Player extends Actor {
    Sprite sprite = new Sprite(new Texture (Gdx.files.internal("character.png")));

    public Player() {
        setBounds(sprite.getX(), sprite.getY(), sprite.getWidth(), sprite.getHeight());
        setTouchable(Touchable.enabled);

        addListener( new InputListener() {

            @Override
            public boolean keyDown(InputEvent event, int keycode) {
                if (keycode == Input.Keys.RIGHT) {
                    MoveByAction mba = new MoveByAction();
                    mba.setAmount(1f, 0f);

                    Player.this.addAction(mba);
                }
                return true;
            }
        });
    }

    @Override
    protected void positionChanged() {
        sprite.setPosition(getX(), getY());
        super.positionChanged();
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        sprite.draw(batch);
    }

    @Override
    public void act(float delta) {
        super.act(delta);
    }


}

Upvotes: 1

Views: 2405

Answers (2)

m.antkowicz
m.antkowicz

Reputation: 13581

I'm not really sure if actor has a focus on itself to handle KeyUp/Down events and that's why I would avoid using listeners to move player.

Also changing the actor's position does not need actions - there is a simple setPosition() method in Actor class. You have also getX() and getY() methods to get current position of actor.

What would i do would be to check if any Key is down (by using Gdx.input not lisetners) and set position modified by some defined step like:

//Actor class
final float STEP = 1f;

...

@Override
public void act(float delta) {
    super.act(delta);

    if(Gdx.input.isKeyPressed(Keys.W))
        this.setPosition(getX(), getY() + STEP);
    if(Gdx.input.isKeyPressed(Keys.S))
        this.setPosition(getX(), getY() - STEP);
    if(Gdx.input.isKeyPressed(Keys.A))
        this.setPosition(getX() - STEP, getY());
    if(Gdx.input.isKeyPressed(Keys.D))
        this.setPosition(getX() + STEP, getY());
}

the act() method is called in every render (if you are calling stage's act of course) so the movement will be continuous.

Upvotes: 0

Fuat Coşkun
Fuat Coşkun

Reputation: 1055

You can use a state mechanism for doing that. This can be a simple enum like that :

public enum PlayerMoveState {
   RIGHT,
   LEFT,
   IDLE
}

Define a field below to your sprite typed PlayerMoveState like this :

PlayerMoveState moveState;

Set it's state to proper one according to Input.Keys.RIGHT, Input.Keys.LEFT in your keyDown method. Reset the state by setting it to IDLE in keyUp method which you need to override and implement.

@Override
public boolean keyUp(InputEvent event, int keycode) {
    moveState = PlayerMoveState.IDLE;
}

Finally, write a simple switch case block in act method of your player.

@Override
public void act(float delta) {
   super.act(delta);
   switch(moveState) {
      case RIGHT :
      // Move right by using whatever method you want.
      // Directly increasing x
      // Increase x according to velocity you have defined.
      // Use actions, little bit dangerous.
         break;
      case LEFT :
      // Move left by using whatever method you want.
         break;
      case IDLE :
      // Don't change x coordinate of your player.
         break;
      default :

         break;
   }
}

Upvotes: 1

Related Questions