I've a very difficult problem. The terrain I'm using for my game can't be compared with for example the terrain that's generated by the jME terrain maker. It has a lot of hills and mountains (I'll post a screenie later). Now I've several problems:
I want that the player walks on the terrain (gravity). I've heard something about rays and intersection, could somebody clarify this for me?
Sometimes, I want that a player cannot walk on a certain piece of terrain (hill to steep, may not walk into water, etc…). I've been thinking of collision with invisible meshes, but, does jME support that? And, what kind of algorithm do I need to implement to make sure the character cannot move trough these meshes?
I do not wish to use physics to accomplish these goals. I've tried once to use physics, and the effects where horrible (very bouncy player, unable to rotate player, etc…).
For the first point, you can keep the player character (PC) atached to terrain obtaining terrain height (y) for the current (x, z) coordinates of the PC and setting (y) according to the value you got. There is already a method to get terrain height for a couple (x, z), browse the API documentation and you will find it.
For the second point, i am not expert. But yuo could use a Warcraft III like method. You can preset pathable and non pathable squares using a separate file to store this informations. Depending on the resolution of the squares grid you will get more or less accurate results.
I think that this method is used also in World of Warcraft, even if everything seems apparently smooth. I guess this becouse I noticed that there are really steep paths that are pathable, because they lead to a reachable area, while other escarpments with about the same inclination are not pathable.
2) Sometimes, I want that a player cannot walk on a certain piece of terrain (hill to steep, may not walk into water, etc...).
Or You could get the hight of the terrain one step ahead before moving the unit and if the difference to where it currently is is to big then don't move the unit.
The advantage is You can adjust the players ability to climb mountains with skill or use different modifiers for different units.
Endar, can you tell me where to find that method in the api? Note that my terrain is a preloaded model.
For the second question, I've thought about using this. In games with simple maps, such as RTS games, this is a good method. But i'm making a third person game, and I want to use caves, buildings, etc…
winkman, that's a good idea, if I find the method for getting the terrain height. I believe the best option would be a Ray, and checking where it intersects.
EDIT: i've seen somewhere on this forums an algorithm to move the player to the Y location where an ray intersected the terrain, but it seems I cannot find it anymore. Could anyone give me a link?
Surround all "forbidden" terrain (ie too steep hills, rocky terrain, water, etc) with invisible meshes. Next make an invisible box mesh that surrounds my player. When moving, move the invisible mesh first, check whether it collisions with "forbidden" terrain, and if it doesn't, move the player.
2) Sometimes, I want that a player cannot walk on a certain piece of terrain (hill to steep, may not walk into water, etc...).
Or You could get the hight of the terrain one step ahead before moving the unit and if the difference to where it currently is is to big then don't move the unit.
The advantage is You can adjust the players ability to climb mountains with skill or use different modifiers for different units.
This is a good idea... but does it consume a lot of resources or not?
And I have a personal question about it. Can be a good approach for a MMORPG?
SeySayux said:
Endar, can you tell me where to find that method in the api? Note that my terrain is a preloaded model.
So, it is not a TerrainBlock? You can try casting a ray then.
Anyway there are 4 methods in the TerrainBlock class: getHeight(float x, float z), getHeight(Vector2f position), getHeight(Vector3f position) and getHeightFromWorld(Vector3f position). I do not know if there are similar methods in Node or Geometry classes.
if u dont want the player to walk into the water or the hills. simply cast a ray from where the player is to the destination the player is moving towards.
then define a final float as the minimum distance the player can get with the non-walk through models.
and check the distance if the player moves. if the distance is greater than the defined min, let the player walk, if the distance smaller, stop the movement.
if the hill is really steep, the distance will definately be less than the min. so u cant walk up or walk into it.
and for the water, just put a tall straight up model at the shore. and apply an alpha to it to make it invisible. for the same reason, the player cannot walk into the water anymore. well its actually coz the player cant walk through the invisible wall.
So… once the ray intersects, it stops, or what? I was thinking of measuring the distance between the player and the goal, and not the player and first collision.
So... once the ray intersects, it stops, or what? I was thinking of measuring the distance between the player and the goal, and not the player and first collision.
if the distance is less than a defined number, stop~
public float getCollisionPoint(Vector3f goal) {
Vector3f intersection = new Vector3f();
Ray ray = new Ray(goal , new Vector3f(goal.x, goal. y -1f, goal.z)
PickResults results = new TrianglePickResults();
// Use the ray to find all the models on the player's island which are hit by the ray.
results.clear();
terrainNode.findPick(ray, results);
// Find the target model in the results.
boolean found = false;
boolean hit = false;
for(int i = 0; i < results.getNumber() && found == false; i++)
{
TriMesh model = (TriMesh)results.getPickData(i).getTargetMesh().getParentGeom();
if(model.getName().equalsIgnoreCase(terrainNode.getName())
{
found = true;
// Find the intersection where the ray hits the target's boundingBox in world
// coordinate system.
Vector3f[] vertices = new Vector3f[3];
for(int j = 0; j < model.getTriangleCount() && hit == false; j++)
{
model.getTriangle(j, vertices);
hit = ray.intersectWhere(
vertices[0].addLocal(model.getWorldTranslation()),
vertices[1].addLocal(model.getWorldTranslation()),
vertices[2].addLocal(model.getWorldTranslation()), intersection);
}
}
}
// If the target cannot be found or the ray does not hit the target, return null.
if(found == false || hit == false)
return null;
// Return the intersection.
return intersection.y;
}