Advertisement

AI help - flocking behavior - C#

Started by April 23, 2008 02:30 PM
12 comments, last by cdxrd 16 years, 7 months ago
Quote:
It actually doesn't look too bad.


Indeed it doesn't, I hope I haven't given you that impression. I recall my first experiments included boids happily dropping off the screen with NaN positions [wink]

Quote:
One more question if you dont mind there kindjie, your last statement about having the rules affect acceleration? sounds interesting, but as a newb how would you go about implementing that? even in pseudocode.. I'm trying to work it out in my head, but it aint working.. =)


This would have been the starting point of my 'realistic behavior' suggestion as well. Basically you could define a boid with the following properties:

class Boid{  private Vector2 currentPosition;  private Vector2 currentVelocity;  public Vector2 currentAcceleration; // of course, this should be a property  public void Update(float elaspedTime)  {     // update the position     currentPosition += currentVelocity * elapsedTime;     // introduce some drag to cheaply limit velocity     currentVelocity *= (1 - 0.25f * elapsedTime);           // update our velocity     currentVelocity += currentAcceleration * elapsedTime;  }}


Now, by changing the currentAcceleration you can indirectly influence the boid's movement behavior. This setup should allow your boid to react more realistically, so it won't for example change direction instantly but rather 'curve' towards the direction specified by the acceleration. The fudged drag is a cheap way of making sure the velocity vectors don't grow too large, so changes in acceleration are more noticable and it has the added benefit that the boid elegantly slows to a halt whenever there's no acceleration.

This is still pretty basic, but it may already give your simulation some more interesting behavior.
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Ok, but where does the acceleration get updated? I would assume its in the move, but are you talking about passing the velocity and adding that to acceleration? or?

Squiggly Frog - My little project place on the web. Updated as I see fit. =)

Advertisement
You could start off by setting the accelaration like you were setting the velocity in your original boid code. That's nowhere near physically correct, but it should have the effect of the velocity converging to the direction you want the boid to move to. The only thing you'll need to pay extra attention to is that you'll probably want to shorten the accelaration vector a bit so the boids don't 'overshoot' their target too much.


Disclaimer

Remember, you asked for the next few paragraphs. I'm not particularly good at math or physics for that matter, so it's quite possible that this contains errors. I also tried to include unsolicited information on simulation and convergence, which shouldn't really be read by any sane person.

Enjoy [smile]



To make matters more correct (and sadly more complex), you'd have to re-examine your rules. Then you'll see each rule except rule 3 actually calculates distances and not velocities, let alone accelerations. Some basic physics teaches that accelaration (a) affects an objects position (x) over time (t) like this:

x(t) = x(0) + v(0) * t + 0.5 * a * t * t

The calculated distances by the rules represent x(t) - x(0), the boids current position subtracted from the boids target position (center of mass for rule 1, 'away from others' for rule 2 and the cursor position for rule 4). In an ideal situation, the boid will have moved the total distance calculated by the rules after some time t. Hopefully this picture can make things clearer:



So if we define r1 + r2 + r4 as R, meaning the distance we want the boid to travel or x(t) - x(0), we can write:

R = v(0) * t + 0.5 * a * t * t

Now we're facing an interesting problem, since we want to calculate the acceleration (a) a boid with starting velocity v(0) needs to move to the end of vector R over some time (t). Since we have two unknowns (a and t) and only one equation, this problem has infinitely many solutions, so that's not very helpful. Instead we'll define t ourselves, which is reasonable since then it would represent the time we'll allow for the boid to get into position.

If we go with t = 1 (for simplicities sake), we can calculate the acceleration (a) we need to give a boid with initial velocity v(0) to move to the end of vector R in one second. So we can write:

R = v(0) * 1 + 0.5 * a * 1 * 1

or

R = v(0) + 0.5 * a;

or

a = 2 * (R - v(0))


And there you have it, calculating an acceleration to make the boid obey rules 1, 2, and 4 after one second. Of course, this will only work perfectly in an ideal situation where all other boids are stationary. In your (and in fact most typical) situation however, the distance R we so conveniently used as a constant actually depends on the positions and hence the accelerations of the other boids over time. So in order to solve this problem perfectly, you'd need to venture into the dark wastelands of complex integrals and the dreaded differential equations.

If this feels like a bit of a let-down, don't worry. We'll use a 'trick' similar to which most, if not all physics simulators rely on. Instead of calculating a perfect solution each frame, we'll rely on the fact that most videogames are updated at at least 60Hz and our less perfect approach will at least converge to the ideal solution.

The catch here of course is that our approach may not converge and actually goes wild with huge acceleration vectors. This shouldn't put you off, the risk is only marginally higher than with your initial approach, which relies on the same 'trick'. Anyway, this is where the drag comes in, since it helps filter out the effects of errors over time.

An additional help in tweaking the behavior would be adjusting t, which influences how soon your boid should converge. Lower values for t (fractions of seconds) typically give faster convergence but are more instable, meaning they are more likely to generate huge accelerations to travel larger distances (R) in some short time t. Likewise, higher values for t obviously make the boid converge slower, but run less risk of spinning your simulation out of control.


There, with that settled, we have one last thing left to take care off. Since rule 3 gives back a velocity and we don't want to adjust our velocity directly, we have two options to still factor it in. We could calculate the acceleration needed to obtain the desired velocity and adjust our calculated acceleration accordingly. Or we can calculate the distance a boid with the desired velocity would travel over our chosen time t and add that to our R for calculating the required acceleration, like this:

R = r1 + r2 + r4 + r3 * t

Obviously for our t = 1, this means we can just sum it with the other vectors and be done with it.

One last word of caution: this approach calculates a new acceleration each frame, so you should set the acceleration on your boid, not add it to the existing one.





Hopefully this is somewhat helpful and/or correct. If anyone spots a glaring error, feel free to correct it, since I really have to get back to work now [wink]
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Fun fun! lol.. I know I asked for it, so.. this should keep me busy for a little while. Its been a busy weekend and I needed something to study =) The only thing I got done this weekend was to add some code to convert my velocity and position and goal into vectors and into an angle so that I can rotate the boids to be facing the goal.. next up is the acceleration and keeping them from 'formation flying' like they do now.. going to start with landing, and work my way from there.

Looking forward to the read remigius!

[Edited by - cdxrd on April 29, 2008 12:00:44 PM]

Squiggly Frog - My little project place on the web. Updated as I see fit. =)

This topic is closed to new replies.

Advertisement