Heightmap + Collision detection.

Started by
17 comments, last by Carleone 16 years, 10 months ago
Hello all, I've been writing a terrain engine. All is well so far and the thing works beautifully. The only problem is collision detection with hills that are too steep. I got to think, now I could either calculate the degrees the hill is or look at the pixels in the heightmap and check the difference. If the difference would for example be 10 pixels in height, then the hill would most likely be too steep. So, after having figured that out I stumbled upon a problem. How do I figure out what tile I need to check in order to allow/disallow my entity to move. I have a 360 degrees movement system, and I have absolutely no experience on how to do collision detection with that in a tile based map. Does anyone know how to handle this ? Here's my current move entity function.

/// MoveEntity. Moves an entity from it's current position to an other position.
int EntityManager::MoveEntity(BaseEntity *entity, float speed)
{
	Vector cp, cr, tp, np, op, ha, hb, hc, hd, deg;
	HeightObject *object = NULL;
	frametime_t *timer = engine->GetTimer();
	curframe = timer->curtime * 0.001f;
	lastframe = timer->lasttime * 0.001f;

	if (!entity)
		return 1;

	// Retrieve entities current position and rotation.
	cp = entity->GetPosition();
	cr = entity->GetRotation();

	// Negative speed or positive speed.
	if ((cr.GetZ() > 90) && (cr.GetZ() < 270))
		speed = -speed;

	// Retrieve vertice position in the map.
	if (entities.at(0) != NULL)
		object = ((HeightObject*)(entities[0]->GetModel()));
	
	// Get the object's plane position.
	ha = object->GetVertice(Vector(fabs(cp.GetZ() / 20.0f), fabs(cp.GetX() / 20.0f), 0, 0));
	hb = object->GetVertice(Vector(fabs(cp.GetZ() / 20.0f) + 1, fabs(cp.GetX() / 20.0f), 0, 0));
	hc = object->GetVertice(Vector(fabs(cp.GetZ() / 20.0f) + 1, fabs(cp.GetX() / 20.0f) + 1, 0, 0));

	hd = object->GetVertice(Vector(fabs(cp.GetZ() / 20.0f), fabs(cp.GetX() / 20.0f) + 1, 0, 0));
	// Calculate new position, check if a hill is steeper than 65 degrees.
	tp = cp;

	tp.SetX( tp.GetX() + ( (sin(cr.GetZ() * ANG2RAD) * RAD2ANG) * (speed * (curframe - lastframe))));
	tp.SetZ( tp.GetZ() + ( (cos(cr.GetZ() * ANG2RAD) * RAD2ANG) * (speed * (curframe - lastframe))));


	cp.SetX( cp.GetX() + ( (sin(cr.GetZ() * ANG2RAD) * RAD2ANG) * (speed * (curframe - lastframe))));
	cp.SetZ( cp.GetZ() + ( (cos(cr.GetZ() * ANG2RAD) * RAD2ANG) * (speed * (curframe - lastframe))));

	// Perform a bilinear interpolation.
	float tx = cp.GetX() / 20.0f - float(cp.GetX() / 20.0f);
	float ty = cp.GetZ() / 20.0f - float(cp.GetZ() / 20.0f);

	float xy = tx * ty;
	float h = ha.GetY() * (1.0f - ty - tx + xy)
				+ hb.GetY() * (tx - xy)
				+ hc.GetY() * xy
				+ hd.GetY() * (ty - xy);

	np.SetY(h);

	// Adjust the Y value so the object is always on top of the terrain.
	cp.SetY(np.GetY() + entity->GetModel()->GetBoundingBox().GetMax().GetY());

	// Set the new position.
	entity->SetPosition(cp);

	return 0;
}


Thanks a lot.
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
Advertisement
this is my advice:

1)You must get yours coordinates
2)if you use an heightmap for terrain, you must have a 'gap value' that identify the distance between 2 consecutives vertices. If you divide your position by this gap values, you get the vertice where you are.
3)with a very easy offset you can get from your heightmapbuffer the 4 vertices's heigh of the square where you are..
4)with these datas and your position in this square, you can calculate the exact heigh where you must be.


ok... my english is poor... so I post an example....

you have a heightmap of 256x256 --> byte* heightmapbuffer[256*256]
distances between vertices 10 --> int gap =10
so the world is 2560x2560 unit...

you are in position 1302,803
1302/10 = 130,2
803/10 = 80,3

this mean that on X axis you are between 130th and 131th vertice,
on Z axis you are between 80th and 81th vertices.

now you get the square's vertices where you are:
heightmapbuffer[(256*79)+130]
heightmapbuffer[(256*79)+131]
heightmapbuffer[(256*80)+130]
heightmapbuffer[(256*80)+130]

now you have this
 _____                                   _____                _____|     |                                 |\    |              |    /||     |                                 |  \  |              |  /  ||_____| and it is divide or in this way |____\|   or in this |/____|  


with some operation you can know in which triangle you are, e then calculate your real high....

probably is more easy do it, that read it....


bye



Hmmm, that's an idea yes. But my main point was, I still don't know what square to check for the height, and how to make it so I can stop my player/entity from walking into that part of the terrain.
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
Assuming you use the y coordinate for the height, then use the x and z coordinates of the player's position to find the tile that it sits on. You do this by dividing the x and z coordinate by the size of the tile. So, if each tile represents 10 units in world space, and the player's position is at (15, 11), then the entity is sitting on (1, 1) in tile space.
you can calculate the square where you are, the square to check for the height.

Like strtok has rewrite, dividing your position by vertices's distance, you get the vertices of the square where you are.

easy and speed....
The problem is not with finding the tile I am standing on. The problem is finding out what tiles to test for how steep a hill is. and also how to make it so that if it is too steep, X or Z won't be added.
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
This is really better for Math & Physics, I think.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Quote:
The problem is finding out what tiles to test for how steep a hill is. and also how to make it so that if it is too steep, X or Z won't be added.

it is not a problema, because with trigonometry and the 3 triangle vertices coordinates, you can calculate the tile slope...
if the slope is too much, you don't add X or Z.... you don't need of another tile... and otherwise you know your direction, so you can know which will be the next tile.
Well in that case, if I need to calculate it on the tile that I am standing on. How would I go about calculating how steep it is ? And I still need to know wether I should add X or Z or if I should not add them. I hope you understand me. Thx a lot already :)
http://sourceforge.net/projects/pingux/ <-- you know you wanna see my 2D Engine which supports DirectX and OpenGL or insert your renderer here :)
ok... you follow above istructions, and you'll know in which tile you stay.

for example you are in this square.
A_____B _ _|\    |  | | \   |  | Z|  \  |  |   <---- this is a square! not a rectangle!!  :)|   \ |  | |____\| _|_C     D  |__x__||     |

A B C and D are 3 vector(x,y,z), of course..

You are in ABD or in ACD??

1)check position inside tile
float coefX = B.x - position.x;
float coefZ = B.z - position.z;

if (coefX >= coefZ) <---- you are in ABD
D3DXPlaneFromPoints(Plane, A,B,D);
else <---- you are in ACD
D3DXPlaneFromPoints(Plane, A,&v3,&v4);

now you have a plane!!
This is your point height
height = (-position.x * Plane.a - position.z * Plane.c - Plane.d) / Plane.b;


now, you calculate the slope.

ok... maybe there are some errors, but the juice there is...

in this forum there is people with mathematical skill better than mine.

This topic is closed to new replies.

Advertisement