A common solution to that problem is to use ray casting, where an imaginary line is tested for intersections with the objects (ground, road) beneath the avatar (the running object).
Here's an example that uses the mechanics provided by jMonkeyEngine 3:
public boolean isOnRoad(Vector3f avatarPosition, Geometry road) {
// Pointing downwards (assuming that the Y-axis is facing upwards in your game)
Vector3f direction = new Vector3f(0, -1, 0);
// Create a line that starts at 'avatarPosition' and has a direction
Ray ray = new Ray(avatarPosition, direction);
// Results of the collision test are written into this object
CollisionResults results = new CollisionResults();
// Test for collisions between the road and the ray
road.collideWith(ray, results);
// If there is a collision, avatarPosition is above the road
return results.size() != 0;
}
You need to pass the position of the avatar to the function.
avatarPosition = avatar.getLocalTranslation();
If your road consists of multiple Geometries packed into a Node, you can also pass the Node instead of a single Geometry into the function. collideWith()
called on a Node will test all its children.
The function above might not work correctly if the Node also contains other parts of your Scene.
The call of road.collideWith(ray, results)
will implicitly build a BIH-Tree (Bounding Interval Hierarchy Tree) for the road-Mesh the first time it is used. That will speed up collision tests as it doesn't have to check the ray against every triangle of the road. It will be fast enough to do it in every update cycle.
Additionally, you can work with the results of the collision test.
This will return the exact point of the intersection that is closest to the starting point:
Vector3f p = results.getClosestCollision().getContactPoint();
And with the iterator you can process all collisions separately, sorted from closest to furthest collision:
Iterator<CollisionResult> it = results.iterator();
while(it.hasNext())
{
CollisionResult collisionResult = it.next();
Vector3f p = collisionResult.getContactPoint();
Geometry geom = collisionResult.getGeometry();
// Do something with contact point and geometry
}
More information about collisions:
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:collision_and_intersection
Ray casting is also used to select objects in the 3D Scene with a crosshair or the mouse.
This is called picking:
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:beginner:hello_picking