JMEDesktop Mouse Clicking + Picking Problem (Solved)

I have a game where movement of the player is performed via point-and-click. I also am using JMEDesktop where I make it the size of the display and place buttons at absolute positions.



My problem is whenever I click on a button, and if the terrain is behind it, I get both an action from the button (which is correct) and the player is moved to the point on the terrain where the clicking occurred. Obviously, I don't want any picking to occur if a Swing component was clicked…even if pickable Geometry exists behind the component.



Is there a good way to prevent these 2 events from occurring with 1 click?



For reference, I copied the usage of JMEDesktop as found in HelloJMEDesktop so I have:


public void setupGUI() {
   guiNode = new Node("guiNode");
   guiNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);
   final JMEDesktop desktop = new JMEDesktop("desktop", display.getWidth(), display.getHeight(), input);
   guiNode.attachChild(desktop);
      
   // center desktop on screen
   desktop.getLocalTranslation().set(display.getWidth()/2, display.getHeight()/2, 0);
      
   // perform all the swing stuff in the swing thread
         // (Only access the Swing UI from the Swing event dispatch thread!
   // See SwingUtilities.invokeLater()      
   // and http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html for details.)
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                // make it transparent blue
                desktop.getJDesktop().setBackground( new Color( 0, 0, 1, 0.0f ) );

                // create a swing button
                final JButton button = new JButton( "Click Me" );
                // and put it directly on the desktop
                desktop.getJDesktop().add( button );
                // desktop has no layout - we layout ourselves (could assign a layout to desktop here instead)
                button.setLocation( 200, 200 );
                button.setSize( button.getPreferredSize() );
                // add some actions
                // standard swing action:
                button.addActionListener( new ActionListener() {
                    public void actionPerformed( ActionEvent e ) {
                        // this gets executed in swing thread
                        // alter swing components ony in swing thread!
                        button.setLocation( FastMath.rand.nextInt( display.getWidth() ), FastMath.rand.nextInt( display.getHeight()) );                       
                    }
                } );
                // action that gets executed in the update thread:
                button.addActionListener( new JMEAction( "my action", input ) {
                    public void performAction( InputActionEvent evt ) {
                        // this gets executed in jme thread
                        // do 3d system calls in jme thread only!
                        guiNode.updateRenderState(); // this call has no effect but should be done in jme thread :)
                    }
                });
            }
        } );

        // don't cull the gui away
        guiNode.setCullMode( SceneElement.CULL_NEVER );
        // gui needs no lighting
        guiNode.setLightCombineMode( LightState.OFF );
        // update the render states (especially the texture state of the deskop!)
        guiNode.updateRenderState();
        // update the world vectors (needed as we have altered local translation of the desktop and it's
        //  not called in the update loop)
        guiNode.updateGeometricState( 0, true );       
}



For the picking, I simply have a MouseInputListener and the picking occurs in the onButton method.

One idea I had about solving this is to place a fully transparent Quad behind my GUI elements so that when a button is clicked, my picking logic would identify this transparent Quad (since it's closest to the camera) and I can simply ignore the pick request.



This could be a pain however if I made my GUI panels moveable around the screen. I'd then have to also move the transparent Quad so that they always aligned.



Anyone have any thoughts on this? I've been unable to find a similiar thread regarding this issue so if this has already been solved I'd love to know the URL.

I've done this before by bringing mouse events in and offering them to the GUI.  If they are consumed, (iow, if they hit the UI and the UI cares) then I don't offer it to the game world.

I've done this before by bringing mouse events in and offering them to the GUI.  If they are consumed, (iow, if they hit the UI and the UI cares) then I don't offer it to the game world.


Does this mean you don't setup an ActionListener for your buttons and other Swing elements?

I did not use JMEDesktop, so no, but I imagine you could grab the event, offer it to swing and in your ALs, flip a "consumed" flag to true.  Then before offering the event to your game InputHandler, check that flag.

Thanks for the hints. I'll look into this technique and give it a go this evening after work.

Unfortunately I don't have a code example because this was at NC, and also I had a more unified event system to work with (rather than having to go from jme events -> awt events).  Sorry.  :frowning:

Unfortunately I don't have a code example because this was at NC, and also I had a more unified event system to work with (rather than having to go from jme events -> awt events).  Sorry.


Thanks for the speedy responses and help with this renanse. It's much appreciated. At least I know of one more way that won't work for me.

In my next attempt I will try an invisible Quad hidden back behind all my GUI panels. Hopefully this will just work so I can resume on focusing on the meat of my game instead of fiddling around with GUI.  :wink:

I did not use JMEDesktop, so no, but I imagine you could grab the event, offer it to swing and in your ALs, flip a "consumed" flag to true.  Then before offering the event to your game InputHandler, check that flag.


I played around with getting this technique to work, and I was unsuccessful.

In passing an 'event' it implies that there are 'listeners' for that event. So how would this work if I didn't create an ActionListener on the buttons, but yet offered an event to Swing? When I create the ActionListeners on the button, the order in which the input methods are called are as follows:

1) onButton // from my JME MouseInputListener
2) actionPerformed // from the ActionListener
3) performAction // from the JMEAction

Do you have a code example you can offer?

Ok, the transparent Quad idea was too clunky.



I found a different solution that works though, and it's somewhat related to the technique mentioned by renanse.



My strategy is as follows:


  1. I created a GUIManager responsible for initializing and maintaining all of my GUI Swing elements.
  2. The GUIManager knows about all the GUI 'containers', like panels, etc. that should consume events.
  3. I assign ActionListeners as usual per normal Swing methodology.
  4. In my InputHandler, in the onButton method, I simply pass the screen coordinates of the mouse click to the GUIManager and ask if it 'willProcessEvent'.
  5. The GUIManager checks the screen coordinates with its own list of elements and returns true if the clicked point intersects with an element.
  6. In onButton, if 'willProcessEvent' returns true, then further processing of the mouse click stops – no picking is performed. Otherwise, the game picking occurs as usual.





    This strategy is so far working great for my needs. Hopefully anyone else having similar experiences with using JMEDesktop will find this useful.