How to implement smooth flocking
- by Craig
I'm working on a simple survival game, avoid the big guy and chase the the small guys to stay alive for as long as possible.
I have taken the chase and evade example from MSDN create and drawn 20 mice on the screen.
I want the small guys to flock when they arent evading. They are doing this, but it isnt as smooth as I would like it to be. How do i make the movement smoother? Its very jittery.#
Below is what I have going at the moment, flocking code is within the IF statement, when it isnt set to evading.
Any help would be greatly appreciated! :)
namespace ChaseAndEvade
{
class MouseSprite
{
public enum MouseAiState
{
// evading the cat
Evading,
// the mouse can't see the "cat", and it's wandering around.
Wander
}
// how fast can the mouse move?
public float MaxMouseSpeed = 4.5f;
// and how fast can it turn?
public float MouseTurnSpeed = 0.20f;
// MouseEvadeDistance controls the distance at which the mouse will flee from
// cat. If the mouse is further than "MouseEvadeDistance" pixels away, he will
// consider himself safe.
public float MouseEvadeDistance = 100.0f;
// this constant is similar to TankHysteresis. The value is larger than the
// tank's hysteresis value because the mouse is faster than the tank: with a
// higher velocity, small fluctuations are much more visible.
public float MouseHysteresis = 60.0f;
public Texture2D mouseTexture;
public Vector2 mouseTextureCenter;
public Vector2 mousePosition;
public MouseAiState mouseState = MouseAiState.Wander;
public float mouseOrientation;
public Vector2 mouseWanderDirection;
int separationImpact = 4;
int cohesionImpact = 6;
int alignmentImpact = 2;
int sensorDistance = 50;
public void UpdateMouse(Vector2 position, MouseSprite [] mice, int numberMice, int index)
{
Vector2 catPosition = position;
int enemies = numberMice;
// first, calculate how far away the mouse is from the cat, and use that
// information to decide how to behave. If they are too close, the mouse
// will switch to "active" mode - fleeing. if they are far apart, the mouse
// will switch to "idle" mode, where it roams around the screen.
// we use a hysteresis constant in the decision making process, as described
// in the accompanying doc file.
float distanceFromCat = Vector2.Distance(mousePosition, catPosition);
// the cat is a safe distance away, so the mouse should idle:
if (distanceFromCat > MouseEvadeDistance + MouseHysteresis)
{
mouseState = MouseAiState.Wander;
}
// the cat is too close; the mouse should run:
else if (distanceFromCat < MouseEvadeDistance - MouseHysteresis)
{
mouseState = MouseAiState.Evading;
}
// if neither of those if blocks hit, we are in the "hysteresis" range,
// and the mouse will continue doing whatever it is doing now.
// the mouse will move at a different speed depending on what state it
// is in. when idle it won't move at full speed, but when actively evading
// it will move as fast as it can. this variable is used to track which
// speed the mouse should be moving.
float currentMouseSpeed;
// the second step of the Update is to change the mouse's orientation based
// on its current state.
if (mouseState == MouseAiState.Evading)
{
// If the mouse is "active," it is trying to evade the cat. The evasion
// behavior is accomplished by using the TurnToFace function to turn
// towards a point on a straight line facing away from the cat. In other
// words, if the cat is point A, and the mouse is point B, the "seek
// point" is C.
// C
// B
// A
Vector2 seekPosition = 2 * mousePosition - catPosition;
// Use the TurnToFace function, which we introduced in the AI Series 1:
// Aiming sample, to turn the mouse towards the seekPosition. Now when
// the mouse moves forward, it'll be trying to move in a straight line
// away from the cat.
mouseOrientation = ChaseAndEvadeGame.TurnToFace(mousePosition, seekPosition,
mouseOrientation, MouseTurnSpeed);
// set currentMouseSpeed to MaxMouseSpeed - the mouse should run as fast
// as it can.
currentMouseSpeed = MaxMouseSpeed;
}
else
{
// if the mouse isn't trying to evade the cat, it should just meander
// around the screen. we'll use the Wander function, which the mouse and
// tank share, to accomplish this. mouseWanderDirection and
// mouseOrientation are passed by ref so that the wander function can
// modify them. for more information on ref parameters, see
// http://msdn2.microsoft.com/en-us/library/14akc2c7(VS.80).aspx
ChaseAndEvadeGame.Wander(mousePosition, ref mouseWanderDirection, ref mouseOrientation,
MouseTurnSpeed);
// if the mouse is wandering, it should only move at 25% of its maximum
// speed.
currentMouseSpeed = .25f * MaxMouseSpeed;
Vector2 separate = Vector2.Zero;
Vector2 moveCloser = Vector2.Zero;
Vector2 moveAligned = Vector2.Zero;
// What the AI does when it sees other AIs
for (int j = 0; j < enemies; j++)
{
if (index != j)
{
// Calculate a vector towards another AI
Vector2 separation = mice[index].mousePosition - mice[j].mousePosition;
// Only react if other AI is within a certain distance
if ((separation.Length() < this.sensorDistance) & (separation.Length()> 0) )
{
moveAligned += mice[j].mouseWanderDirection;
float distance = Math.Abs(separation.Length());
if (distance == 0) distance = 1;
moveCloser += mice[j].mousePosition;
separation.Normalize();
separate += separation / distance;
}
}
}
if (moveAligned.LengthSquared() != 0)
{
moveAligned.Normalize();
}
if (moveCloser.LengthSquared() != 0)
{
moveCloser.Normalize();
}
moveCloser /= enemies;
mice[index].mousePosition += (separate * separationImpact) + (moveCloser * cohesionImpact) + (moveAligned * alignmentImpact);
}
// The final step is to move the mouse forward based on its current
// orientation. First, we construct a "heading" vector from the orientation
// angle. To do this, we'll use Cosine and Sine to tell us the x and y
// components of the heading vector. See the accompanying doc for more
// information.
Vector2 heading = new Vector2(
(float)Math.Cos(mouseOrientation), (float)Math.Sin(mouseOrientation));
// by multiplying the heading and speed, we can get a velocity vector. the
// velocity vector is then added to the mouse's current position, moving him
// forward.
mousePosition += heading * currentMouseSpeed;
}
}
}