Game Development Community

Ai Finding Cover

by Bryce · in Technical Issues · 05/27/2007 (5:26 am) · 38 replies

Has anybody figured out how to make AI find cover from an enemy???? I would love to know.


Thanks
Page «Previous 1 2
#1
05/27/2007 (6:14 am)
BrYcE,

If you're using the Killer Kork resource, you might want to take a look at the ammo and healthpatch seeking scripts. You should be able to extrapolate new behavior from those examples.

There are other ways, of course, but that is one approach.

AaRoN
#2
05/27/2007 (6:43 am)
Bryce,
I have an old power point presentation I found while googling for half-life a.i., lots of pictures and logic formulas, it's a very good presentation and pretty easy to understand, if your interested, shoot an email to my account email address and i'll send it on it's way.
#3
05/27/2007 (8:49 am)
Hi Chris plz send to me this presentation on waleedot2003@gmail.com
thank you very mutch
#4
05/27/2007 (12:38 pm)
@aaron: yes, I am using killer kork.
@chris: email, coming right up
#5
05/27/2007 (12:46 pm)
BrYcE,

There is a really good article up on TDN that might be a big help to you as well. I'm not sure if you have TDN access, though.
#6
05/27/2007 (6:03 pm)
The simplest way of doing this would be:

First, run to a random point any between 1 to 20 units away.

Then, cast a ray from you to the attacker. If the ray did not reach, you found cover, else repeat steps one and two.

example:
function AIPlayer::findCover(%this)
{
   %x = getRandom(-25, 25);
   %x = firstWord(%this.getPosition()) + %x);

   %y = getRandom(-25, 25);
   %y = getWord(%this.getPosition(), 1) + %y);

   %this.setMoveDestination(%x SPC %y SPC "0");
}
Then add this in your AI's onReachDestination" function:
%start = %obj.getWorldBoxCenter();
   %end = %attacker.getWorldBoxCenter();
   %mask = $TypeMasks::PlayerObjectType;
   
   if (ContainerRayCast(%start, %end, %mask, %obj))
      %obj.findCover();
I'm not entirely sure this will work for you, but I hope it helps.
#7
05/28/2007 (2:55 am)
My AI are more tactical, so they are going to be right up against the cover so he can poke his gun over the top or side of it (Soon as I get access to the c++. No, I can't use TDN). Is it possible to check in the rayCast what the first thing preventing it from reaching (starting from the attacker) is? I'm thinking that then I would be able to change that point along a vector to the enemy, somehow aligning it with the enemy?

Here is his situation:
img91.imageshack.us/img91/44/21059121dl9.pngPossible cover points. See how they're taking up empty space?
img152.imageshack.us/img152/4913/47987391ra3.pngI choose this one:
img149.imageshack.us/img149/8615/21238467ur7.pngThe vector to the enemy:
img152.imageshack.us/img152/2079/45710876yj9.pngNew point along that vector, right up against that cover.
img149.imageshack.us/img149/9724/13692019qn6.png
Then he transits to that point.


p.s. this was my hardest-worked on post EVER
#8
05/28/2007 (2:56 am)
Sorry you can't read the text on the first pic. The blue lines are pointing to cover objects. Blue dot is player, red dot is enemy
#9
05/28/2007 (3:11 am)
@Caleb
In the containerRayCast (just in case any other poeple are trying your method), wouldn't you want to have it before you make him run all the way over there? When I'm being shot at (Hope it never comes to that!), I wouldn't really be darting from here to there, stopping, saying "Am I still being shot at? YES? Shazbot!" and then running somewhere else.

And another thing: %masks should have other things than PlayerObjectType. Doing that, he would end up taking cover behind a teammate, which works, but is incredibly mean.

Yet again another thing: Insert a for loop in the findCover() function of yours. That way you can pick more than one point, like 40, and you have better chances of seeing cover. Ahem:
function AIPlayer::findCover(%this)
{   
   for (%i = 0; %i < 40; %i++)
   {
      %x = getRandom(-25, 25);   
      %x = firstWord(%this.getPosition()) + %x);   
      %y = getRandom(-25, 25);   
      %y = getWord(%this.getPosition(), 1) + %y);   
      %start = %obj.getWorldBoxCenter();   
      %end = %attacker.getWorldBoxCenter();   
      %masks = $TypeMasks::InteriorObjectType, $TypeMasks::VehicleObjectType, $TypeMasks::StaticTSObjectType;
      if (ContainerRayCast(%start, %end, %masks, %obj))    
      {  
         // And the for loop continues
      }
      else
      {
         %this.setMoveDestination(%x SPC %y SPC "0");
         return;       // We don't want him to keep going with the for loop and find more cover when in transit.
      }
   }
}
EDIT: Parsing
#10
05/28/2007 (6:50 am)
Bryce, your absolutely right. I just remembered that about %mask and was coming to repost. If you called the findCover function when he was shot, (or shot at), he would keep running around randomly until there is something between him and is enemy.

I didn't intend for this to be used as I never tried so I don't know if it would work. To make him see if were he wants to run is in cover before he runs there, try something more like this:
function AIPlayer::findCover(%this, %attacker)
{   
   %x = getRandom(-25, 25);   
   %x = firstWord(%this.getPosition()) + %x);   
   %y = getRandom(-25, 25);   
   %y = getWord(%this.getPosition(), 1) + %y);   
   %start = %x SPC %y SPC getTerrainHeight(%x SPC %y) + 3;   
   %end = %attacker.getWorldBoxCenter();   
   %masks = $TypeMasks::InteriorObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticTSObjectType;

      if (ContainerRayCast(%start, %end, %masks, %obj))    
      {
         //The ray hit, heres a good spot  
         %this.setMoveDestination(%start);
      }
      else
      {
         %this.findCover(%attacker);
      }
}
If all goes well upon calling this function, the AI should keep looking until he finds cover. And it is a good idea to have a for loop in there, if he is in an open field, he would keep calling this function forever.

Good luck. :)
#11
05/28/2007 (8:06 am)
You may want to switch the code in your if and else statements. What it would do is send the AI Player off to the destination that has a successful raycast, meaning exposure to enemy fire, and if the raycast fails, call the function again!

Try this instead:
if ([b]![/b]ContainerRayCast(%start, %end, %masks, %obj))

And also, calling the function over and over again in an open field when there is actually no cover may freeze or slow the game down. IMO, a for loop is better. It can check x number of times, and if none work, then maybe have him empty out his magazine at full rate in hopes of taking the threat(s) out.
#12
05/28/2007 (2:13 pm)
ContainerRayCast returns the ID of any thing it hits, and nothing if the ray did not hit any thing. If the ray did not collide, theres nothing between you and the attacker, your a sitting duck. If it did collide, theres something in the way which you can hide behind.

Emptying the magazine sounds like a good idea, if you can't hide, neither can they.
#13
05/28/2007 (2:28 pm)
Okay. We have all that aside. What I'm trying to do now is eliminate all that space between the chosen point and the cover. Look at my post with the little thumbnails. Before I have the AI transit to the point, I want to move the point along that direction until it is right against that cover. Follow me?

I'm thinking I could work on this by using a ContainerFindFirst from the %start to figure out what the RayCast is hitting. That is easy, but how would I calculate where to put the new point that's pushed against cover? In other words, how can I move it along a certain direction?
#14
05/29/2007 (6:33 am)
OKAY! MOMENT OF PURE GENIUS!
function AIPlayer::findCover(%this, %attacker)
{      
      %x = getRandom(-25, 25);
      %x = firstWord(%this.getPosition()) + %x);
      %y = getRandom(-25, 25);
      %y = getWord(%this.getPosition(), 1) + %y);
      %start = %x SPC %y SPC getTerrainHeight(%x SPC %y) + 3;
      %end = %attacker.getWorldBoxCenter();
      %masks = $TypeMasks::InteriorObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticTSObjectType;
      if (ContainerRayCast(%start, %end, %masks, %obj))
      {
           [b]%cover = ContainerFindFirst($TypeMasks::InteriorObjectType | $TypeMasks::VehicleObjectType | $TypeMasks::StaticTSObjectType, %start, getWord(%end,1),getWord(%end,2),getWord(%end,3));
           %coverPos = %cover.getTransform():
           // Get X space between start and attacker
           %totalX = getWord(%start,1) - getWord(%end,1)
           // Get X space between player and cover
           %coverX = getWord(%start,1) - getWord(%coverPos,1);
           // Get X scale factor
           %scaleX = %totalX/%coverX;

           // Get Y space between start and attacker
           %totalY = getWord(%start,2) - getWord(%end,1);
           // Get Y space between player and cover
           %coverY = getWord(%start,2) - getWord(%coverPos,2);
           // Get Y scale factor
           %scaleY = %totalY/%coverY;

           // Scale down X and get new position
           %scaledX = %totalX/%scaleX;
           %newX = getWord(%start,1) - %scaledX;
           
           // Your turn, Y!
           %scaledY = %totalY/%scaleY;
           %newY = getWord(%start,2) - %scaledY;

            // Throw it all together....
            %flatPos = %newX SPC %newY;
            %terrHeight = GetTerrainHeight(%flatPos);
            %movePoint = %newX SPC %newY SPC %terrHeight;
            // Get moving!
            
            %this.setMoveDestination(%movePoint);[/b]
      }
      else
      {
           %this.findCover(%attacker);
      }
}

Somebody please test this for me? My Torque laptop is having a very annoying power issue.

EDIT: If/else stupidity
#15
05/31/2007 (2:28 pm)
Anyone?
#16
06/01/2007 (7:30 am)
I tried testing it, but my AI code keeps interfering. It would take forever to temporarily disable everything I've put in my AI, Sorry.

I did notice one thing though, when using getWord, 0 is always the first word. So to get the X pos, use getWord(%start, 0).

Nice job on the code!!! I hope you get your laptop working. :)
#17
06/01/2007 (2:36 pm)
I do too, thanks!

You think they do that just to mess with people's minds! When the second argument is set to 1, you think "1st word of argument one." But noooooo...... :-)
#18
06/14/2007 (12:03 pm)
Okay. We can make that code simpler using some vectoring , but how do I find out the exact point where the RayCast hits the cover object? When we get the position of the cover, it returns the center of the object. That would mess up my AI. If we are inside a building and the RayCast hits a support beam that is part of the entire interior, we would need the point of intersection so we run up to the support, not somewhere else that calculates the center of the entire interior!

That was probably clear as mud.....
#19
06/15/2007 (6:13 am)
I made a pathfinding resource that does that, example:
%ray = ContainerRayCast(%startPos, %endPos, %mask);
   %collPos = getWords(%ray, 1, 3);
I believe that should do it.
#20
06/15/2007 (12:28 pm)
I thought RayCast returns the object id?
Page «Previous 1 2