GameStates and a simple JMEDesktop menu

Hi,



I'm a little confused with the GameState system… I'm pretty sure there's something I'm missing.



I've modified TestGameStateSystem a bit : my MenuState has a JMEDesktop and i try to switch between States with simple JButtons in a JPanel.



First

From my IngameState, i press Esc to go back to the menu. I have a "Go back to game" button there.

If clicked, the game works but has an input problem : the mouse works, but keys don't (registered in InputHandler).

If i switch applications with Alt-Tab (Apple-Tab in my case actually), everything works again.



Button in menu :


goBackButton.addActionListener( new ActionListener() {
   

First

This sounds like s focus problem. Do you use the getFocusedComponent method of JMEDesktop somehow to disable ingame input? (Like in TestJMEDesktop)



Second

I wonder if creating a new game state is really a good idea to implement 'new game'. What about resetting the old game state. Nonetheless it should be possible, of course. Which line actually causes the NPE?

Was it getFocusOwner() for JMEDesktop ? I wasn't using it, i'll give it a try.



I agree that my "New Game" state is not the best way to go, but i'd like to understand why it doesn't work though :wink:

The NPE occurs in MenuState on


ingame = new IngameState("ingame");


Caused apparently by StandardGameState.initCamera();

I don't understand what's different from the MenuHandler "enter" Action (TestGameStateSystem)...

The whole exception :


java.lang.reflect.InvocationTargetException
   at java.awt.EventQueue.invokeAndWait(EventQueue.java:863)
   at javax.swing.SwingUtilities.invokeAndWait(SwingUtilities.java:1225)
   at com.jmex.awt.swingui.JMEDesktop.onButton(JMEDesktop.java:412)
   at com.jmex.awt.swingui.JMEDesktop$ButtonAction.performAction(JMEDesktop.java:1097)
   at com.jme.input.ActionTrigger.performAction(ActionTrigger.java:253)
   at com.jme.input.InputHandler.update(InputHandler.java:475)
   at com.jme.input.InputHandler.update(InputHandler.java:483)
   at brian.test.b02.MenuState.stateUpdate(MenuState.java:342)
   at com.jme.app.StandardGameStateDefaultCamera.update(StandardGameStateDefaultCamera.java:90)
   at com.jme.app.GameStateNode.update(GameStateNode.java:71)
   at brian.test.b02.Brian.update(Brian.java:61)
   at com.jme.app.FixedLogicrateGame.start(FixedLogicrateGame.java:128)
   at brian.test.b02.Brian.main(Brian.java:162)
Caused by: java.lang.NullPointerException
   at org.lwjgl.opengl.GL11.glMatrixMode(GL11.java:1718)
   at com.jme.renderer.lwjgl.LWJGLCamera.onFrustumChange(LWJGLCamera.java:116)
   at com.jme.renderer.AbstractCamera.<init>(AbstractCamera.java:213)
   at com.jme.renderer.lwjgl.LWJGLCamera.<init>(LWJGLCamera.java:70)
   at com.jme.renderer.lwjgl.LWJGLRenderer.createCamera(LWJGLRenderer.java:223)
   at com.jme.app.StandardGameState.initCamera(StandardGameState.java:111)
   at com.jme.app.StandardGameState.<init>(StandardGameState.java:76)
   at brian.test.b02.IngameState.<init>(IngameState.java:60)
   at brian.test.b02.MenuState$2.actionPerformed(MenuState.java:194)
   at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1819)
   at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1872)
   at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
   at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
   at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:247)
   at java.awt.Component.processMouseEvent(Component.java:5166)
   at java.awt.Component.processEvent(Component.java:4963)
   at java.awt.Container.processEvent(Container.java:1613)
   at java.awt.Component.dispatchEventImpl(Component.java:3681)
   at java.awt.Container.dispatchEventImpl(Container.java:1671)
   at java.awt.Component.dispatchEvent(Component.java:3543)
   at com.jmex.awt.swingui.JMEDesktop.dispatchEvent(JMEDesktop.java:617)
   at com.jmex.awt.swingui.JMEDesktop.sendAWTMouseEvent(JMEDesktop.java:796)
   at com.jmex.awt.swingui.JMEDesktop.access$9(JMEDesktop.java:729)
   at com.jmex.awt.swingui.JMEDesktop$6.run(JMEDesktop.java:414)
   at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:179)
   at java.awt.EventQueue.dispatchEvent(EventQueue.java:478)
   at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:234)
   at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:184)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:178)
   at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:170)
   at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)

I get this too.



There is a bug with the LWJGLCamera in the method onFrameChang calling GL11.glMatrixMode(GL11.GL_MODELVIEW)



This didnt happen before using JMEDesktop, unfortunately, i have no idea what this is. The only hunch is that i now am including ortho.

Hmm, I don't have a clue yet what it could be. Please try to replace JMEDesktop by a simple Quad and reduce your test until you can pin down the actual problem. I'd guess it's erroneous camera setup . . .

Ive taken out all of the ortho objects but still get it ( including all JMEDesktops and the cursorNode )



Just wonder wether this is a new bug introduced recently



It seems to manifest itself fromat java.awt.EventQueue.invokeAndWait(EventQueue.java:851)

Aha - it is a thread issue



I have assigned the method that changes views to a key stroke - this works as it used to, so it must be an issue with the awt event queue



btw. this works with ortho rendered nodes


Be sure that you touch the scenegraph from a single thread! If you have to touch it in an action use JMEAction as shown in HelloJMEDesktop.

Nice - it works :slight_smile:



Had to do a few tweaks to get the inputHandler statically available to the JPanel that owns the button - but yay - i can move on



Expect this may catch a few more people out - is it worth adding a Logging warning on the Onbutton method



Nice one irrisor

Could someone please explain why invokeAndWait() is being used in JMEDesktop at all? Removing them seems to work fine, and gets rid of those nasty-looking "Don't call invokeAndWait in the event-handling thread" entries in the log.

You should not get those in the log. Do you get them in HelloJMEDesktop or TestJMEDesktop? Or only in your own program?



InvokeAndWait is used to execute an operation in the awt event thread while current control flow is in the jME (usually main-) thread. When you get the log messages you describe, methods from JMEDesktop are already invoked in the awt thread - that should not happen!

I've been seeing the focus problem in current HelloJMEDesktop, TestJMEDesktop and my own program.



For example in HelloJMEDesktop, pressing "esc" to exit doesn't work until I Apple-Tab twice, once to another application and then once to come back to HelloJMEDesktop. Pressing "esc" then work if I haven't clicked the buton with the mouse.



Any idea what wrong with HelloJMEDesktop?








On some platforms, some JDKs/JREs cause these focus problems. We weren't able to solve them all. Especially on MacOS there are some unresolved focus problems. If you are able to find a fix or workaround, we would really appreciate it when you would post it on the board.

I'm working through HelloJMEDesktop and JMEDesktop to try and find the problem or a work around, no luck yet I still digging into it.



I think I can confirmed your comment about focus problems and that it happens in Java 1.5 on and Intel Mac with OSX 10.4.7.



I've also found that the keyboard input isn't getting to the InputHandle, I'm assuming thats because of the focus problem.



I've go one question about the code in JMEDesktop. I found the following in JMEDesktop…



        // this internal frame is a workaround for key binding problems in JDK1.5
        // todo: this workaround does not seem to work on mac
        if ( System.getProperty( "os.name" ).toLowerCase().indexOf( "mac" ) < 0 ) {
            final JInternalFrame internalFrame = new JInternalFrame();
            internalFrame.setUI( new BasicInternalFrameUI( internalFrame ) {
                protected void installComponents() {
                }
            } );
            internalFrame.setOpaque( false );
            internalFrame.setBackground( null );
            internalFrame.getContentPane().setLayout( new BorderLayout() );
            internalFrame.getContentPane().add( desktop, BorderLayout.CENTER );
            internalFrame.setVisible( true );
            internalFrame.setBorder( null );
            contentPane.add( internalFrame );
        }
        else {
            // this would have suited for JDK1.4:
            contentPane.add( desktop, BorderLayout.CENTER );
        }



What's this fix when you don't have a Mac?

I've found that the awtWindow Frame in JMEDesktop has the missing focus.



When the application starts it seems that nothing has the focus so keyboard input doesn't get to the JME InputHandler. Using Apple-tab you can move the focus to the JME window and the key event then get to the JME InputHandler (which can then get passed to AWT).



However when a mouse button event hits an AWT component then that hidden Frame (awtWindow) gets given the focus. Keyboard inputs doesn't get to the JME InputHandler. Keyboard input does however get to AWT via the hidden Frame (awtWindow).



I'm not sure if this is a symptom or the cause.



One thought is to writing an AWT event listener that can pass the input back to JME.

One other thought is to somehow prevent the focus changing at all (but that not such a good idea).



What do you think?


First about that win/lin fix: In the windows and linux jdk 1.5 there is a check if a component should be draw. It checks whether the component is in a natively visible window (uses a native method which can't be overwritten) or if it's in a virtually visible internal frame. Only if the check is successful the component is drawn. So the only possibility was to put them into an internal frame as the frame shouldn't be visible. On Mac the whole drawing seems to fail with the internal frame - thus the fix is only applied on windows and linux.



Passing back swing events to jME would mean to pass swing events to OpenGL - which won't be possible without alot of a hassle. So preventing that focus change seems the only possibility to me. This is done on windows and linux by making the window unfocusable and invisible. But it already was a pain to get it working that way for Win/14 + Win/1.5 + Lin/1.5 + Mac10.3/1.4. Now it seems there are problems with Mac10.4/1.5 and Win/1.6 . . .



It's great that you are trying to help.

I've been looking at this over the weekend and on OSX with JDK 1.5 it seems that:

  • you simple can't get the focus in the first place, it seem that neither the lwjgl or awt frame has it when the application start (even if the awtWindow is visable).
  • if you never call awtWindow.setFocusableWindowState( true ) then once the lwjgl window has the focus it can keep (but then things like text input which require focus can't work). Otherwise each time you press a button the awtWindow takes the focus back.



    Not sure what to try next. I'm going to have a quick look at replacing awt Toolkit, I've found some simple example that make it look simple (eg: PJA). At first look it doesn't seem to hard if you only support swing component (only light weight components) and it might mean the the awt thread is not needed. I'll let you know how I go.