Search code examples
javalibgdxbox2dscene2d

Input Listener on libgdx Actor with Box2D


I want to touch an actor an execute an action(such as shooting bullets) but my Actor does not respond to touchDown. I tried both InputListener as well as clickListener. Also, I am using Box2D position to draw my actor. So, I am unable to determine correct values for setBounds. Please look at this code and let me know if I am doing anything wrong and how to set values in setBounds:

public class Jet extends Actor{

        World world;
        Body planeBody;
        MyGdxGame game;
        Texture plane;
        Animation<TextureRegion> jet;
        float planeWidth, planeHeight, stateTime = 0f, PIXELS_TO_METRES = 100;

        public Jet(World world, MyGdxGame game) {
            this.world = world;
            this.game = game;

            TextureAtlas textureAtlas = new TextureAtlas(Gdx.files.internal("plane.atlas"));
            jet = new Animation<TextureRegion>(0.01f, textureAtlas.findRegions("Fly"), Animation.PlayMode.LOOP);

            planeWidth = 100f;
            planeHeight = 80f;

            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.DynamicBody;
            bodyDef.position.set((game.V_WIDTH/8) / PIXELS_TO_METRES, (game.V_HEIGHT/2) / PIXELS_TO_METRES);

            PolygonShape polygonShape = new PolygonShape();
            polygonShape.setAsBox((planeWidth/2)/PIXELS_TO_METRES , (planeHeight/2)/PIXELS_TO_METRES);

            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = polygonShape;
            fixtureDef.density = 1f;

            planeBody = world.createBody(bodyDef);
            planeBody.createFixture(fixtureDef);
            planeBody.setGravityScale(0f);
     // I don't know what to set here, should it box.getPosition()?
    //        this.setBounds(game.V_WIDTH/8, game.V_HEIGHT/2, planeWidth, planeHeight);

            this.addListener(new ClickListener(){
                @Override
                public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                    //This isn't logged
                    Gdx.app.log("Inside touchDown", "just touched down");
                    return true;
                }
            });

        }

        @Override
        public void draw(Batch batch, float parentAlpha) {
            stateTime += Gdx.graphics.getDeltaTime();

            TextureRegion currentFrame = jet.getKeyFrame(stateTime);
            batch.draw(currentFrame, planeBody.getPosition().x * PIXELS_TO_METRES - planeWidth/2,
                    planeBody.getPosition().y * PIXELS_TO_METRES - planeHeight/2, planeWidth/2,
                    planeHeight/2, planeWidth, planeHeight, 1, 1,
                    planeBody.getAngle() * MathUtils.radiansToDegrees);
        }

    }

Stage render class :

    public class GameScreen implements Screen {

        MyGdxGame game;
        Stage stage;
        World world;

        public GameScreen(MyGdxGame game) {
            this.game = game;
            camera = new OrthographicCamera();
            stage = new Stage(new FitViewport(game.V_WIDTH, game.V_HEIGHT, camera));

            Jet jet = new Jet(world, game);
            stage.addActor(jet);
            Gdx.input.setInputProcessor(stage);
        }

        @Override
        public void render (float delta) {
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

            game.batch.setProjectionMatrix(camera.combined);

            game.batch.begin();
            stage.act();
            stage.draw();
            game.batch.end();

            world.step(1/60f, 6, 2);
        }
    }

Solution

  • Your actor position and your body positions are two different things.

    • An actor is a Scene2D element. You can update its position with setPosition method.All actors are on the stage
    • A body is a Box2D element which can be affected by gravity etc.

    You can, as you did, have a body assigned to an actor when you want to have the benefits of both Scene2D and Box2D, but then you must update the actor position with the body position if you interact with the body (e.g.:gravity) or update the body position if you interact with an actor using an actor method (click listener)

    you can do that in the act method as in this example. In this particular case it update the actor position based on the body position affected by gravity. You can see the end result here: https://libgdx.info/box2d-basic/

    So in your particular case you are missing something like

    this.setPosition(body.getPosition().x-this.getWidth()/2,body.getPosition().y-this.getHeight()/2); and this.setSize(actorWidth,actorHeigth)

    to set the actor position to the body position. Currently your actor is probably initialized at position 0,0 and with size 0

    I hope this helps..