Page 1 of 1

[Enemy AI] Need some advice

Posted: Sun Oct 23, 2011 2:26 pm
by DTKilb
I'm currently making AI for zombies in an overhead shooter.
The zombie's task is to come into close combat with the player, and this works, so my question is if there is any possible way to improve this walking path, because I'm afraid if I add multiple zombies into a map they will walk in unison directions and it may look a bit weird. I left comments in the code to make it a little bit more clear.

Also, this is all under an "enemy" class, and in order for me to implement multiple zombies, I create multiple instances like so:

Code: Select all

enemy zombie1(/*all of the initializing stats such as speed*/);
enemy zombie2(/*all of the initializing stats such as speed*/);
Straight to the point: There aren't any errors or bugs with this code, I just want advice for more efficient ways.
Anyways, here is the walking path code:

Code: Select all

int a1 = player::playerX - enemyX;
int a2 = player::playerY - enemyY;

if(a1 < -5){
	enemyX-=speed; // If the zombie is to the right of the player, then move left
} else if(a1 > 5){
	enemyX+=speed; // If the zombie is to the left of the player, then move right
} else if((a1 > -5 || a1 < 5) && a2 < 0){
        enemyY-=speed; //If you are under the player, and you are in the range of the x axis to attack, them move up
} else if((a1 > -5 || a1 < 5) && a2 > 0){
        enemyY+=speed; //If you are above the player, and you are in the range of the x axis to attack, them move down
}

Re: [Enemy AI] Need some advice

Posted: Sun Oct 23, 2011 3:19 pm
by dandymcgee
A picture, video, or compiled executable would definitely help us to visualize your algorithm in the context of your game.

Re: [Enemy AI] Need some advice

Posted: Mon Oct 24, 2011 4:09 am
by ismetteren
dandymcgee wrote:A picture, video, or compiled executable would definitely help us to visualize your algorithm in the context of your game.
I think the zombies are just moving towards the player, and he want to stop them from balling too much up, right?

I read a book called "Programming Game AI By Example". That book had a chapter about steering behaviors

The idea is, that you calculate a bunch of vectors, in this example, you would have one going from the zombie in the direction of the player(arrive), and one that repulses the zombie from other zombies(seperation). Then you add these two together(and probably truncating it). Then you can use this vector as an acceleration.

I'm not really 100% sure about excatly how it is done, but i found this: http://www.red3d.com/cwr/steer/ (and the full article: http://www.red3d.com/cwr/steer/gdc99/). You could offcourse also get the book...

But the behaviors you would use, i think, is arrival and seperation.

Re: [Enemy AI] Need some advice

Posted: Mon Oct 24, 2011 6:00 am
by Van-B
One technique I've found that can help, is detecting if another zombie is in front of each zombie - and those zombies then move at a slower rate, or backwards, or if the zombie in front is moving slowly, sidestep. When I did this, the zombies would behave more intelligently, moving out of the way of eachother and swarming around their destination. I used standard box collision for speeds sake, with 256 zombies if I recall, didn't seem to affect performance too much doing all those box checks. You might not be able to guarantee that zombies won't collide with this method, instead they'll do their best to avoid it, which I think is a better option. There are more factors and problems with full on collision detection - for instance, say 2 zombies walk straight into eachother, with full collision they'd most likely stop and cause a bottleneck. If you have them move out of the way instead, then they would sidestep eachother. I'm sure I checked the angle difference between zombies too, to decide which way to sidestep.

Re: [Enemy AI] Need some advice

Posted: Mon Oct 24, 2011 6:38 am
by DTKilb
Van-B wrote:One technique I've found that can help, is detecting if another zombie is in front of each zombie - and those zombies then move at a slower rate, or backwards, or if the zombie in front is moving slowly, sidestep. When I did this, the zombies would behave more intelligently, moving out of the way of eachother and swarming around their destination. I used standard box collision for speeds sake, with 256 zombies if I recall, didn't seem to affect performance too much doing all those box checks. You might not be able to guarantee that zombies won't collide with this method, instead they'll do their best to avoid it, which I think is a better option. There are more factors and problems with full on collision detection - for instance, say 2 zombies walk straight into eachother, with full collision they'd most likely stop and cause a bottleneck. If you have them move out of the way instead, then they would sidestep eachother. I'm sure I checked the angle difference between zombies too, to decide which way to sidestep.
This seems to be a very good method, but I don't know how I'd do it as this is all in an "enemy" class and in order to make, for an example, 20 zombies, I have to update and initialize 20 instances of the "enemy" class. Perhaps I should find a different way to structure my AI other than in a class?

Re: [Enemy AI] Need some advice

Posted: Mon Oct 24, 2011 6:54 am
by superLED
DTKilb wrote:
This seems to be a very good method, but I don't know how I'd do it as this is all in an "enemy" class and in order to make, for an example, 20 zombies, I have to update and initialize 20 instances of the "enemy" class. Perhaps I should find a different way to structure my AI other than in a class?
Instead of doing:

Code: Select all

Enemy myEnemy1;
Enemy myEnemy2;
...
Enemy myEnemy20;
Why not making an array of enemies?

Code: Select all

Enemy enemies[20];
Or even vectors. That way you can expand and subtract enemy instances.

Code: Select all

vector<Enemy> enemies(20);
And to update them all:

Code: Select all

for(int i = 0; i < enemies.size(); i++) {
     enemies[i].update();
}

Re: [Enemy AI] Need some advice

Posted: Mon Oct 24, 2011 7:08 am
by Van-B
There is one other strange little option...

If you take your whole game world, and split it into a grid - not necesserily the same size as your tile grid (if you use one), maybe a grid that is about the right size to just squeeze one zombie into, with a container variable and a stamp variable. Then, each frame, you increment a stamp variable and after updating each enemy, you stamp the current stamp variable into the grid location along with an ID refering to the enemy.

Then, when moving your zombies, you can check this grid (or array) to see what is occupying that grid. If there's already a zombie stamped in there, then you know that the zombie should back pedal and find a free slot. One advantage with this is that it's really good for performance - pretty quick to check a 2D array compared to the other method I mentioned. I have found that arrays like that can be incredibly useful - for path finding, blocking areas, and it could be a shared array that your enemies class accesses and sets.

I mean, say you went for the grid array stamp idea - and say all the walls and solid areas are marked on the grid, now add in a direction variable, so each grid location also has a direction. Now, take the player and the surrounding 8 grid locations and have them all point to the player, and each loop expand an area around this, checking 'slots' with no direction, and setting that to point towards an neighboring slot with a direction... only resetting when the player moves to a slot with no direction (then you have to start again). You'd probably need an ID variable for that (maybe incrementing, so the zombs know how hot or cold the trail is, and which surrounding slot is the hottest), but what you'd end up with zombies that can get to the player no matter how complex a maze the player might be in. All the zombies would have to do is check their slot, if it has a direction, then set off, and the chain of slots would lead them right to the player. If the player was in a fenced area with a gate, the zombies wouldn't have a clue how to get to the player, but then if the gate was opened, then the direction flood fill would leak out of the fenced area, and get to the zombies - then they'd instantly know to run to the gate and get into the player. When the player moves to a different slot, maybe check the 5x5 slots around them, then each loop you'd scan the slots. Even if your game only runs at 30 fps, that's still enough to have any zombies on screen know how to get to you within a second. You could even have zombies find alternate routes if they end up blocking an entrance.

Personally, I enjoy the AI stage of coding a game, because it can really surprise you how effective a simple idea can be, it gets fascinating pretty quickly. Maybe would be useful to make a small demo to illustrate this properly, as I said this stuff can be a lot of fun to work on.

Re: [Enemy AI] Need some advice

Posted: Tue Oct 25, 2011 3:09 am
by Van-B
Ooooh! - I made a little demo of the moving back and straffing idea last night, and it works like a charm!. Really straightforward as well, I'll post up the basic code later. It's as if they fight to get to the player, swarm around and try and push their way in. Would work great for a zombie game.

Re: [Enemy AI] Need some advice

Posted: Tue Oct 25, 2011 2:08 pm
by ismetteren
Van-B wrote: Personally, I enjoy the AI stage of coding a game, because it can really surprise you how effective a simple idea can be, it gets fascinating pretty quickly. Maybe would be useful to make a small demo to illustrate this properly, as I said this stuff can be a lot of fun to work on.
If you haven't I think you should look into steering behaviors. I find it kind of amazing, especially flocking behavior, which is the combination of the steering behaviors: Separation, alignment and cohesion. http://www.youtube.com/watch?v=Qk-O4C17 ... re=related this video also has some other steering behaviors in the end(the last one actually looks a little bit like zombies :) ).

I'm not saying that steering behaviors necessarily should be used in the game, just mentioning that they are cool ;)

Also, this video is nice: http://www.youtube.com/watch?v=SeL9HZE8 ... re=related

Re: [Enemy AI] Need some advice

Posted: Wed Oct 26, 2011 2:41 am
by Van-B
Yeah, those videos are pretty cool - I like the one with the predators, they react so realisticaly. I wish that they'd add these advanced AI behaviours to games already... seems like all enemies ever do is follow waypoints or charge right at the player, even in the most modern games.

The demo I'm doing actually looks a lot like the zombie part, with the circles and lines. I found that when the zombs react with eachother and bunch up, they form little queues that spread out and surround the player, but that happens a bit too slowly. What I'm planning on doing is have zombies turn away from eachother, so they sidestep but also try to walk around the zombie in front. I tried that with a lame fix yesterday, and now when 2 zombies get too close, they start to dance around eachother!. I have made them move faster depending on how far they are from the player, thats really effective. Right now they tend to funnel down while moving towards the player, I'm thinking that some turning interference will help spread that out.
I guess what I'm trying to do is make an example of zombie logic that sticks closely to very basic principles that can be applied to any language and don't involve any heavy math (I'm allergic). Zombie logic written on a cocktail napkin, if you like.

Re: [Enemy AI] Need some advice

Posted: Wed Oct 26, 2011 4:35 am
by ismetteren
Van-B wrote:Zombie logic written on a cocktail napkin, if you like.
That... is a really cool sentence ;)

Good luck with the zombies.

Re: [Enemy AI] Need some advice

Posted: Thu Nov 03, 2011 8:44 pm
by Light-Dark
superLED wrote:
DTKilb wrote:
This seems to be a very good method, but I don't know how I'd do it as this is all in an "enemy" class and in order to make, for an example, 20 zombies, I have to update and initialize 20 instances of the "enemy" class. Perhaps I should find a different way to structure my AI other than in a class?
Instead of doing:

Code: Select all

Enemy myEnemy1;
Enemy myEnemy2;
...
Enemy myEnemy20;
Why not making an array of enemies?

Code: Select all

Enemy enemies[20];
Or even vectors. That way you can expand and subtract enemy instances.

Code: Select all

vector<Enemy> enemies(20);
And to update them all:

Code: Select all

for(int i = 0; i < enemies.size(); i++) {
     enemies[i].update();
}

How Would one convert his array system to vectors? im thinking of converting so i dont have to have things off in some dark place to hide from the player?