Newbie Question - Simple Collision Detection

Hi,



I am trying to implemented very simple collision detection between static node terrain and dynamic node box. Terrain is a maze with walls and I am hoping to implemented a scenario where when the box collides with walls it doesnt go through it. I tried the basic stuff with generating geometry on both parts i.e. staticNode.generatePhysicsGeometry(true) and dynamicNode.generatePhjysicsGeometry(). But unfortunately when the box collides, it goes up in the air and goes round and round and the whole thing crashes. I tried using getcollisioneventhandler just to change the co-ordinates of the object on impact to see if it stays stable - doesnt crash but the damn thing spins all over the place and the scene flickers and it crashes!



Any ideas why and how to change that - I just want to stop my player/box going through the walls!



Regards,



Dev

I would suggest digging a little deeper in the forums using search. I know that I have seen a few topics on the very same problem. (or maybe I'm just crazy  :|) I have found that changing up my search terms helps in finding what you are looking for. Good luck.

Which implementation of jME Physics do you use? I assume it's ODE (you can see it in the console when you don't turn off logging level info)



Generally your use case should work out of the box. If you're still stuck you could test it with TestGenerateTerrain, throw out that terrain and add your maze stuff to the very same node. If this works, try to figure out what you did differently…

Hey,



It says on the console Odejava 0.3.1. I also tried replacing my terrain in TestGenerateTerrain. The terrain generates fine but as soon as the sphere or box hit the terrain it crashes and I get this error:


#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x7c911404, pid=3872, tid=3224
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_07-b03 mixed mode)
# Problematic frame:
# C  [ntdll.dll+0x11404]
#
# An error report file with more information is saved as hs_err_pid3872.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

[error occurred during error reporting, step 270, id 0xc0000005]

Java Result: -1
BUILD SUCCESSFUL (total time: 11 seconds)



This does not mean a thing to me. So at least we now know that the problem seems to be in Terrain. The full code for my program is as follows:

Main Class Ares.java

This class is run with AresHandler which at this point in time is same as FlagRushHandler provided in the next "code segment". It uses image "image.png" (provided at the end, which is a randomly generated 2D maze) to generate a 3D maze - which generates fine.



/**
 * This class is designed from the framework provided at the
 * jME(graphics engine/scenegraph being used in the project) website
 * in the "Flag Rush Tutorial series". It can be viewed at
 * http://www.jmonkeyengine.com/wiki/doku.php?id=flag_rush_tutorial_series_by_mojomonkey
 */

import com.jme.app.SimpleGame;
import Backup.BaseGame;
import com.jmex.terrain.TerrainBlock;
import com.jmex.terrain.util.ImageBasedHeightMap;
import com.jmex.terrain.util.ProceduralTextureGenerator;
import com.jme.math.Vector3f;
import com.jme.bounding.BoundingBox;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.image.Texture;
import java.net.URL;
import javax.swing.*;
import com.jme.scene.Skybox;
import com.jme.renderer.ColorRGBA;
import com.jme.system.DisplaySystem;
import java.util.HashMap;
import com.jme.util.resource.MultiFormatResourceLocator;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.ResourceLocator;
import java.net.URISyntaxException;
import com.jme.renderer.Camera;
import com.jme.system.JmeException;
import com.jme.util.Timer;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.scene.Node;
import com.jme.scene.shape.Sphere;
import com.jme.light.DirectionalLight;
import com.jme.scene.state.LightState;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.renderer.Renderer;
import com.jmex.terrain.util.ProceduralSplatTextureGenerator;
import com.jme.light.PointLight;
import com.jme.bounding.BoundingBox;
import com.jme.scene.shape.Box;
import com.jme.input.ChaseCamera;
import com.jme.input.thirdperson.ThirdPersonMouseLook;
import com.jme.math.FastMath;
import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.KeyBindingManager;
import com.jme.input.MouseInput;
import com.jme.input.joystick.JoystickInput;
import com.jme.scene.state.MaterialState;
import com.jme.scene.shape.Sphere;
import com.jme.light.SimpleLightNode;
import com.jme.scene.shape.Quad;
import com.jme.scene.SharedMesh;
//import com.jme.math.Quaternion;
import java.nio.FloatBuffer;
import ares.Agent;
import com.jme.util.export.binary.BinaryImporter;
import java.io.IOException;
import com.jme.bounding.BoundingSphere;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import com.jmex.model.converters.FormatConverter;
import com.jmex.model.converters.ObjToJme;
import com.jme.intersection.TriangleCollisionResults;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.StaticPhysicsNode;
import ares.Agent3D;
import com.jme.input.FirstPersonHandler;
import com.jmex.physics.geometry.PhysicsBox;
import com.jme.input.util.SyntheticButton;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jmex.physics.contact.ContactInfo;
import com.jme.util.geom.Debugger;
import com.jmex.physics.PhysicsDebugger;

/**
 * This class currently provides 3D geometry for a randomly generated
 * maze and also provides background textures for the environment.
 * It displays a player(box at this stage) in a 3rd person view whose movement
 * can be controlled through arrow keys. It contains following issues:
 * Lighting - the lighting needs to improve
 * Textures - for the geometry generated with ImageBasedHeightMap
 * Collision Detection - collisions are not detected currently
 *
 * @author Dhaval Sejpal
 */
   
public class Ares extends BaseGame
{
    private int width, height, depth, freq;
    private boolean fullscreen;
    private PhysicsSpace physicsSpace;
    private Camera cam;
    protected Timer timer;
    private Node scene;
    private TextureState ts;
    private Texture t;
    private TerrainBlock tb;
    private Skybox skybox;   
    private LightState lightState;
    private Node player;
    private ChaseCamera chaser;
    protected InputHandler input;
    private Box box;
    private DynamicPhysicsNode playerNode;
    private StaticPhysicsNode terrainNode;

    protected boolean showPhysics;
   
    public static void main(String[]args)
    {
        Ares app = new Ares();
        app.setDialogBehaviour(NEVER_SHOW_PROPS_DIALOG, Ares.class.getClassLoader()
             .getResource("jmetest/data/images/Space Art.jpg"));
        app.start();
    }
   
    //update
    protected void update(float interpolation)
    {
        timer.update();
        interpolation = timer.getTimePerFrame();
       
        getPhysicsSpace().update(interpolation);
       
        input.update(interpolation);
        chaser.update(interpolation);
       
        skybox.setLocalTranslation(cam.getLocation());

   if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit"))
        {
            finished = true;
   }     
        scene.updateGeometricState(interpolation, true);   
    }

    protected void render(float interpolation)
    {
        display.getRenderer().clearBuffers();
        display.getRenderer().draw(scene);
    }
   
    protected void initSystem()
    {
        width = properties.getWidth();
        height = properties.getHeight();
        depth = properties.getDepth();
        freq = properties.getFreq();
        fullscreen = properties.getFullscreen();
       
        try
        {
            display = DisplaySystem.getDisplaySystem(properties.getRenderer());
            display.createWindow(width, height, depth, freq, fullscreen);
           
            cam = display.getRenderer().createCamera(width, height);
   }
       
        catch (JmeException e)
        {
            e.printStackTrace();
            System.exit(1);
   }

        display.getRenderer().setBackgroundColor(ColorRGBA.blue);

        cam.setFrustumPerspective(45.0f, (float) width / (float) height, 1,5000);
        Vector3f loc = new Vector3f(250.0f, 30.0f, 180.0f);
        Vector3f left = new Vector3f(-0.5f, 0.0f, 0.5f);
        Vector3f up = new Vector3f(0.0f, 1.0f, 0.0f);
        Vector3f dir = new Vector3f(-0.5f, 0.05f, -0.5f);
   cam.setFrame(loc, left, up, dir);
        cam.update();

        timer = Timer.getTimer();

        display.getRenderer().setCamera(cam);
 
        KeyBindingManager.getKeyBindingManager().set("exit",KeyInput.KEY_ESCAPE);

    }
   
    protected void initGame()
    {
        display.setTitle("Ares");
       
        scene = new Node("Scene graph node");
       
        physicsSpace = PhysicsSpace.create();
                terrainNode = getPhysicsSpace().createStaticNode();
                playerNode = getPhysicsSpace().createDynamicNode();
  
        ZBufferState buf = display.getRenderer().createZBufferState();
   buf.setEnabled(true);
   buf.setFunction(ZBufferState.CF_LEQUAL);
   scene.setRenderState(buf);
       
        CullState cs = display.getRenderer().createCullState();
        cs.setCullMode(CullState.CS_BACK);
        scene.setRenderState(cs);
       
        buildTerrain();
       
        buildPlayer();

        buildChaseCamera();
       
        buildInput();
       
        buildSkyBox(); 
       
        scene.updateGeometricState(0.0f, true);
        scene.updateRenderState();
    }
 
     private void buildPlayer()
    {
        Box box = new Box("Player", new Vector3f(), 0.35f,0.25f,0.5f); 
        //box.setLocalTranslation(100, 15, 100);
        box.setSolidColor(ColorRGBA.blue);
        box.setModelBound(new BoundingBox());
        box.updateModelBound();
        scene.attachChild(playerNode);
        playerNode.attachChild(box);
        playerNode.setLocalTranslation(100, 10, 42);
        playerNode.updateWorldBound();
        playerNode.generatePhysicsGeometry();
        playerNode.setAffectedByGravity(false);
        //playerNode
        playerNode.computeMass();
        System.out.println("The bounding of the box is: " + box.getWorldBound());
    }

    private void buildTerrain()
    {
       
        display.getRenderer().setBackgroundColor(ColorRGBA.blue);

        URL grayscale = Ares.class.getClassLoader().getResource("jmetest/data/texture/image.png");

        URL waterImage=Ares.class.getClassLoader().getResource("jmetest/data/texture/wall.jpg");
        URL baserock =Ares.class.getClassLoader().getResource("jmetest/data/texture/cloud_land.jpg");
        URL highest=Ares.class.getClassLoader().getResource("jmetest/data/texture/highest.jpg");

        ImageBasedHeightMap ib=new ImageBasedHeightMap(new ImageIcon(grayscale).getImage());

        TerrainBlock tb=new TerrainBlock("image icon",ib.getSize(),new Vector3f(2f,.05f,2f),ib.getHeightMap(),
            new Vector3f(0,0,0),false);

        ProceduralTextureGenerator pg=new ProceduralTextureGenerator(ib);      
        pg.addTexture(new ImageIcon(highest), -128, 0, 10);
        pg.addTexture(new ImageIcon(waterImage), 40,80,128);     
        pg.addTexture(new ImageIcon(highest), 110,180,256);
        pg.createTexture(256);                       

        TextureState ts=display.getRenderer().createTextureState();

        ts.setTexture(TextureManager.loadTexture(pg.getImageIcon().getImage(),
            Texture.MM_LINEAR_LINEAR,Texture.FM_LINEAR, true));

        tb.setRenderState(ts);
        tb.setModelBound(new BoundingBox());
        tb.updateModelBound();
        tb.setLocalTranslation(new Vector3f(0,0,-50));
        terrainNode.attachChild(tb);
        terrainNode.generatePhysicsGeometry();
        scene.attachChild(tb);
    }
   
     private void buildChaseCamera()
     {
        Vector3f targetOffset = new Vector3f();
        targetOffset.y = ((BoundingBox) playerNode.getWorldBound()).yExtent * 1.12f;
        HashMap props = new HashMap();
        props.put(ThirdPersonMouseLook.PROP_MAXROLLOUT, "6");
        props.put(ThirdPersonMouseLook.PROP_MINROLLOUT, "3");
        props.put(ChaseCamera.PROP_TARGETOFFSET, targetOffset);
        props.put(ThirdPersonMouseLook.PROP_MAXASCENT, ""+45 * FastMath.DEG_TO_RAD);
        props.put(ChaseCamera.PROP_INITIALSPHERECOORDS, new Vector3f(5, 0, 30 * FastMath.DEG_TO_RAD));
        props.put(ChaseCamera.PROP_TARGETOFFSET, targetOffset);
        chaser = new ChaseCamera(cam, playerNode, props);
        chaser.setMaxDistance(8);
        chaser.setMinDistance(2);
    }
    
     private void buildInput()
     {
        input = new AresHandler(playerNode, properties.getRenderer());
    }
        
    private void buildSkyBox()
    {
        skybox = new Skybox("skybox", 500, 100, 500);
 
        Texture north = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/north.jpg"),Texture.MM_LINEAR,Texture.FM_LINEAR);
        Texture south = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/south.jpg"),Texture.MM_LINEAR,Texture.FM_LINEAR);
        Texture east = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/east.jpg"),Texture.MM_LINEAR,Texture.FM_LINEAR);
        Texture west = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/west.jpg"),Texture.MM_LINEAR,Texture.FM_LINEAR);
        Texture up = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/clouds.png"),Texture.MM_LINEAR,Texture.FM_LINEAR);
        Texture down = TextureManager.loadTexture(Ares.class.getClassLoader().getResource(
            "jmetest/data/texture/bottom.jpg"),Texture.MM_LINEAR,Texture.FM_LINEAR);
       
        skybox.setTexture(Skybox.NORTH, north);
        skybox.setTexture(Skybox.WEST, west);
        skybox.setTexture(Skybox.SOUTH, south);
        skybox.setTexture(Skybox.EAST, east);
        skybox.setTexture(Skybox.UP, up);
        skybox.setTexture(Skybox.DOWN, down);
        skybox.preloadTextures();
        scene.attachChild(skybox);
    }
   
    protected void setPhysicsSpace(PhysicsSpace physicsSpace)
    {
        if (physicsSpace != this.physicsSpace)
        {
            if ( this.physicsSpace != null )
            {
                this.physicsSpace.delete();
                this.physicsSpace = physicsSpace;
            }
        }
    }
   
    public PhysicsSpace getPhysicsSpace()
    {
        return physicsSpace;
    }
   
    protected void reinit()
    {
        display.recreateWindow(width, height, depth, freq, fullscreen);
    }

    protected void cleanup()
    {
        //ts.deleteAll();
    }     

}



AresHandler.java(for movement of the box)


/*
 *
 * Created on 17 November 2007, 15:56
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */


/**
 *
 * @author ug73dxs
 */
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.action.KeyNodeBackwardAction;
import com.jme.input.action.KeyNodeForwardAction;
import com.jme.input.action.KeyNodeRotateLeftAction;
import com.jme.input.action.KeyNodeRotateRightAction;
import com.jme.scene.Spatial;

 
/**
 * Input Handler for the Ares game. At this minute it is the same as
 * flag rush handler
 *
 */
public class AresHandler extends InputHandler
{
 
    /**
     * Supply the node to control and the api that will handle input creation.
     * @param node the node we wish to move
     * @param api the library that will handle creation of the input.
     */
    public AresHandler(Spatial node, String api)
    {
        setKeyBindings(api);
        setActions(node);
    }
 
    /**
     * creates the keyboard object, allowing us to obtain the values of a keyboard as keys are
     * pressed. It then sets the actions to be triggered based on if certain keys are pressed (WSAD).
     * @param api
     */
    private void setKeyBindings(String api)
    {
        KeyBindingManager keyboard = KeyBindingManager.getKeyBindingManager();
       
        keyboard.set("forward", KeyInput.KEY_UP);
        keyboard.set("backward", KeyInput.KEY_DOWN);
        keyboard.set("turnRight", KeyInput.KEY_RIGHT);
        keyboard.set("turnLeft", KeyInput.KEY_LEFT);              
    }
 
    /**
     * assigns action classes to triggers. These actions handle moving the node forward, backward and
     * rotating it.
     * @param node the node to control.
     */
    private void setActions(Spatial node)
    {
        KeyNodeForwardAction forward = new KeyNodeForwardAction(node, 22f);
        addAction(forward, "forward", true);
       
        KeyNodeBackwardAction backward = new KeyNodeBackwardAction(node, 18f);
        addAction(backward, "backward", true);
       
        KeyNodeRotateRightAction rotateRight = new KeyNodeRotateRightAction(node, 0.8f);
        rotateRight.setLockAxis(node.getLocalRotation().getRotationColumn(1));
        addAction(rotateRight, "turnRight", true);
       
        KeyNodeRotateLeftAction rotateLeft = new KeyNodeRotateLeftAction(node, 0.8f);
        rotateLeft.setLockAxis(node.getLocalRotation().getRotationColumn(1));
        addAction(rotateLeft, "turnLeft", true);
    }
   
   
   
}



Finally image.png which I use to generate the 3D terrain



This code is relatively straight forward and its nothing high level or complex. The functions implemented are relatively simple as well still I dont understand why the physics does not work??

Kind Regards,

Dev


EDIT: Since we established that the problem was with the terrain, I typed a search for "imagebased" in the physics part of the forum and I found another person who had exactly the same problem(on contact with the terrain the box would spin and go wild and crash) but different error console. Unfortunately, he got it to work but without definitely finding out what the problem was(just said "it has something to do with the heightscale of the terrain"). The html of the post is as below:

http://www.jmonkeyengine.com/jmeforum/index.php?topic=6610.0

So are there any specific rules regarding heightscale of the terrain or for terrains/maps generated using imagebasedheightmaps for using physics??

None that I know of. But you should generally avoid triangles where all points are at the same location. You could check if it's the case in your terrain…



Maybe you should ask in the other thread what he changed with the height scale?

Alright… I have asked the person about the changes he made with the heightscale. But since I am using basegame instead of simplegame is it possible for you to just check my Ares.java class to make sure I have integrated the physics correctly and it is a bug/other error and nothing wrong with the code? The code is relatively standard and based on the tutorials and I feel I have integrated the physics correctly.



Thanks,



Dev