I have created enemies that chase the player around a game, but there is a problem. The enemies are too perfect and quickly converge on each other when they get close to the player. This is because they just move in the direction of the player each time the game updates.
I would like to introduce some randomness into the enemies, probably with the angle of motion. This is what I have so far (I haven't optimized it as it's not done yet, so I'm aware of the high overhead):
Angle = (float)Math.Atan2((HeroPosition - Position).Y, (HeroPosition - Position).X)// Positions are Vector2s
GlobalForce Propellant = new GlobalForce((float)Math.Cos(Angle) / 2, (float)Math.Sin(Angle) / 2);
ApplyForce(Propellant);
If I try to add a random number to the angle there are a couple of problems:
They all get updated so quickly after each other that the seed time is the same for all of them
The random number is so different on each update that the angle of the enemy jumps around erratically.
So what I want to know is: How do most games get around this problem? How should I make the enemies take different paths (without having access to the list of other enemies)?
EDIT:
This is the code I am using after the suggestions below for future passers by:
Angle = (float)Math.Atan2((HeroPosition - Position).Y, (HeroPosition - Position).X);
GlobalForce Propellant = new GlobalForce((float)Math.Cos(Angle) / 2, (float)Math.Sin(Angle) / 2);
ApplyForce(Propellant);
foreach (Enemy e in OtherEnemies)
{
if (e != this)
{
if ((e.Position - Position).Length() < 64)
{
float angleBetween = MathHelper.TwoPi-(float)Math.Atan2((e.Position-Position).Y, (e.Position-Position).X);
GlobalForce avoidance = new GlobalForce((float)Math.Cos(angleBetween)*2, (float)Math.Sin(angleBetween)*2);
ApplyForce(avoidance);
}
}
}
A significant portion of AI tactics (as well as human tactics BTW) is not only knowing and acting on where the enemy is, but also knowing and acting on where your allies are. Most of the simplest and most well-known maneuvers are impossible without that (think encirclement).
Much of this comes down to "dont' get too close to an ally, if you can avoid it".
So basically what you need to do is manage your force in a way, that it is not only attracted by the enemy, but also rejected by an ally (less so). Combine this with a two-stage wayfinder and you're done.
Most games get around this by having the enemies block each other, so that they don't move onto the same space.
This can be implemented as either a hard constraint (e.g. only one enemy is allowed in each square, no other enemies can move into an already occupied square) or a soft constraint (some hidden "force" that pushes enemies apart if they get too close to each other).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With