Total n00b app #2 - inputcontroller & collision

Got my 1stperson navigation working fine. With regards to collision how would it work?



For example in xith to get collision with terrain in the first person I would create a collision system to hold all of the collisions which occur & are checked at each render. I would then create a dummy view using any old shape & attach it to a CollisionNode & update the view from here - also it would have its own physics. Then I would add a CollisionNode to the entire terrain. The collisionSytem checks for collisions between the CollisionNodes during each render.



With Jme would I use intersection to somehow work out if my view intersects my terrain after giving both a boundingVolume.



Also with regards to the phyiscs/gravity (because ultimately I want to use a milkshape character) would I need to use something like ODE or does JME have something built in?



Sorry if that sounds a bit muddled.

collision detection is easy peasy. Il get right on to answer this:



CollisionResults rs = new CollisionResults();
CollisionDetection.hasCollision(Spatial, Node, rs);



then:


if (rs.getNumber() > 0) {
//collision occured:
 Node collideWith = rs.getNode(0);
}



thats it basically.

as for physics, plans are in place, but no implementation yet. So ODE will be your best bet at the moment.

Hope that helps

Thanks.



CollisionResults rs = new CollisionResults();
CollisionDetection.hasCollision(Spatial, Node, rs);


So CollisionDectection tests for the Collision specified, so would Spatial will be my view. Can I put a view into a node? Or would I have to somehow create a dummy Node like a box and feed the positions of this into the view?


if (rs.getNumber() > 0) {
//collision occured:
Node collideWith = rs.getNode(0);
}

And this gets hold the node that has collided so you can do something with it?
So CollisionDectection tests for the Collision specified, so would Spatial will be my view. Can I put a view into a node? Or would I have to somehow create a dummy Node like a box and feed the positions of this into the view?


I don't understand what you mean by view. Are you trying to do picking? If so, there is a Pick object that takes a Spatial to test against and a ray. See the TestPicking test in the jmetest.intersection directory.

And this gets hold the node that has collided so you can do something with it?


Collision Results and PickResults both contain a list of all Geometry that had a collision. You can getNumber and getNode(int).

I don't understand what you mean by view. Are you trying to do picking? If so, there is a Pick object that takes a Spatial to test against and a ray. See the TestPicking test in the jmetest.intersection directory.


What I mean't was the camera moving around on the terrain like in any first person shooter.

Also I'll need to use getInterpolatedHeight(float x, float z) to reset the camera position/location each time I move/collide I assume so simulate gravity.
Also I'll need to use getInterpolatedHeight(float x, float z) to reset the camera position/location each time I move/collide I assume so simulate gravity.


Working on that right now, as a matter of fact.

I’ve noticed a class called CameraNode which I guess part answers my question.



Can I say the following to see if my camera/cameraNode collides with the terrain? :



Camera cam = setFrustum(....etc...);
CameraNode camNode = ("CameraNode", cam);

Node terrainNode = new Node("terrainNode"); //+ terrain creation stuff

CollisionResults rs = new CollisionResults();
CollisionDetection.hasCollision(camNode, terrainNode, rs);

if (rs.getNumber() > 0) {
//collision occured
camNode = rs.getNode(0);

//camNode is the node which collides
camNode.setCamera(--a new camera position on top of the terrain
using getInterpolatedHeight(x,z) to set the y location);
}



Do I make sense?

That is the plan, however, currently collision is only Bounding Volume accurate. That means you’ll only get true for collision of the box the surrounds the terrain block. We have plans to improve accuracy to triangles before too long.

So best only to use a flat terrain I guess.



Do I need to define the Bounging areas or are they automatically set?

Terrain bounds are currently set automatically.



See third post in this thread:



http://mojomonkeycoding.com/jmeforum/viewtopic.php?t=396

Thanks.



At the moment I’m going to download ODE & see about using it.



Has anyone else had any experience of using ODE with JME? :?

I’m definitely interested in hearing your opinion of the combination once you’ve used it.



I’m working on clicking on 3d objects (“picking with absolute mouse”) right now, but forcing my camera to stick on top of the terrain is my probable next step.



-Mike

I know that FuseBoy was working on using ODE in his application…

I’ve downloaded and built ODE, but at the moment I think I’m going to leave it as need to understand JME better.



At the moment I’m tring to set my camera on my terrain and detect a collision when the camera goes through its bounding volume.



Am I using getScaledHeightAtPoint() at the right place in initGame()(assuming its in the 0.6 jar) as I keep getting ArrayIndexOutOfBoundsException errors?



At the moment I have the following:



public class TestApp06 extends BaseGame {

   private Camera cam = null;
   private Node terrainNode = null, rootNode = null, sceneNode = null;
   private LightState lightState = null;
   private InputHandler input = null;
   private Timer timer = null;
   private CameraNode camNode = null;
   private MidPointHeightMap heightMap = null;

   
   public static void main(String[] args) {
      TestApp06 app = new TestApp06();
      app.start();
    }

   protected void update(float interpolation)
   {
      timer.update();
      input.update(timer.getTimePerFrame());
      sceneNode.updateGeometricState(timer.getTimePerFrame(), true);

      CollisionResults rs = new CollisionResults();
      CollisionDetection.hasCollision(camNode, terrainNode, rs);

      if (rs.getNumber() > 0)
      {
      //collision occured
      System.out.println("Collision with terrain");
      }

   }

   protected void render(float interpolation)
   {
      display.getRenderer().clearBuffers();
      display.getRenderer().draw(terrainNode);
   }
 
   protected void initSystem()
   {
      try{
         display = DisplaySystem.getDisplaySystem(properties.getRenderer());
            display.createWindow(800,600,16,60,false);
         cam = display.getRenderer().getCamera(
            800, 600);
        }
      catch (JmeException e)
      {
            e.printStackTrace();
            System.exit(1);
        }

      // setup our camera
      cam.setFrustum(1.0f, 1000.0f, -0.55f, 0.55f, 0.4125f, -0.4125f);
      
      display.getRenderer().setCamera(cam);
      camNode = new CameraNode("Camera Node", cam);

      // Setup the input controller and timer
      input = new FirstPersonHandler(this, cam, properties.getRenderer());
      input.setKeySpeed(15f);  //slow these down with lower values
      input.setMouseSpeed(2f);
      timer = Timer.getTimer(properties.getRenderer());
   }


   protected void initGame()
   {
      rootNode = new Node("rootNode");
      sceneNode = new Node("3D Scene Node");
      terrainNode = new Node("terrainNode");

      CullState cs = display.getRenderer().getCullState();
      cs.setCullMode(CullState.CS_NONE);
      cs.setEnabled(true);

      PointLight light = new PointLight();
      light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
       light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
       light.setLocation(new Vector3f(100, 100, 100));
       light.setEnabled(true);

      lightState = display.getRenderer().getLightState();
      lightState.setEnabled(true);
      lightState.attach(light);
      
      lightState.setTwoSidedLighting(true);
      sceneNode.setRenderState(lightState);

      heightMap = new MidPointHeightMap(128, 1.9f);
      Vector3f vector3f = new Vector3f(20F, 1.0F, 20F); //x & z increased to flatten
                                           
      TerrainBlock tb = new TerrainBlock("Terrain", heightMap.getSize(), vector3f,
                                 heightMap.getHeightMap(),
                                 new Vector3f(0, 0, 0), false);
      tb.setDetailTexture(1, 4);
      tb.setModelBound(new BoundingBox());
      tb.updateModelBound();
      terrainNode.attachChild(tb);
      terrainNode.setRenderState(cs);

      ProceduralTextureGenerator pt = new ProceduralTextureGenerator(
         heightMap);
      pt.addTexture(new ImageIcon(TestApp06.class.getClassLoader()
                           .getResource("data/grassb.png")),
                 -128, 0, 128);
      pt.addTexture(new ImageIcon(TestApp06.class.getClassLoader()
                           .getResource("data/dirt.jpg")),
                 0, 128, 255);
      pt.addTexture(new ImageIcon(TestApp06.class.getClassLoader()
                           .getResource("data/highest.jpg")),
                 128, 255, 384);

      pt.createTexture(512);

      Vector3f loc = new Vector3f(200, heightMap.getScaledHeightAtPoint(200, 500)
                                                         , 500);
      Vector3f left = new Vector3f( -1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, 0f, -1.0f);
      cam.setFrame(loc, left, up, dir);

      TextureState ts = display.getRenderer().getTextureState();
      ts.setEnabled(true);

          ......lots of terrain texturing stuff!

      terrainNode.setRenderState(ts);
      sceneNode.attachChild(terrainNode);

      rootNode.attachChild(sceneNode);
      sceneNode.updateGeometricState(0.0f, true);
      rootNode.updateRenderState();
   }

   protected void reinit() {}

   protected void cleanup() {}

}

You have to adjust for the terrain offset.



See



http://mojomonkeycoding.com/jmeforum/viewtopic.php?t=383

Now use getHeight from TerrainPage/TerrainBlock.

Thanks.



I must admitt I used that in the end.

I’m currently stuggling to get any collision to work. What I am tring to do is get my camera/cameraNode to register a collision with a cube I have placed on my terrain.


  1. I’ve setup the camera in the following way:



   protected void initSystem()
   {
      // setup camera
      cam.setFrustum(1.0f, 1000.0f, -0.55f, 0.55f, 0.4125f, -0.4125f);   
      display.getRenderer().setCamera(cam);
      camNode = new CameraNode("Camera Node", cam);
      Vector3f camCentre = new Vector3f(0.0f, 0.0f, 0.0f);
      BoundingSphere camBound = new BoundingSphere(1.0f, camCentre);
      camNode.setWorldBound(camBound);
}

protected void initGame()
   {
      //position camera on terrain
      Vector3f loc = new Vector3f(200, tb.getHeight(200, 200) + 15, 200);
      Vector3f left = new Vector3f(-1.0f, 0.0f, 0.0f);
      Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
      Vector3f dir = new Vector3f(0.0f, 0.0f, -1.0f);
      cam.setFrame(loc, left, up, dir);
}



2. I've created my box :


         //add box
      Vector3f max = new Vector3f(5, 5, 5);
      Vector3f min = new Vector3f( -5, -5, -5);
      aBox = new Box("Box 1", min, max);
      aBox.setModelBound(new BoundingBox());
      aBox.updateModelBound();
      //aBox.setLocalScale(2.0f);
      aBox.setLocalTranslation(new Vector3f(310, tb.getHeight(310, 310)+ 15,310));



3. Setup my Collision:


   protected void update(float interpolation)
   {
      timer.update();
      input.update(timer.getTimePerFrame());
      sceneNode.updateGeometricState(timer.getTimePerFrame(), true);

      CollisionResults boxCol = new CollisionResults();
      CollisionDetection.hasCollision(camNode, aBox, boxCol);

      if (boxCol.getNumber() > 0)
      {
         //terrain collision occured
         System.out.println("Collision with aBox");
      }

      //keep in boundary of terrain
      if(cam.getLocation().x < 10)
            cam.getLocation().x = 10;
      if(cam.getLocation().z < 10)
            cam.getLocation().z = 10;
      if(cam.getLocation().x > 5055)
            cam.getLocation().x = 5055;
      if(cam.getLocation().z > 5055)
            cam.getLocation().z = 5055;
      if(cam.getLocation().y < tb.getHeight(cam.getLocation().x, cam.getLocation().z) + 15)
          cam.getLocation().y = tb.getHeight(cam.getLocation().x, cam.getLocation().z) + 15;

   }




I can't see what I'm doing wrong. Do I need to specify the BoundingVolumes? But I'm sure these are automatically done.

The Camera Node has a BoundingSphere & the Box has a BoundingBox but I wouldn't think this makes a difference.

I can't really deduce much from the TestCollision example as it seem to test for any collision in the scene rather than between the two cubes.

I thought I followed Dark Prophets explanation, but I'm not so sure now.

no, bounding volumes are not automatically done:



Box b = new Box("Hello", new Vector3f(-0.1f, -0.1f, -0.1f), new Vector3f(0.1f, 0.1f, 0.1f);
b.setModelBounds(new BoundingBox());
b.updateModelBounds();



that sets the bounding volumes. :)

My first mistake was not calling the updateModelBounds(), that should clear the whole thing up

Thanks Dark Prophet.



I checked that that was OK and it didn’t seem to make a difference.



I think it must have something to do with my Bounds, but I have no idea what. :? :?