Game Development Community

dev|Pro Game Development Curriculum

Turret & AITurret classes, Version 1.20

by Brian Howard · 03/14/2004 (9:33 am) · 131 comments

Download Code File

Included in this archive are the original files and the files modified to work with 1.20 version. Most files did not have to be modified. Files that were modified were saved as a new file in an originalname_1_20.ext format. For example, trigger.cc had to be modified and the 1.20 code was saved as trigger_1_20.cc

I've maintained the same commenting format Paul used.

I've included the original turret_readme.txt file and an updated turret_readme_1_20.txt in the archive. The new readme file contains references for other fixes I found along the way. Please let me know if I missed a reference.

***I have not tested this on moving vehicles!

Hope the changes are helpful. I'll check back in, and do what I can to help out. This is my first posting, so let me know if there is a better way to communicate code updates.

About the author

Recent Blogs

#81
12/22/2007 (3:24 pm)
Well if you want to have AI turrets realize teams this should work. I haven't tested it much, but from what I can tell it works fine. If anybody has any troubles, post a comment here and I get sent an email.

So lets get started in engine/game/AITurret.cc

under

mTargetInLOS = false;

add

lastTarget = 0;

replace the bool AITurret::pickTarget() function with

/**
 * Pick a target from among objects in zone.
 */
bool AITurret::pickTarget()
{
   Point3F pos = this->getBoxCenter();

   // we pick closest target that is
   // in LOS and is at reachable angle
   GameBase *chosen = NULL;
   F32 dist = 1000000.0;
   U32 i;
   for (i = 0; i!= mObjects.size(); i++)
   {
	   
      GameBase* obj = mObjects[i];
      Point3F delta = pos - obj->getBoxCenter();
      F32 thisDist = delta.len();
      if (thisDist < dist && isInLOS(obj) && isReachableAngle(obj) && obj != mAimObject)
      {
         chosen = obj;
         dist = thisDist;
      }
   }

   if(chosen!=NULL){
	   lastTarget = i;
	   Con::executef(getDataBlock(), 3, "onTarget", scriptThis(),chosen->scriptThis());
   }

   return chosen != NULL;
}
bool AITurret::iterateTarget(){
   Point3F pos = this->getBoxCenter();

   // we pick closest target that is
   // in LOS and is at reachable angle
   GameBase *chosen = NULL;
   F32 dist = 1000000.0;
   U32 i;
   for (i = lastTarget; i!= mObjects.size(); i++)
   {
	   
      GameBase* obj = mObjects[i];
      Point3F delta = pos - obj->getBoxCenter();
      F32 thisDist = delta.len();
      if (thisDist < dist && isInLOS(obj) && isReachableAngle(obj) && obj != mAimObject)
      {
         chosen = obj;
         dist = thisDist;
      }
   }

   if(chosen!=NULL){
	   lastTarget = i;
	   Con::executef(getDataBlock(), 3, "onTarget", scriptThis(),chosen->scriptThis());
   }

   return chosen != NULL;
}

below that with all the other console methods put

ConsoleMethod( AITurret, iterateTarget, bool, 2,2, "ai.pickTarget();" )
{
   AITurret *ai = static_cast<AITurret *>( object );
   return ai->iterateTarget();
}

so now lets move over to AITurret.h

in class AITurret : public Turret under

U32               mCurrThinkingTick;

add

U32 lastTarget;

and under

bool pickTarget();

add

bool iterateTarget();

Okay so that should be all in the source code, now we need to do slight modifications to the script.
Head over to AITurret.cs

under

function AITurretData::onTargetChanged(%this,%turret, %oldTarget, %newTarget)
{
   //echo("AITurretData::onTargetChanged()");
}

add

function AITurretData::onTarget(%this,%turret, %newTarget)
{
   if(%newTarget.team == %turret.team){
      %turret.iterateTarget();
   }else{
      %turret.setTarget(%newTarget);
      %this.setupNextFire(%turret);
   }
}

replace the function 'function AITurretData::ChooseTarget(%this,%turret)' with

function AITurretData::ChooseTarget(%this,%turret)
{
  if (%turret.pickTarget()){
     %this.setupNextFire(%turret);
  }else {
     echo("failed to pick a target");
  }
}

well that should be it, let me know how it turns out. As I said before I'll be happy to work out any bugs.
#82
12/28/2007 (9:26 pm)
Thanks so much, I'll try that as soon as possible. =D
#83
01/10/2008 (10:43 am)
Brilliant :)

Master Treb: sounds good, but I can't figure out exactly what your code does. Probably not much of an issue if it works ;)

Kirk Longendyke: Thanks for the update :) I'd been wondering bout some of that code, but now I don't have to do any hard mental acrobatics. That should be merged into the resource.
EDIT: Just realised that's for TGEA :P. Is it for more recent versions of TGE, too?
#84
01/19/2008 (8:17 am)
Note: I tried what Master Treb said but it made no difference which protected section I put it in.

I put this code into the protected part of Trigger:

protected:
   bool onAdd();
   void onRemove();
   void onDeleteNotify(SimObject*);
   bool onNewDataBlock(GameBaseData* dptr);
   void onEditorEnable();
   void onEditorDisable();

   bool testObject(GameBase* enter);
   void processTick(const Move *move);

   Convex* mConvexList;
   void buildConvex(const Box3F& box, Convex* convex);
	// phdana aiobject ->
   void setOwner(GameBase *owner);
   // <- phdana aiobject

because I was getting this error...
trigger.cc(121) : 'setOwner' : is not a member of 'Trigger'

Now I get this error
trigger.cc(121) : 'Trigger::setOwner' : cannot access protected member declared in class 'Trigger'
#85
01/19/2008 (8:48 am)
Well I moved it to public instead and it worked. I guess the console method setOwner needed to have it visible and even though it instantiated a turret object, it was not privy to the owner member data without the public method... kinda simple when you think about it :)

I'm assuming cTriggerSetOwner is used for the console??? Yes/no?

public:
   void setTransform(const MatrixF &mat);
// phdana aiobject ->
   void setOwner(GameBase *owner);
   // <- phdana aiobject

.. where it's used ...
// phdana turrets ->
void cTriggerSetOwner(SimObject* obj, S32 argc, const char** argv )
{
   AssertFatal(dynamic_cast<Trigger*>(obj) != NULL, "Error, how did a non-trigger get here?");
   Trigger* trigger = static_cast<Trigger*>(obj);

   if (argc > 2)
   {
      GameBase* owner = NULL;
      if (Sim::findObject(argv[2], owner) == false)
         return;

      trigger->setOwner(owner);
   }

}
// <- phdana turrets
#86
02/06/2008 (2:48 am)
Hi all,

I'm using TGEA 1.0.3 - I've made all the changes, added the turret source files and made the changes discussed above (specifically the post by Kirk). I get a successful build with no errors or warnings.

However, when I run my game is freezes at 'Loading Objects' before the mission starts. The game doesn't actually hang - I can hit cancel to go back to the main menu, but the progress bar stops moving and the mission doesn't load. The console log doesn't give anything away. I don't think the issue is with the script because if I comment out all the script changes it still hangs.

Does anyone have any hints for getting this to work in TGEA 1.0.3? Kirk - do you have this working in TGEA?

Any help would be greatly appreciated.

Thanks all,

Andy

EDIT: Ignore - all fixed. I did a debug build and tracked down the problem. It was completely my fault: I'd put a stream->read() where a readFlag() should have been...
#87
02/06/2008 (9:03 am)
Hi again,

Now I have a new problem. The player-controlled turret works a treat and that was my main aim for today so thanks! However, The engine crashes back to the desktop as soon as I try and add a GenericAITurret. The last few lines of the console log are:

ACTIVATE sequence found
TurretData::onNewDataBlock
AITurretData::onNewDataBlock
TurretData::onAdd()
TurretData::onAdd() - Mounted Default Barrel on Turret

If I run a debug build, it breaks when trying to use inline Point3F Point3F::operator+(const Point3F& _add) const (at line 1311 in mPoint.h) and it looks like _add is not getting passed correctly (no x,y,z values). However, I don't know at what point in the turret creation process this actually happening as I'm not too sure what I'm doing with the c++ debugger!

Any help would be appreciated.

Thanks,

Andy
#88
02/27/2008 (6:14 pm)
It seems now when i build this with TGEA 1.02, it lags like crazy. With all other executables I have made, as soon as I added this, it made the engine go to almost a stand still. What would be the problem?
#89
03/15/2008 (4:44 pm)
Horray, problems with the resource.

The getAnglesFromVector fix is making my game sort of unstable. It has a tendency to freeze when I get within a turret's range. Without that fix, no freezing -- but my turrets' aim sucks.

For some reason, when my player is in a turret's trigger, he can't shoot properly. Items appear inside him instead of at the weapon's muzzle, same goes for regular projectiles. Weapons that inherit the muzzle velocity don't seem to experience this problem.

Any help? :\

EDIT: Never mind, both problems have been fixed. :]
#90
04/18/2008 (3:56 pm)
I got the turrets ingame, but when I mount the turret, it doesn't rotate with my view or shoot.

Help, please.
#91
04/18/2008 (5:23 pm)
@Niko - how did you get to mount the turret? I could never do that? Is it how you set up the model?
#93
05/02/2008 (5:31 pm)
I am working on adding this resource and I get the following errors when compiling:

/Torque Game Engine 1.5.2 SDK/Torque SDK/engine/game/turrets/aiTurret.cc:623: error: no matching function for call to `AITurret::getAnglesFromAimLocation(Point3F&, Point3F, F32&, F32&)'
/Torque Game Engine 1.5.2 SDK/Torque SDK/engine/game/turrets/aiTurret.cc:541: error: candidates are: void AITurret::getAnglesFromAimLocation(VectorF&, VectorF&, F32&, F32&)

Is it possible to convert a Point3F to a VectorF? How?
#94
05/02/2008 (5:48 pm)
@Matthew - are you sure the function getAnglesFromAimLocation(Point3F&, Point3F, F32&, F32&) has a definition in the .cc / .cpp file?

Looks looks to me like code somewhere is expecting an overriden form of the original function (which may have less or different arguments) but you haven't defined the new function in the implementation (.cc/.cpp) file.

It doesn't look like the parameter list is at fault.

Do a careful scan of the file and make sure there is a version of this function that accepts the parameters (Point3F&, Point3F, F32&, F32&)
#95
05/02/2008 (5:53 pm)
The first line of that function is
void AITurret::getAnglesFromAimLocation(VectorF &loc, VectorF &velocity, F32 &newYaw, F32 &newPitch)

I don't see one that uses Point3F. All I did was copy the file from the resource into the code folder. I don't see what could be wrong.
#96
05/02/2008 (6:34 pm)
It seems VectorF maps to Point3F in math.h anyway

typedef Point3F VectorF;

You also have a typo...
getAnglesFromAimLocation(Point3F&, Point3F <---, F32&, F32&)

should be 

getAnglesFromAimLocation(Point3F&, Point3F& <---, F32&, F32&)  - see the ampersand?
#97
05/02/2008 (7:13 pm)
Yes I see the ampersand, I am a C++ programmer (actually D, but I know C++). I don't know where the typo came from, I simply copied the code from the extracted folder. That must be a typo in the resource.
The function that is causing the error is:
bool AITurret::isReachableAngle(GameBase *obj)
{
   F32 pitch,yaw;
   Point3F targetLoc = obj->getBoxCenter();
   getAnglesFromAimLocation(targetLoc,obj->getVelocity(),yaw,pitch); // <- here!

   // if yaw is 0...2PI adjust it
   if (yaw > M_PI)
      yaw -= M_2PI;

   // if both are inside range we are good
   if (pitch >= mMinPitch && pitch <= mMaxPitch &&
       yaw >= mMinYaw && yaw <= mMaxYaw)
   {
      return true;
   }

   // otherwise not!
   return false;
}

The actual line is marked by <- here. I can't even find GameBase::getVelocity anywhere, so I don't even know what it is returning.

EDIT:
I don't understand why the velocity and center are being passed as references, but I fixed the problem by changing the function to:
*/
bool AITurret::isReachableAngle(GameBase *obj)
{
   F32 pitch,yaw;
   Point3F targetLoc = obj->getBoxCenter();
   Point3F vel = obj->getVelocity();
   getAnglesFromAimLocation(targetLoc,vel,yaw,pitch);

   // if yaw is 0...2PI adjust it
   if (yaw > M_PI)
      yaw -= M_2PI;

   // if both are inside range we are good
   if (pitch >= mMinPitch && pitch <= mMaxPitch &&
       yaw >= mMinYaw && yaw <= mMaxYaw)
   {
      return true;
   }

   // otherwise not!
   return false;
}
#98
05/02/2008 (9:29 pm)
@Matthew - sorry for over simplification but it's just meant for anybody else that has similar errors.

I'm looking for the getVelocity solution
#99
05/02/2008 (9:32 pm)
Sorry, that was a stupid misunderstanding on my part :)
I edited my previous post with a solution, so be sure to check it.
EDIT:
With the changes mentioned above, it compiles just fine. Now I just have to check to see if it will work...
#100
08/16/2008 (1:10 pm)
I have this installed and working fine - test turret cranks up, tracks, and shuts down properly but doesn't fire. I placed an echo into the AITurretData::fireGun function of aiTurret.cs and it's showing that function is being called, but no actual projectile is shown. I boosted the turret's energy to 2500 just in case it was an ammunition issue but that made no difference.

Any sugestions on where to look first? So far I'm not seeing anything amiss.


And while we're at it, is there any provision for (or a place to hotwire in) having a turret use an existing weapon? I'd love to have turrets spit out the guided missles from Decane's flight pack. :-D


EDIT: Nevermind on the weapon question - I found the weapon declare in the barrel datablock. Now if I can just get it to fire, I'd be golden... ;-)