Basic problems putting first scene to work

Hi,



I'm new to jMonkeyengine, and I'm trying to figure out some basics.



I've gone through a bunch of tutorials and examples to get some thoughts before trying out, and now I'm making the move to code.



So first, my basic code, where I do my testing and where I plan to learn something useful from :):



(Code is mainly copied from somewhere else).



package com.sandbox.runtime;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.game.StandardGame;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;

public class Runtime {

   /**
    * @param args
    */
   public static void main(String[] args) {

      // Instantiate StandardGame
      StandardGame game = new StandardGame("A Simple Test");
      // Show settings screen
      try {
         GameSettingsPanel.prompt(game.getSettings());
      } catch(InterruptedException e) {
         e.printStackTrace();
      }
      // Start StandardGame, it will block until it has initialized successfully, then return
      game.start();

      DebugGameState gameState = new DebugGameState();   // Create our game state
      GameStateManager.getInstance().attachChild(gameState);   // Attach it to the GameStateManager
      gameState.setActive(true);   // Activate it

      gameState.getRootNode().attachChild( Runtime.getAxis() );

      Future<Camera> future = GameTaskQueueManager.getManager().update(
            new Callable<Camera>() {
               public Camera call() throws Exception {
                  DisplaySystem display = DisplaySystem.getDisplaySystem();
                  int width = display.getWidth();
                  int height = display.getHeight();
                  Camera camera = display.getRenderer().createCamera(width, height);
                  camera.setFrustumPerspective(45.0f, (float)width / (float)height, 1, 1000);
                  return camera;
               }
            }
         );
      Camera myCamera = null;
      try {
         myCamera = future.get();
      } catch(ExecutionException e) {
         e.printStackTrace();
      } catch(InterruptedException e) {
         e.printStackTrace();
      }
      myCamera.setLocation(new Vector3f(10f, 10f, 10f));
//      myCamera.setDirection(new Vector3f(0f, 0f, 0f));
//      myCamera.lookAt(new Vector3f(0f, 0f, 0f), new Vector3f(0f, 1f, 0f));
//      myCamera.apply();

      Box box = new Box("TestBox", new Vector3f(), 1.0f, 1.0f, 1.0f);      // Create a Box
      box.setRandomColors();   // Set random colors on it
      box.updateRenderState();   // Update the render state so the colors appear (the game is already running, so this must always be done)
      gameState.getRootNode().attachChild(box);   // Attach the box to rootNode in DebugGameState

//      CameraNode camNode = new CameraNode("Camera Node", myCamera);
//      camNode.setLocalTranslation(new Vector3f(0, 250, -20));
//      camNode.updateWorldData(0);
//      gameState.getRootNode().attachChild(camNode);

      gameState.getRootNode().updateRenderState();
   }

   public static Node getAxis() {
      Node axis = new Node("axis");

      float extent = 40.0f;

      Vector3f xAxis = new Vector3f(extent, 0, 0); //red
      Vector3f yAxis = new Vector3f(0, extent, 0); //green
      Vector3f zAxis = new Vector3f(0, 0, extent); //blue

      ColorRGBA[] red = new ColorRGBA[2];
      red[0] = new ColorRGBA(ColorRGBA.red);
      red[1] = new ColorRGBA(ColorRGBA.red);

      ColorRGBA[] green = new ColorRGBA[2];
      green[0] = new ColorRGBA(ColorRGBA.green);
      green[1] = new ColorRGBA(ColorRGBA.green);

      ColorRGBA[] blue = new ColorRGBA[2];
      blue[0] = new ColorRGBA(ColorRGBA.blue);
      blue[1] = new ColorRGBA(ColorRGBA.blue);

      Line lx = new Line("xAxis", new Vector3f[] { xAxis.negate(), xAxis },
            null, red, null);
      Line ly = new Line("yAxis", new Vector3f[] { yAxis.negate(), yAxis },
            null, green, null);
      Line lz = new Line("zAxis", new Vector3f[] { zAxis.negate(), zAxis },
            null, blue, null);

      lx.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      lx.updateModelBound();
      ly.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      ly.updateModelBound();
      lz.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      lz.updateModelBound();

      axis.attachChild(lx);
      axis.attachChild(ly);
      axis.attachChild(lz);

      return axis;
   }

}




Now some questions:


1# Strange errors

When started, I'm presented with "Game Settings".

After clicking "OK", I get the following error:
"The application or DLL D:...lwjglnativewindowsOpenAL64.dll is not a valid Windows image. Please check this against your installation diskette."

Clicking "OK" on the dialog, it apparently runs ok, but when pressing F4 the stats present some graphic artifacts.

At the end, the System.out is presented with an error info. Full System.out:


10/Ago/2009 17:19:47 com.jme.input.joystick.DummyJoystickInput <init>
INFO: Joystick support is disabled
10/Ago/2009 17:19:47 com.jme.system.lwjgl.LWJGLDisplaySystem <init>
INFO: LWJGL Display System created.
10/Ago/2009 17:19:47 com.jme.renderer.lwjgl.LWJGLRenderer <init>
INFO: LWJGLRenderer created. W: 640 H: 480   Version: 2.1.0
10/Ago/2009 17:19:47 com.jme.renderer.AbstractCamera <init>
INFO: Camera created.
10/Ago/2009 17:19:48 com.jmex.audio.openal.OpenALSystem setupSourcePool
INFO: max source channels: 32
10/Ago/2009 17:19:48 com.jmex.game.state.GameStateManager create
INFO: Created GameStateManager
10/Ago/2009 17:19:48 com.jme.util.lwjgl.LWJGLTimer <init>
INFO: Timer resolution: 1000 ticks per second
10/Ago/2009 17:19:48 com.jme.scene.Node <init>
INFO: Node created.
10/Ago/2009 17:19:49 com.jme.scene.Node <init>
INFO: Node created.
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "Text" attached to this node "TextNode"
10/Ago/2009 17:19:49 com.jme.scene.Node <init>
INFO: Node created.
10/Ago/2009 17:19:49 com.jme.scene.Node <init>
INFO: Node created.
10/Ago/2009 17:19:49 com.jme.scene.Line <init>
INFO: Line created.
10/Ago/2009 17:19:49 com.jme.scene.Line <init>
INFO: Line created.
10/Ago/2009 17:19:49 com.jme.scene.Line <init>
INFO: Line created.
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "xAxis" attached to this node "axis"
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "yAxis" attached to this node "axis"
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "zAxis" attached to this node "axis"
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "axis" attached to this node "RootNode"
10/Ago/2009 17:19:49 com.jme.renderer.AbstractCamera <init>
INFO: Camera created.
10/Ago/2009 17:19:49 com.jme.scene.Node attachChild
INFO: Child "TestBox" attached to this node "RootNode"
#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0bbfc059, pid=592, tid=2928
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_11-b03 mixed mode, sharing)
# Problematic frame:
# C  [OpenAL32.dll+0xc059]
#
# An error report file with more information is saved as hs_err_pid592.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#



Note: Removing files "OpenAL64.dll" and "lwjgl64.dll" from the natives folder will not present the dialog error, but still put's the error on the System.out.


2# Colors?

I'm defining axis lines to help understanding my 3D world, but although I'm assigning colors, they appear gray ... what am I missing? Light? Some update method?


3# Camera Pointing

The camera is pointing origin (0,0,0), but positioned somewhere on the z axis ...

I made an efford to change this ... without success ... I'm retrieving a camera, setting it's location on (10,10,10) and I want to point it to (0,0,0).

How to do that? Again, is there some update missing?


Thanks
  1. the EXCEPTION_ACCESS_VIOLATION happens when you exit your application right?

    this is a known problem see here:

    http://www.jmonkeyengine.com/forum/index.php?topic=11677.0


  2. you are using vertex colors, those colors are only visible if you disable lighting or set the MaterialStates ColorMaterial to AmbientAndDiffuse

    see http://www.jmonkeyengine.com/doc/com/jme/scene/state/MaterialState.ColorMaterial.html

         MaterialState ms =
            GameTaskQueueManager.getManager().update(new Callable<MaterialState>() {
            public MaterialState call() throws Exception {
               return DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
            }
         }).get();
         ms.setColorMaterial(ColorMaterial.AmbientAndDiffuse);
         axis.setRenderState(ms);




Alternatively, use MaterialStates to color your objects when using Lighting.

3) use the camera's cam.setLocation() and cam.lookAt() and cam.update()
DebugGameState uses a FirstPersonController to move the camera around, so this will ovverride your camera settings.


When pressing F4 you will only see stats, if stats are enabled:

       // Enable statistics gathering
       System.setProperty("jme.stats", "set");




I'd suggest, create your own GameState which creates your scene and handles the input / moves the camera.

I had #1 a few times - and it wasn't related to shutdown at all



I bit the bullet & went and set up all the native libraries properley, and it worked (jme2). When running from workspace (eclipse, anyway) you can set up native library directories on a per jar basis (don't know how well it works, only that it did for me).



Then I switched to windows and had workspace issues switching the libraries, so I just manually made sure that I loaded the right version.



in jme1, I had similar issues, but I solved them differently - I downloaded the lwjgl library independantly & used that.



When these crashes happened for me, it was always the wrong lib file being loaded


Thanks for the replies.



1# I created my own gamestate and the System.out message disappeared. Still get the warning popup if the *64.dll files are in native path.



public class WorldGameState extends BasicGameState {

   public WorldGameState(String arg0) {
      super(arg0);
   }

}



2# The minute I created my gamestate, the colors appeared ... so should they? eh

3# Finally I've put the camera on the location I wanted :)


Now I'm fighting to create some InputHandlers and InputActions to work ... I'm getting really frustrated, really fast ... I've ran through all examples, and can't seem to make it work.


First the code. It's crap, I know, but it's my little sandbox:


public class Runtime {

   /**
    * @param args
    */
   public static void main(String[] args) {

//      MouseInput.setProvider( InputSystem.INPUT_SYSTEM_AWT );
      KeyInput.setProvider( InputSystem.INPUT_SYSTEM_AWT );
//      JoystickInput.setProvider( InputSystem.INPUT_SYSTEM_LWJGL );

      InputAction buttonAction = new InputAction() {
         public void performAction( InputActionEvent evt ) {
            System.out.println( "[" + evt.getTriggerName() + "] button action performed." );
         }
      };

      KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
      keyboard.set("myCommand", KeyInput.KEY_SPACE);

      InputHandler input = new InputHandler();
      input.addAction(buttonAction , "myCommand", false);

      // Instantiate StandardGame
      StandardGame game = new StandardGame("A Simple Test");
      // Show settings screen
      try {
         GameSettingsPanel.prompt(game.getSettings());
      } catch(InterruptedException e) {
         e.printStackTrace();
      }
      // Start StandardGame, it will block until it has initialized successfully, then return
      game.start();

      WorldGameState gameState = new WorldGameState("World 3D");  // Create our game state
      GameStateManager.getInstance().attachChild(gameState);   // Attach it to the GameStateManager
      gameState.setActive(true);   // Activate it

      gameState.getRootNode().attachChild( Runtime.getAxis() );

      Future<Camera> future = GameTaskQueueManager.getManager().update(
            new Callable<Camera>() {
               public Camera call() throws Exception {
                  DisplaySystem display = DisplaySystem.getDisplaySystem();
                  int width = display.getWidth();
                  int height = display.getHeight();
                  Camera camera = display.getRenderer().createCamera(width, height);
                  camera.setFrustumPerspective(45.0f, (float)width / (float)height, 1, 1000);
                  camera.setLocation(new Vector3f(10f, 10f, 10f));
                  camera.lookAt(new Vector3f(0f, 0f, 0f), new Vector3f(0f, 1f, 0f));
                  display.getRenderer().setCamera(camera);
                  return camera;
               }
            }
         );
      Camera myCamera = null;
      try {
         myCamera = future.get();
      } catch(ExecutionException e) {
         e.printStackTrace();
      } catch(InterruptedException e) {
         e.printStackTrace();
      }
      myCamera.setLocation(new Vector3f(30f, 10f, 30f));
      myCamera.lookAt(new Vector3f(0f, 0f, 0f), new Vector3f(0f, 1f, 0f));

      Box box = new Box("TestBox", new Vector3f(), 1.0f, 1.0f, 1.0f);      // Create a Box
      box.setRandomColors();   // Set random colors on it
      box.updateRenderState();   // Update the render state so the colors appear (the game is already running, so this must always be done)
      gameState.getRootNode().attachChild(box);   // Attach the box to rootNode in DebugGameState

      Sphere sphere = new Sphere("TestSphere", new Vector3f(10.0f, 0.0f, -5.0f), 50, 50, 3);
      sphere.setRandomColors();
      sphere.updateRenderState();
      gameState.getRootNode().attachChild(sphere);

      gameState.getRootNode().updateRenderState();
   }

   public static Node getAxis() {
      Node axis = new Node("axis");

      float extent = 200.0f;

      Vector3f xAxis = new Vector3f(extent, 0, 0); //red
      Vector3f yAxis = new Vector3f(0, extent, 0); //green
      Vector3f zAxis = new Vector3f(0, 0, extent); //blue

      ColorRGBA[] red = new ColorRGBA[2];
      red[0] = new ColorRGBA(ColorRGBA.red);
      red[1] = new ColorRGBA(ColorRGBA.red);

      ColorRGBA[] green = new ColorRGBA[2];
      green[0] = new ColorRGBA(ColorRGBA.green);
      green[1] = new ColorRGBA(ColorRGBA.green);

      ColorRGBA[] blue = new ColorRGBA[2];
      blue[0] = new ColorRGBA(ColorRGBA.blue);
      blue[1] = new ColorRGBA(ColorRGBA.blue);

      Line lx = new Line("xAxis", new Vector3f[] { xAxis.negate(), xAxis },
            null, red, null);
      Line ly = new Line("yAxis", new Vector3f[] { yAxis.negate(), yAxis },
            null, green, null);
      Line lz = new Line("zAxis", new Vector3f[] { zAxis.negate(), zAxis },
            null, blue, null);

      lx.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      lx.updateModelBound();
      ly.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      ly.updateModelBound();
      lz.setModelBound(new BoundingBox()); // Important to set bounds to prevent some error
      lz.updateModelBound();

      axis.attachChild(lx);
      axis.attachChild(ly);
      axis.attachChild(lz);

      return axis;
   }

}



I just want to understand how this works.

1. I've created an InputAction that will do something (like moving, fire, exit, etc....):


      InputAction buttonAction = new InputAction() {
         public void performAction( InputActionEvent evt ) {
            System.out.println( "[" + evt.getTriggerName() + "] button action performed." );
         }
      };


2. I've used the factory/singleton KeyBindingManager to get a ... ehrm ... binding manager :), and created a binding for the SPACEBAR key:


      KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
      keyboard.set("myCommand", KeyInput.KEY_SPACE);


3. I then created an InputHandler, where I state that my "myCommand" binding will execute the InputAction to execute.


      InputHandler input = new InputHandler();
      input.addAction(buttonAction , "myCommand", false);



4. It doesn't work ...  :cry:


So I have questions ...

1. What am I doing wrong?
2. How does "input.addAction" know that it must connect the action provided with the "keyboard" object (my binding manager)? Is it automatically done?
3. Shouldn't I somewhere connect an InputHandler with my game state? Because if I have 2 gamestates, one for 3D world and another for a main menu, the actions would/could be entirely different ... I should disable/enable the respective ones ... what is the common way of achieving this?
4. Does the command name "forward" already has a defined behavior?


My intentions with the InputHandler and InputAction: to create an user control that WASD move camera forward, back, right, left, then XC for rotation on the vertical axis, then QZ for rotation on the horizontal axis, with a maximum and minimum defined angle on this latest rotation.


Thanks for your patience
  1. it says so in the javadoc :slight_smile:
  2. yes, your gamestate needs to update your inputhandler.
  3. of course it does :slight_smile:



    i made an example with two version.

    #1 is only using the KeyBindingManager, #2 the InputAction



import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jmex.editors.swing.settings.GameSettingsPanel;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;

public class InputGamestate extends BasicGameState {
   private InputHandler inputHandler = new InputHandler();
   
   public InputGamestate(String name) {
      super(name);
      // #1
      KeyBindingManager.getKeyBindingManager().add("space key", KeyInput.KEY_SPACE);
      
      // #2
      InputAction buttonAction = new InputAction() {
         public void performAction( InputActionEvent evt ) {
            System.out.println( "[" + evt.getTriggerName() + "] button action performed." );
         }
      };
      KeyBindingManager.getKeyBindingManager().add("myCommand", KeyInput.KEY_ESCAPE);
      inputHandler = new InputHandler();
      inputHandler.addAction(buttonAction , "myCommand", false);
   }
   
   @Override
   public void update(float tpf) {
      super.update(tpf);
      
      // #1
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("space key")) {
         System.out.println( "KeyBindingManager: 'space key' triggered");
      }
      
      // #2
      inputHandler.update(tpf);
   }
   
   @Override
   public void render(float tpf) {
      super.render(tpf);
   }

   /** run standardGame with our Gamestate */
   public static void main(String[] args) throws InterruptedException {
      StandardGame game = new StandardGame("inputtest");
      if (GameSettingsPanel.prompt(game.getSettings()) == false) {
         return;
      }
      game.start();
      GameStateManager.getInstance().attachChild(new InputGamestate("GS input"));
      GameStateManager.getInstance().activateAllChildren();
   }
}




You could also look into the GameControl System, which is yet another way of handling input.
Here is also a small example using GameStates and different input systems. -> Click <-