Reputation: 4708
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);
}
}
}
Upvotes: 4
Views: 2224
Reputation: 106351
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).
Upvotes: 2
Reputation:
An intermediate solution is to have different strategies for the different AI's. e.g. one AI that homes in on where the player is now, another AI that homes in on where the player is going, another that habitually tries to hang out a few units South of the player, except when the player is moving straight for it, ....
It's not as good as having a strategy where your AI's take into account where their friends are, but (when written properly) it will have them behave differently.
Upvotes: 2
Reputation: 25619
Last year I had to code a PACMAN game for one of the courses I took
I used the A-Star search algorithm for the enemies
Running this algorithm straight-forward will yield perfect enemies.
The trick is to add some randomness to the outcome of the algorithm - make the enemy 'make mistakes' as the difficulty level goes down (i.e. go to a different direction than the algorithm yielded, as the difficulty level lowers, the enemey makes more 'mistakes')
Upvotes: 1
Reputation: 65274
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.
Upvotes: 4