AI help - flocking behavior - C#

Started by
12 comments, last by cdxrd 15 years, 12 months ago
Ok, so I thought that next on my list was tackling some AI. I was looking at Boids Psuedocode for a flocking setup. Well, I set up a new project, got a background and some sprites. Im populating the list, and displaying the sprites, then with a short delay it starts updating. Problem is, as far as I can see I implemented it properly but all the sprites move to the bottom right. For some reason my Velocity vector keeps ending up with values like 568, 492.. not sure where exactly im going wrong on this, so thought I would see if anyone wants to look at it and see if you can tell where im going wrong. game1.cs flutterby.cs Project source if you have xna 2.0 installed - Zipped - 597kb Download Anyone see where im going wrong? I think i've gone cross eyed.. [Edited by - cdxrd on April 24, 2008 10:52:54 PM]

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

Advertisement

The function for rule one (lines 77-104), you're returning the center of mass position as the velocity to use. This should be (centerOfMass - boid.Position), to actually get the required velocity for the boid to move to the center of mass. This is also detailed in the pseudocode as (pcJ - bJ.position) .

You might also want to multiply the combined velocity by the elapsed time from the last frame (you can get this from the GameTime object supplied by the overridden Update function in your Game class). This way line 63 would become:

63. flutter.Pos += flutter.Vel * elapsedFrameTime;

I think this should reduce the position increase to acceptable levels (so the calculated velocity is actually used as units/second) and the behavior of your objects no longer depends on your framerate, which is generally considered bad practice.

Hope this helps :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Thanks regimus, I havent played with it yet but Ill go back over it today after work. I knew I had to be doing something not quite right, but I thought I had it all the way it should have been. thanks for taking a look!

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

Ok regimus, i fixed Rule 1 where I overlooked that, but that still doesnt solve the troubles. Right now I have added a rule4 which guides them all to a predetermined point which is controlled by WASD right now. The problem Im encountering right now is that I usually get 2-3 butterflies that DO migrate to that point, but I get 3-4 that always seem to migrate to the bottom right.

Its Rule 2 that Im having the problem in, as soon as I make it return a 0,0 vector they all flock to the point they are supposed to, they just dont keep a distance from each other like rule 2 is supposed to provide. Any insights?

ATM Im not worried about updating distance based on the elapsedtime since this is only a demo project, I'd rather get the behaviors correct and then move on to moving them based on the elapsed time. Ive included a link to a youtube video here to show the current mucked up behaviors. I've also updated the source zip to include the latest changes.

New Game1.cs

New FlutterBy.cs

New Zip file

">Youtube Behavior Video

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


Well, at first glance I'd say the distance calculations aren't entirely correct. You'd probably want to use something like this:

Vector2 distVector = (otherBoid.Pos - thisBoid.Pos);bool tooClose = distVector.Length() < range;


But that doesn't account for the strange behavior. I think the main problem lies in the 'scaling' of the velocity vectors you calculate. In rule 1 you divide the target velocity by the number of boids, while the total velocity of rule 2 has a far greater magnitude since it is not scaled like this. This would mean the velocity from r2 would easily be large enough to hide any behavior prompted by rule 1.

Depending on your setup code, this would most likely mean that the first boid is starting to move away from the flok, since rule 2 is so stong, with the rest cascading along in the same general direction. A quick and dirty way to fix this would probably be to divide the r2 velocity by the number of boids, so rule 1 and 2 have equal influences. In fact, I'd divide the result form rule 2 by a somewhat larger number to make rule 1 leading.


That said, I'm unfamiliar with original algorithm by Reynolds, but the implementation suggested by the pseudocode feels a bit backwards to me. Obviously the choice is up to you, but I'd try and start with the general movement behaviors of the boids and then implement the flocking rules against these. The restrictions implied by realistic movement behavior typically make for a much more interesting simulation.

But I'll spare you a treatise on this unless you're really interested [smile]
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Well Regimus, you have peaked my curiosity.. and I've tried dividing R2 by the number of boids and it didnt seem to make too much of a difference, especially since i added in a velocity limiter.. they still flock wrong.. The pseudocode did seem a bit off to me, but since Im such a newb to this particular part of programming It felt off, but its been referenced by so many books and sites i figured I have to be doing something wrong.

I am thinking about rewriting parts of it to add a bool flag like currentUpdate or such and when its that boids turn to update, flip the flag and eliminate any possibility that the while if(b != fb) thing is causing troubles.. plus I wondered if the list isnt getting passed right, etc.. I might just tear the whole thing down and try rebuilding from scratch. This *IS* just a learning experience for me..

If you have some other ideas on implementing on flocking behavior, go right ahead.. im interested.. =)

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

In rule 1 shouldnt
119. r1 = r1 / (count - 1) ;
be just
119. r1 = r1 / count;
(As count is initialized to 0, and only increases for each boid velocity added.)


In rule 2 (line 146) I would have thought that the scaling is wrong, as the futher away another FlutterBy is(within the range 45), the faster you will move away from it.
Maybe something like this would be better. (btw psuedo code)
Vector2 direction = (b.Pos - fb.Pos).normalise();float scale =  1.0f / ((b.Pos - fb.Pos).magnitude() + 1.0f); r2 += direction * scale;


For rule 3 i suggest you perform it last, as although the current FlutterBy's velocity is taken into account, it is the last frame/ticks velocity and not the current accumulation from the other rules. (Though this probably won't be noticable.)

I also suggest you scale the ending velocity with the time delta (as remigius first suggested)

flutter.Pos += flutter.Vel;

becomes
flutter.Pos += flutter.Vel * elapsedFrameTime;


Apart from that, nothing stands out at me.
Hey!

It actually doesn't look too bad. I think your problem is that you're not reflecting the velocity when they collide with the edge of the world, so your alignment rule will have them keep crashing into the wall and get stuck in the corner.

Another thing that I usually do is add multipliers for each rule, because it's pretty hard to control the flocking. One way is just to add 3 new member variables that you can tweak to your Flutterby class, then multiply them with what your rules return.

I didn't look too closely, but your alignment might be a lot higher than your separation. Usually that's ok, because alignment's the main way you stop them from colliding (if they all fly in the same direction, they won't hit each other), but you might run into issues when you hit a wall or approach a goal.

Once you have everything working, try having your rules affect their acceleration instead. You get more smooth, natural motion that way.

Hope that helps!

~kindjie
[size="1"]Try GardenMind by Inspirado Games !
All feedback welcome.
[s]
[/s]

[size="1"]Twitter: [twitter]Owen_Inspirado[/twitter]
Facebook: Owen Wiggins

[size="1"]Google+: Owen Wiggins

Really appreciate the thoughts everyone.. I am switching it over to a time based movement.. plus Moomin in rule 1, yes that should have been divided by count not count-1.. but ive been playing for 2 days and was experimenting and that got left in.. thanks for noticing tho!

Kindjie, you said:

Another thing that I usually do is add multipliers for each rule, because it's pretty hard to control the flocking. One way is just to add 3 new member variables that you can tweak to your Flutterby class, then multiply them with what your rules return.

Ok, so what exactly do you mean by adding multipliers and adding 3 new member variables? such as what? Just a random int or better a random float value such as 0.6f for each 'rule' and multiply by those? of course having different random floats for each entity?

It would make things a little more interesting maybe, plus this way they couldnt end up in a 'formation' and flying around as such constantly.

I do plan to add in multiple goals and as each flutterby hits a goal there's a chance it will 'land' and 'sit' on the goal for x amount of time before taking off and joining the flock again.

Of course, this is just all to teach myself a few new tricks and I really reallly reallllly appreciate the help and input!

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.. =)

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

Best of luck with the code.

Just thought i'd post my Fish Flocking / Schoaling demo, it uses the Boids algorithm too.

http://www.kjmsoftware.co.uk/fish_flocking/fish.htm

You can modify it in run time to create different flocking behaviours.

Hope you like it.

KJM

This topic is closed to new replies.

Advertisement