vrijdag 19 november 2010

Turn around, every now and then...

An important feature of platform games is enemies. Enemies that will try to harm you and make the levels harder and more diverse. From a level designers perspective you want to be able to place enemies wherever you'd like, so for a programmer there is no hard-coding enemy behaviour like "when the x coordinate is greater than 5 then turn around". Instead enemies should be able to find their own paths. When the enemy bumps into an object he should turn around, so we might think "Ok, let's use the collision report that the physic engine will give us", but that won't do because sometimes the enemy needs to turn around when there is no collision. "What?" you might say... well, we don't want enemies to run off platforms and in to pits, so they should turn around at the cliff but we won't get a collision report. We might introduce a new invisible kind of object and place that at every cliff, but our level designers won't like it. So let's explore a ray casting solution.

We cast a ray from the center of the enemy (a collision box, see image). W is the box width, H is the box height and L is how far to look ahead, R is the length before the ray hits the ground (on flat ground, ignoring slopes for now). This diagonal ray captures both to turn around on objects that are on the enemies path as well as to turn around when reaching a cliff. If the ray hits an object within distance R then there is some object in front of the enemy, but this doesn't necessarily mean the enemy should turn around. It could be that the ray hits the player in which case we don't want the enemy to turn around because we want the enemy to hurt the player. So some objects the ray hits should be ignored. When the ray hits an object at a distance exactly R then it's the ground the enemy walks on and it shouldn't turn around. If the ray didn't hit any object (ignoring the player) within distance R (plus a little bit) then we should turn around otherwise we will fall down possibly in to a pit which we don't want.

Now let's also explore slopes. Slopes sort of ruin our solution so far because now when the enemy starts walking up a slope we will get a ray hit with the ground within distance R as shown in the image. What we can do to avoid turning around now is taking into account the normal of the point on the ground we hit. If the normal is not strictly up (Y axis) or strictly to the side (X axis, the walls are also ground) then we've hit a slope and we won't turn around. It gets more tricky when walking down a slope. What we would like to know is "the distance along the ray when we can be certain we're not looking down a slope, but we're at a cliff and we should turn around". This depends on the steepest slope we have in the game which is 2 units right, 1 unit down. The ray we cast has "slope" (W/2)+L units right, H/2 units down. Looking at the image above at "Walking down a slope" we want to find the distance where the ray intersects with the slope. To calculate this we start at the intersection point and walk back until the difference between ray and slope is H/2. The equation to solve then becomes ((H/2)/((W/2)+L) - (1/2)) * t = H/2 in which t is the unknown which can be calculated by t = H/(H/(W+2L)-(1/2)). Note that (H/2)/((W/2)+L) should be greater than (1/2) or else t will be negative or when they are equal we get division by zero (meaning they never intersect). The distance S after which ray R intersects the slope then becomes sqrt(t^2 + (t*(H/(W+2L)))^2). This should actually be a bit more cause I haven't drawn the worst situation (Can you see what is the worst situation?). Now if ray R hits a slope and the distance along the ray is greater than S then we should still turn around (this situation can happen if we're at a cliff but somewhere below there is a slope).

And now that I've thought this out, it's time to code it. There are still little things to take into consideration, but this will do for the most part.

-- Stijn

Geen opmerkingen:

Een reactie posten