AI related

Started by
3 comments, last by 3Dgonewild 15 years, 12 months ago
Hi. I decided to use my 2d/3d "engine"(well ,sort off..i just like how it sounds) , and to create something out of it(got bored with demos :). I decided to create something related with AI, so , i ended up coding a simple shooter. Right now im in the most important part of the AI system , and i stuck badly. First of all , here's how the system works:

-load script file which contains position data , and at which time the enemy should appear
-load basic textures
-render each object 

--main loop--
while running
 switch state 
clear screen
handle events
case main game
execute script
handle ai + render
end
swap buffers


Everything works as expected , except one thing that i could never imagine. I have a class named CEnemyList. The class has a method "update()", which handles ai & renders the enemies. Now , what happens. As you can see , enemies trying to reach player's position. It works well with just 1 enemy....but guess what happens with 20 enemies...lol. Still can't figure out? Then let me tell you. The enemies keep moving at a constant speed until they catch up with player, and after a little while they end up at the same position. Really lame. I've been trying to think a way to move them in groups , without covering each other. Anyone can help me out on this?...IM LOST(4th season :) )... Here's the troublesome code...

void CEnemyList::update(const int ai_op,const CBox& player_pos,const unsigned time_now)
	{
		if(enemies.empty())return;
		for(std::vector<CEnemyAttributes>::iterator it=enemies.begin(); it!=enemies.end();it++)
		{
			switch(it->getState())
				{
//========================follow state
				case AI_ENEMY_STATE_FOLLOW://follow the player
					{
	 				 
					if(it->box.angle > player_pos.angle)
						{
						it->box.angle -=6;
						}
					if(it->box.angle < player_pos.angle)
						{
						it->box.angle +=6;
						}

					if(it->box.x > player_pos.x)
						{
						it->box.x -= it->box.xvel;
						}
					if(it->box.x < player_pos.x)
						{
						it->box.x += it->box.xvel;
						}
					if(it->box.y > player_pos.y)
						{
						it->box.y -= it->box.xvel;
						}
					if(it->box.y < player_pos.y)
						{
						it->box.y += it->box.yvel;
						}
					}
					break;
				}//switch

 
				if(it->getType() == ENEMY_TYPE_A)
					{
					enemy_type_a.draw(it->box);
					}
				}//for
	}


Advertisement
you need to implement some collition detection and some path finding, basically, path finding figures out how to get from point a to point b while going around an obstacle. what collition detection does is basically flag an area as obstacled (where the other fellow enemy is)

[edit] a quick fix would be to calculate where the enemy will move next, then check evey other enemy on the list and make sure no one is at that desired position RANGE, and only move the enemy if the desired position is avaliable, that is a pretty basic way of tackling the problem and it will create invisible bottlenecks if enemies start to gather up at the same point
If your enemies are moving in a clear environment (as opposed to a maze-like environment or having to navigate around the level geometry), I'd say you don't really need to go with pathfinding, as most if not all the obstacles they need to avoid will be dynamic ones (their own comrades).

In this case, I'd instead add some level of steering or flocking behaviour to your enemies. A force that attracts them towards the goal, combined with a force that repels them from each other should do the work. You can find more about steering behaviours in the paper by Craig Reynolds, and in Programming Game AI by Example

Please note that even when the enemies will space out more naturally, this solution will not ensure zero overlapping. If you need that, you should look into some kind of collision detection system.

Hope it helps!
-----DevZing Blog (in Spanish)
Thanks for the replies.


The enemies simply navigate around the map , and they attack player or trying to avoid any incoming attacks.

Sante , i looked at your 1st link , but looks too complicated for what im trying to do.
I need something really simple :).

Anyway , i've coded a function (similar to rect collision detection) , but didn't work as expected.
I've also tried various methods to get the desired effects , but at the end the movement looks choppy :).

Here , im posting the source for those who're interested.



	inline void dontTouchMe(CBox& a,CBox& b)	{ 		float leftA,leftB,rightA,rightB,		      topA,topB,bottomA,bottomB;		//'a' box		leftA = a.x;		rightA = (a.x + a.w);		topA = a.y;		bottomA = a.y + a.h;		//'b' box		leftB = b.x;		rightB = (b.x + b.w);		topB = b.y;		bottomB = (b.y + b.h);		if(bottomA  <= topB)			{			a.yvel += b.h/2;			b.yvel -= b.h/2;			}		if(topA >= bottomB)			{			a.yvel -= b.h/2;			b.yvel += a.h/2;			}		if(rightA <= leftB)			{			a.xvel += b.w/2;			b.xvel -= a.w/2;			}		if(leftA >= rightB)			{			a.xvel -= b.w/2;			b.xvel += a.w/2;			} 	}


And here's my second attempt ( check if 'a' touching 'b' , and adjust their velocity)

void CEnemyList::update(const int ai_op,const CBox& player_pos,const unsigned time_now)	{		if(enemies.empty())return; 		 std::vector<CEnemyAttributes>::iterator next = enemies.begin();		for(std::vector<CEnemyAttributes>::iterator it=enemies.begin(); it < enemies.end();it++)		{			next = it++;			 			switch(it->getState())				{//========================follow state				case AI_ENEMY_STATE_FOLLOW:					{	 				  					 					if(it->box.angle > player_pos.angle)						{						it->box.angle -=2 ;						} 					if(it->box.angle < player_pos.angle)						{						it->box.angle +=2  ;						}				 	  if(next < enemies.end())				 		{					if( collidesWith(it->box,next->box)  )				 		{					next->box.xvel += it->box.w/6;					next->box.yvel += it->box.h/6;				 	it->box.xvel -= next->box.w/6;				 	it->box.yvel -= next->box.h/6;				 		}				 		} 					if(it->box.xvel > 1.0f) it->box.xvel = 1.0f;					if(it->box.yvel > 1.0f) it->box.yvel = 1.0f;					 if(it->box.x > player_pos.x - player_pos.w/2)						{						it->box.x -= it->box.xvel;//  + (float)(rand()%(int)it->box.w/6)+1;						} 					if(it->box.x < player_pos.x+ player_pos.w/2)						{						it->box.x += it->box.xvel ;//  + (float)(rand()%(int)it->box.w/6)+1;						} 					if(it->box.y > player_pos.y - player_pos.h/2)						{						it->box.y -= it->box.xvel ;//  + (float)(rand()%(int)it->box.w/6)+1;						} 					if(it->box.y < player_pos.y + player_pos.h/2)						{						it->box.y += it->box.yvel ;//  + (float)(rand()%(int)it->box.w/6)+1;						} 					}					break;				}//switch 				applyBorderCollision(it->box);				 				if(it->getType() == ENEMY_TYPE_A)					{					enemy_type_a.draw(it->box);					} 				 				 				}//for	}
Heh , i solved my problem.
How?...i just added basic physics , and works like a charm :)

This topic is closed to new replies.

Advertisement