Dodging algorithms

Started by
15 comments, last by Storyyeller 13 years, 11 months ago
Quote:Original post by Kid of the neon
I've read about boids and algorithm implementation (http://www.vergenet.net/~conrad/boids/pseudocode.html), but I don't understand how to apply this algorithm to my problem. As from algorithm overview, there are 3 corrections to velocity of boids: to center of mass, away from nearby boids and matching velocity. From this, how NPC agent velocity should be changed?


That article is very good.

You can change "away from nearby boids" to "away from X" where X is anything you want, such as enemies or projectiles. You can change "move to center of mass" to moving to wherever, such as toward the target or some other desired position.

Advertisement
I'd probably use potential fields. Create a grid over the playing area, put a large value at the point of each projectile based on the amount of damage it does, then draw a line of decreasing values along the projectile's path (with how much each step decreases in 'badness' based on the speed of the projectile - slower projectiles decrease in value faster). If the paths of multiple projectiles cross, add the values together. Then make a new field based on the sum of values close together in the original field (so if the AI is 10 units in radius, each square in the new field is the sum of all squares in a 10 unit radius). Finally, move towards the lowest values you can reach this frame.

If you have many AIs with identical characteristics, you can calculate the field only once and use it for all of them.

Also, you don't have to calculate the entire field, only the field around the AI based on its movement capabilities and size. If the AI is 10 units in radius and can move 20 units, you only need to calculate the field in a 30 unit circle around the agent. To do this, just project projectiles until they collide with the area of interest, then use that distance to decide how much to reduce the field impact of the projectile (just as if you had filled in the grid all the way from the projectile to the area of interest).

This has the benefit of taking global projectile distribution, time, and agent statistics into account. The steering or boids approach will typically only take local projectile distribution into account, and it takes more work to incorporate the fact that you only need to avoid the front of projectiles (using distance to a line or something like that).
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Quote:Original post by Extrarius
I'd probably use potential fields. Create a grid over the playing area[...]


Short of trying to do something optimal (which is hard and likely not worth it), I'd likely just use a potential-based approach as well. But why a grid? Just choose some reasonable function that you can evaluate analytically and move down its gradient; computing that should be much faster than iterating over a grid...

I'd only use a grid if I wanted to compute something like the brushfire algorithm or solve the heat equation (or some other PDE) over it numerically; sometimes this gives nice potential fields with particular global properties (e.g., no local minima). But if we're just doing locally-optimal stuff, heck, just build a potential out of elementary functions and differentiate.
Take a normal vector to each 2D (ground plane) projectile velocity vector (90 degree turn) and accumulate them. This is very cheap as only requires swapping their x and y and changing sign of new x. If this normal vector is on the opposite side of their velocity vector than the agent is, invert it. You want the normal vector to point into agent subspace (the projectile striaght path is a 2D BSP splitting plane).

The accumulated vector is your desired direction.

Rationale: You dont want to cross projectile paths and you will preferably avoid running in the same direction projectiles go, as they sort of catch up.

You can weight the vectors according to their speed and intersection distance (distance from agent position to projectile straight path) if you want.
Quote:Original post by Emergent
[...]But why a grid? Just choose some reasonable function that you can evaluate analytically and move down its gradient;[...]
Because it's easier to iterate over projectiles and draw lines from them than try to figure out an equivalent formula, and I'm not sure you could create an equivalent formula that didn't involve the same calculations as a grid. The influence of a projectile is conditional upon its eventual collision with a point, so you're still going to have to project them all forward in time to test for collision, then, if it would collide with a given position, calculate some value based on the distance into the future when it would collide combined with its damage.

The grid acts a very simple cache that allows evaluating each projectile only a single time regardless of the number of movement choices (or agents that need to make choices). You could use something more complicated (a fancy partitioning tree or graph) to cache collision information but I don't think it buys enough to be worth the extra work.

For example, if your movement choices are stay, right 1-10 units, or left 1-10 units, you'll need to know collisions for 21 possible locations. If you make a grid and fill it, you'll calculate each projectile's path once over a 21-square grid (since you only need to know the info for the places you can move) or, if you calculate each choice's weight independently, you might end up examining each projectile 21 times.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Quote:Original post by Extrarius
The grid acts a very simple cache that allows evaluating each projectile only a single time regardless of the number of movement choices (or agents that need to make choices).

I like that the complexity is basically constant w.r.t. the number of agents, but generally I'd expect many more grid cells than agents, which means that iterating over agents should be faster...

Quote:For example, if your movement choices are stay, right 1-10 units, or left 1-10 units, you'll need to know collisions for 21 possible locations.

Oh! So you're not just talking about moving down a gradient (which is what I always think of when I hear "potential field"); you actually want a global minimum. Is that right? In that case, I understand gridding, since basically all methods to find global minima boil down to exhaustive search...

In my game, the way I did it was to have the ai project forward the trajectories of bullets, and also project forward the trajectories of itself following possible inputs.

It starts by testing the trajectory it would follow if it does nothing. If that results in a collision, it then starts testing more complicated patterns such as accelerate 50, wait 50 or wait 50, accelerate 50.

If there are no paths with fewer then N input changes, then it just gives up and resigns itself to taking damage.


Of course, my game has factors that may make it not applicable to your situation. For example, I have a strong gravity well, meaning that simply projecting straight lines doesn't work. It also makes it impossible to find a closed form solution for the equations of motion. So that pretty much forces a trial and error approach involving projecting the simulation forward in time.

Other factors in my game that make it a more viable approach are the fact that all bullets do the same damage (so that I just do a boolean test instead of trying to minimize total damage), and there are a small number of them at any given time.
I trust exceptions about as far as I can throw them.

This topic is closed to new replies.

Advertisement