I have tried to to create the collision detection for the 1st person shooter after reading the various postings. I created two nodes, one is a box which follows the camera all the time and the other is the box I am colliding with.
Box which is following camera:
Vector3f loc = new Vector3f(0,6,0);
Box camBox= new Box("CameraBox", loc, 0.1f, 0.1f, 0.1f);
camBox.setModelBound(new OrientedBoundingBox());
camBox.updateModelBound();
camBox.setTextureCombineMode(TextureState.OFF);
camBox.addController(new FollowCam(camBox));
camBoxNode = new Node("Camera box");
camBoxNode.attachChild(camBox);
sceneNode.attachChild(camBoxNode);
box3Node = new Node("box three");
box3Node.attachChild(box3);
sceneNode.attachChild(box3Node);
I use this code (which was posted in the WiKi to follow the camera:
public class FollowCam extends Controller
{
public Spatial[] toChange;
public FollowCam()
{
toChange = new Spatial[0];
}
public FollowCam(Spatial node)
{
toChange = new Spatial[1];
toChange[0] = node;
}
public void addSpatial(Spatial node)
{
// only add if a new node
int i;
for (i=0; i<toChange.length; ++i)
if (toChange[i]==node)
return;
// increase toChange size
// I do this because I assume this method is called only a few times
// during init, so optimise for update() (below)
Spatial[] temp = new Spatial[toChange.length+1];
for (i=0; i<toChange.length; ++i)
temp[i] = toChange[i];
toChange = temp;
toChange[i] = node;
}
/* (non-Javadoc)
* @see com.jme.scene.Controller#update(float)
*/
public void update(float time)
{
Camera cam = DisplaySystem.getDisplaySystem().getRenderer().getCamera();
Vector3f v = new Vector3f(cam.getLocation());
for (int i=0; i<toChange.length; ++i)
{
toChange[i].setLocalTranslation(v);
}
}
}
In the initGame() method I add collision detection
results = new BoundingCollisionResults()
{
public void processCollisions()
{
if (getNumber() > 0)
{
dbg("Collision: YES");
} else
{
dbg("Collision: NO");
}
}
};
results.addCollision(camBox, box3);
and in the update(float i) method I add this to detect collisions
but the only response I get is "Collision: No". I think I have covered just about everything to get the collision working, but I am doing something wrong and I am not detecting collision. Any ideas what's going wrong?
You could use the physics system and place a Box - which you turn into a PhysicsObject - at the cameras position (and synchronizing it every frame).
Then you set a ContactHandler to that PhysicsObject and simply override its (the ContactHandler, that is) onContact method to move the camera to its previous location…
However, if you’r not using the physics system for anything else, this wouldn’t be the ideal solution
What I would do, is init a cameraNode, and attach an invisble sphere at local translation (0, 0, 0). Add a boundingSphere/orientatedBoundingBox and check for collisions with the cameraNode.
I haven’t looked at your code there tomcat, but this is what i would do to check collisions AFTER ive setup the setup from above:
Thanks for this. I’ll try it tonight and hope I can get mine to work.
"Anonymous" wrote:
results.addCollision(camBox, box3);
What does this do? I never used it in my code. I'm pretty sure you don't need it. I think this function is called by findCollisions() to populate the collisions results list and you don't have to invoke it directly.
OK I used this code to say that I am looking for collision between those two objects so I knew which ones are colliding. My reason was that I wasnt sure how to find out which objects collide if I didnt use this. Is there anyway to do this if you had say 10 objects which were collision enabled?
You don’t need to do that to get a collision. I never called addCollision() and it still found any collisions between the ship and objects in the scenegraph.
//Clear the collision results
results.clear();
//Check to see if our ship has collided
rootNode.updateGeometricState(tpf, true);
ship.findCollisions(rootNode, results);
if (results.getNumber() > 0) {
int[] indexBuffer = new int[3];
collisionData = results.getCollisionData(0);
if(results.getCollisionData(0).getSourceTris().size() > 0){
ship.velocity.x = ship.velocity.x * -1;
ship.velocity.z = ship.velocity.z * -1;
ship.setLocalTranslation(ship.previousPos);
ship.setLocalRotation(ship.getPrevRot());
}
else{
if(results.getCollisionData(0).getTargetTris().size() > 0){
ship.velocity.x = ship.velocity.x * -1;
ship.velocity.z = ship.velocity.z * -1;
ship.setLocalTranslation(ship.previousPos);
ship.setLocalRotation(ship.getPrevRot());
}
}
//Outputs the triangles on the source that collided
for (int i = 0; i < results.getCollisionData(0).getSourceTris().size(); i++) {
int triIndex = ((Integer) results.getCollisionData(0).getSourceTris().get(i)).intValue();
ship.getTriangle(triIndex, indexBuffer);
System.out.println("Collision: Triag:" + indexBuffer[0]);
}
//Outputs the name of the target spatial that was hit
String Name = results.getCollisionData(0).getTargetMesh().getName();
System.out.println("Collided with: " + Name);
}
You use the following
String Name = results.getCollisionData(0).getTargetMesh().getName();
To get the name of the spatial you collided with. You can also just have it return a pointer to the spatial if you do.
That way you can make changes to the spatial you collided with
Note the above code assumes your object is colliding with only one object at a time. If you want to check for multiple collisions you just have to loop through all the indices in results. (i.e. results.getCollisionData(1), results.getCollisionData(2) etc.)
(My code is pretty sloppy since I'm still in the experimenting phase of using collision detection but hopefully it'll help you get it working)
Thx shocho. After a few more configurations, its now working. I am doing collision detection with geometry (well Boxes) at the moment and havent come across the problem you mentioned. When I start triangle collision detection I keep an eye for the problem.