Search code examples
javalayoutlibgdx

Click through an Actor in libGDX


I have an overlay in my game that consists of an image of a screen, and a set of buttons that are "on" the screen.

Screenshot:

Screenshot showing UI components

My Screen has one Stage. The Stage has a set of Group objects, which I think of as layers. The first group has the backgrounds, the groups in the middle has the game elements, and the frontmost group has the screen overlay.

The overlay layer consists of one Image, the screen itself, and four TextButton (one in each corner).

This would work great, if it weren't for the fact that I can't click on anything in the game layer as long as the image in the overlay layer is in front of it. Even if the image is transparent, it still interecepts all touch events before they reach the game layer.

So my questions is: How can I make the image in the overlay layer ignore all touch events, so that the game layer will get them and one can actually play the game?

I tried one idea myself, but I'm not sure this is the right way to do it: I tried creating the image as a custom Actor that always had height/width set to 0, but still (by overloading the draw() method) drew the image on the entire screen. This works very well, except for the fact that the image for some reason gets drawn behind elements in lower layers.

Screenshot: https://dl.dropboxusercontent.com/u/1545094/Screen2.png

In this screenshot, I have opened a instruction messagebox, which adds itself to one of the game layers (group 6). Note that all the buttons in the overlay layer (which is group 7) is in front of the messagebox, but the screen frame (which is a custom Actor) somehow gets drawn behind the messagebox. Why is that? Note: If I take this exact same case, and change my custom actor into a regular Image, everything is drawn correctly, but then I can't click anything in the lower layers anymore, as described above.

This is my custom actor, if anybody can make any sense of it:

public class ClickThroughImage extends Actor {

    BaseDrawable d;

    public NonexistingImage(BaseDrawable d){
        this.d = d;
        setSize(0, 0);
    }

    @Override
    public void draw(SpriteBatch batch, float parentAlpha) {
        d.draw(batch, 0, 0, 1024, 768); //Yes, I tried swapping these two lines. 
        super.draw(batch, parentAlpha); //It had no effect.
    }
}

Solution

  • Use an InputMultiplexer. The InputMultiplexer class allows you to share user input among multiple input processors. Create your own class extending InputProcessor, and put that in InputMultiplexer with your Stage. That way you can respond to user input in a custom way, and still be able to use your stage.

        InputMultiplexer multiplexer = new InputMultiplexer();
        Array<InputProcessor> processors = new Array<InputProcessor>();
        MyInputProcessor myInputProcessor = new MyInputProcessor(); 
        processors.add(myInputProcessor);
        processors.add(stage);
        this.multiplex.setProcessors(processors);
    
        //...
        //and in your show method in your Screen class
        Gdx.input.setInputProcessor(this.multiplex);
    

    Also, be sure to return null from Actor.hit. This should cause the actor to not respond to any user interaction.

    This is how I solved this problem in my game.