Game Development Community

Help creating sentery turret AI

by Paul Mieksztyn · in Torque Game Engine · 02/24/2010 (2:08 pm) · 7 replies

I am trying to make a game where the player can create turrets to shoot enemies, and I am having trouble getting it to work. (using 1.5.2 starter.fps)
// mask of visible objects reported in visList
$AIPlayer::VisObjMask = 
  $TypeMasks::PlayerObjectType |
  $TypeMasks::ProjectileObjectType |
  $TypeMasks::ItemObjectType;

// mask of opaque objects (things that block vision)
$AIPlayer::VisOpaqueMask = 
  $TypeMasks::PlayerObjectType |      // players
  $TypeMasks::TerrainObjectType |     // dirt, but not water
  $TypeMasks::StaticTSObjectType |    // trees and whatnot
  $TypeMasks::InteriorObjectType;     // walls

// mask of visible objects reported in the fastList (subset of $AIPlayer::VisObjMask)
$AIPlayer::VisFastMask = $TypeMasks::ProjectileObjectType;

// all visible objects
$AIPlayer::VisAllMask = $AIPlayer::VisOpaqueMask | $AIPlayer::VisObjMask;

datablock PlayerData(turretBase : defaultPlayer){
   maxInv[CrossbowAmmo] = 50;
   maxInv[Crossbow] = 1;
   
   maxVisDis = 50;
   
   Team = "Players";
};

function turretBase::onAdd(%this, %obj){
   %obj.setRechargeRate(%this.rechargeRate);
   %obj.setRepairRate(0);
   
   %obj.setInventory(Crossbow,1);
   %obj.setInventory(CrossbowAmmo,50);
   %obj.mountImage(CrossbowImage,0);   
   
   
   
   %obj.turretStartup();
}

function AIPlayer::turretStartup(%this) {
   
   echo("Turret-" @ %this @ " is online");
   
   //%this.schedule(2000, "lookForTarget");
}

function AIPlayer::lookForTarget(%this){
   
   if(!(%target = %this.closestTarget())){
      //echo("No Target!");
      %this.fire(false);
      %this.schedule(100, "lookForTarget");
      return;
   }
   //echo(%target);
   %this.aimAt(%target);
   %this.fire(true);
   
   %this.schedule(100, "lookForTarget");
}

function AIPlayer::closestTarget(%this){
   
   initContainerRadiusSearch(%this.getEyePoint(), %this.getDataBlock().maxVisDis, $AIPlayer::VisOpaqueMask);
   
   %closestDistance = %this.getDataBlock().maxVisDis + 1;
   
   %bestTarget = false;   
   
   while( isObject(%obj = containerSearchNext()) )
   {
      if (%obj & $TypeMasks::PlayerObjectType){
         echo(%obj);         
         if(%obj.getDatablock().Team !$= %this.getDataBlock().Team)
         {
            %rad = containerSearchCurrRadiusDist();
            if ( %rad < %closestDistance)
            {
               %closestDistance = %rad;
               
               %bestTarget = %obj;
            }
         }
      }
   }
   
   return %bestTarget;
}

I know that I am on the right track but right now, but currently there a problem with the "closestTarget" function in that it does not seem to return anything.


though if someone could brief me in how to get an AI to find the closest(or farthest) visible enemy target within a specific range, and start shhoting at them; that would be good too.

About the author


#1
02/24/2010 (4:09 pm)
For an example of a target selection function you can check out the Improved AI Guard Unit. And of course The Universal AI Starter Kit actually comes with a "turret" behavior mode.
#2
02/24/2010 (7:13 pm)
Quote:%obj & $TypeMasks::PlayerObjectType
Incorrect usage here - %obj is a handle, not a typemask. You'll need to do something like %obj.getTypeMask() instead - I'm not exactly sure if that's the right function, but have a search around ;).
#3
02/25/2010 (7:45 am)
Thanks guys! It works well enough now, here is what I changed:

function AIPlayer::lookForTarget(%this, %obj){
   
   if(!(%target = %obj.closestTarget(%obj))){
      //echo("No Target!");
      //%obj.fire(false);
      %obj.setImageTrigger(0,false);
      %obj.setAimLocation(%obj.getTransform());
      %obj.schedule(100, "lookForTarget", %obj);
      return;
   }
   %obj.aimAt(%target);
   %obj.setImageTrigger(0, true);
   //%obj.fire(true);
   
   %obj.schedule(100, "lookForTarget", %obj);
}

function AIPlayer::CheckLOS(%this, %obj, %tgt)
{
	%eyeTrans = %obj.getEyeTransform();
  %eyeEnd = %tgt.getEyeTransform();
  %searchResult = containerRayCast(%eyeTrans, %eyeEnd, $TypeMasks::PlayerObjectType |
  $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType, %obj);
	%foundObject = getword(%searchResult,0);
	
	if(%foundObject && %foundObject.getType() & $TypeMasks::PlayerObjectType && %foundObject.getDatablock().Team !$= %obj.getDataBlock().Team)
		{
		return true;
		}
	else
		{
		return false;
		}
}


function AIPlayer::closestTarget(%this, %obj){
   
   initContainerRadiusSearch(%obj.getEyePoint(), %obj.getDataBlock().maxVisDis, $TypeMasks::PlayerObjectType);
   
   %closestDistance = %obj.getDataBlock().maxVisDis + 1;
   
   %bestTarget = false;   
   
   while( isObject(%trg = containerSearchNext()) )
   {
      //echo(%obj);
      if(%obj.CheckLOS(%obj, %trg))
      {         
         if(%trg.getDatablock().Team !$= %obj.getDataBlock().Team)
         {
            %rad = containerSearchCurrRadiusDist();
            if ( %rad < %closestDistance)
            {
               %closestDistance = %rad;
               %bestTarget = %trg;
            }
         }
      }
   }
   
   return %bestTarget;
}
#4
02/25/2010 (4:46 pm)
Trust me, I would get the Universal AI Kit.

It's the most flexible add-on I've ever used.
#5
02/25/2010 (9:48 pm)
Not sure if your intended functionality is all there... you're saying that the target is in LOS if the raycast hits something... which is faulty. You might be seeing correct results because the ray is hitting your target object.
#6
02/28/2010 (2:22 pm)
I wasn't planning on getting the universal AI kit because this is for an in-class project, and i wanted to figure this out for myself

also, I do have my intended functionality, currently I can place a turret in an area where targets are blocked by terrain until they are very close, then when they round the corner, my turret unloads on them. I added the "%foundObject &&" to the start of CheckLOS's if-statement because of an output error I would revive before doing so.

the next step for me is to add functionality to the closestTarget function in order for me to pick the farthest target instead. I got plans for 3 types of turrets in the game, a machine-gun and shotgun turret that prioritize the closest target, and then a sniper turret that prioritizes the farthest target within it's range. should not be too hard now though.
#7
02/28/2010 (2:40 pm)
Sorry about that - yes, I see how it works now. I would have done it slightly differently, but your way will actually let the turret fire at enemies blocking the LOS of the intended target. It's not a pure 'LOS' test, but more of a 'safe to fire' test. Apologies :)