0

i am currently going through some tutorials on android development and libgdx/scene2d atm but got stuck on the touchevents:

For starters i am implementing a board game. By now i managed to draw the board and some meeples (player tokens) as well as adjust their position to the correct coordinates. When i started using libgdx i also successfully implemented a first test to see if the touchinput is working. The test looked something like this:

if(Gdx.input.isTouched()){
        touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
        camera.unproject(touchPos);
        stone.x=touchPos.x - stone.width/2;
        stone.y=touchPos.y - stone.height/2;

By now i rearranged my code to use scene2d because of some very convenient features. However it seems like i can't manage to get touchevents to work with scene2d despite i followed some rather simple tutorials. Since some of them reference some recent major changes to scene2d, i wondered if those tutorials might be outdated and hope you guys can help me fix my problem :) I will try and only paste the relevant parts of my code in here to present a minimal example of my non-working code. Of course i am also glad about any hints on how to "improve" my code in general since i am still learning and probably break some conventions here ^^

Lets start with my actor-class:

//deleted: imports

public class Player extends Actor{
    private int xval; //x Position of the Player on the board
    private int yval; //y Position of the Player on the board
    private Color color;
    private TextureRegion playerTexture;
    //deleted: some variables that are unimportant for touchevents

    public Player(int x, int y, TextureRegion texture){
        //initializing some Variables with default values
            this.xval = x;
            this.yval = y;
            color = new Color(1,1,1,1);

            playerTexture = texture;
            this.setTouchable(Touchable.enabled); //this should be set by default, but i added it just to be sure.

        //setBounds seems to be necessary in addition to the "touchable" flag to be able to "grab" or "touch" Actors.
        //getX and getY are methods of the actor class which i do not overwrite. I use distinct getters and setters to modify the Variables xval and yval.
            setBounds(getX(), getY(), playerTexture.getRegionWidth(), playerTexture.getRegionHeight()); 

        //now i implement the InputListener. This doesnt seem to get called, since the "touch started" message doesn't appear in LogCat.
        //In Theory the testevent should move the meeple one space to the right. 
        //To do that i call event.getTarget() which returns the actor of which the TouchDown is called. I then cast it to my Actor class (Player) and set xval to xval+1.
            this.addListener(new InputListener(){
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
                Gdx.app.log("Example", "touch started at (" + x + ", " + y + ")");
                ((Player)event.getTarget()).setXf(((Player)event.getTarget()).getXf()+1);
                return true;
                }
            });
    }

    //This is my draw method, which just sets the color of my meeple and then draws it to its current position.
    public void draw(Batch batch, float alpha){
        batch.setColor(color);
        batch.draw(playerTexture, getX(), getY());      
    }

    //deleted: several getters and setters
}

So if i got it right, the gdx inputProcessor is managing all inputs. If i set the Gdx InputProcessor to the stage which contains the actors, it will in case of an event (for example a touchDown) call the inputProcessors of all actors on the stage. Thus since i just added one to my class which includes a touchDown, this should handle the touchDown event in the case that the actor is actually touched. The hitbox to verify that is set by the statement "setBounds" in my Player class.

I implemented this in my ApplicationListener class:

//deleted: imports

public class QuoridorApplicationListener implements ApplicationListener{

    Stage stage;
    OrthographicCamera camera;
    //deleted: several variable declarations.       

    //deleted: constructor - this only fills some of my variables with values depending on game settings.

    @Override
    public void create() {
        //set stage - since "stage = new Stage(800,400,false)" doesn't seem to work anymore, i did set up a viewport manually. If you got suggestions how to this straightforward, please leave a note :)
        Gdx.app.log("Tag", "game started");
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);
        Viewport viewport = new Viewport() {};
        viewport.setCamera(camera);
        stage = new Stage(viewport);
        Gdx.input.setInputProcessor(stage); //like i described above, this should forward incoming touchevents to the actors on the stage.

        //deleted: setting textures, music, setting up the board (the boardtiles are actors which are added to the stage) 

        //deleted: setting TextureRegion, player colors, player positions and player attributes.
            for (int i = 0; i < playercount; i++){
                stage.addActor(players[i]);
            }
    }

    //deleted: dispose(), pause(), resume(), resize() methods.

    @Override
    public void render() {
        camera.update();

        for (int i=0; i< playercount; i++){
            players[i].setX(/*Formula to determine x-coordinates from Player.xval*/);
            players[i].setY(/*Formula to determine x-coordinates from Player.yval*/);
    } 

    stage.act(Gdx.graphics.getDeltaTime());
    stage.draw();
    }
}

I can't figure out what i am missing to get the touchevents working. So i hope you can help me :) Thanks a lot in advance!

1 Answers1

1

I think your problem originates from your manual creation of a Viewport object, which handles the unprojecting internally. Instead of

stage = new Stage(800,400,false);

you should use

stage = new Stage();

To resize the the viewport to the correct size once a resize event occurs you need to call

stage.getViewport().update( newWidth, newHeight )

in your ApplicationListener's resize method.

nfusion
  • 589
  • 1
  • 4
  • 11
  • when i do this, none of the stage content is drawn by my render() method anymore. Do i still need to set up a camera and assign it to the stage? I replaced my camera,viewpoint and stage declarations with the single line stage = new Stage(); now. – user3464149 Mar 26 '14 at 14:45
  • well i checked javadocs and am confused now. In theory stage = new Stage() should handly viewport and camera setup automatically. However my stage doesn't get drawn anymore. I did set x and y coordinates of some actors to 0 in case that i just get a "strange" point of view by default, but nothing shows up. However if i place a gdx.app.log in the draw method of my Playerclass, it gets called constantly. Do i need to modify my textures/ or the coordinates in any way to make this work? – user3464149 Mar 26 '14 at 15:49
  • seems like i am having another problem here. I tried using stage = new Stage() and did set the coordinates of my Actors to 0,0 - nothing showed up. Then i increased x and y coords by 1 in each frame, but no actors crossed my screen at any point. Next thing i tried was increasing the size of the Bounds of my actor and even overriding the hit() method of my actors to always return the actor. But still the touchDown of my InputListener isn't firing! By now i returned to manually setting the viewport and made sure to set bounds and actors to exactly the same coordinates. Thus i still need help =/ – user3464149 Mar 26 '14 at 20:44
  • Along with stage = new Stage() you need to resize the stage's viewport using the ApplicationListener's resize method. To do so, just call stage.getViewport().update( newWidth, new Height); – nfusion Mar 26 '14 at 21:15
  • thanks a lot - this did it for me :) I need to fix the location of my actors, but they all show up and react to touch events now - thanks a lot! – user3464149 Mar 27 '14 at 19:12
  • I am still not quite sure though what i did wrong in my initial approach. Even if the viewport handles projecting/unprojecting, this should only mess around with my coordinates, right? since i did set the hit() method so that it would always trigger, i don't understand why the viewport could prevent my touchevents from firing. – user3464149 Mar 27 '14 at 19:23
  • The unproject relies on the viewport to be of the exact same size as the window when called without additional parameters. Since you werent accounting for resize events, the viewport dimensions were most likely off, causing your touches to unproject onto wrong locations – nfusion Mar 27 '14 at 19:31