Browse Source

Merge pull request #649 from Azaezel/aiPlayer_utility

AIPlayer utility methods
Daniel Buckmaster 11 năm trước cách đây
mục cha
commit
1b06b0d92e
2 tập tin đã thay đổi với 126 bổ sung20 xóa
  1. 124 20
      Engine/source/T3D/aiPlayer.cpp
  2. 2 0
      Engine/source/T3D/aiPlayer.h

+ 124 - 20
Engine/source/T3D/aiPlayer.cpp

@@ -28,6 +28,8 @@
 #include "T3D/gameBase/moveManager.h"
 #include "console/engineAPI.h"
 
+static U32 sAIPlayerLoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
+
 IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
 
 ConsoleDocClass( AIPlayer,
@@ -417,28 +419,21 @@ bool AIPlayer::getAIMove(Move *movePtr)
    // Test for target location in sight if it's an object. The LOS is
    // run from the eye position to the center of the object's bounding,
    // which is not very accurate.
-   if (mAimObject) {
-      MatrixF eyeMat;
-      getEyeTransform(&eyeMat);
-      eyeMat.getColumn(3,&location);
-      Point3F targetLoc = mAimObject->getBoxCenter();
-
-      // This ray ignores non-static shapes. Cast Ray returns true
-      // if it hit something.
-      RayInfo dummy;
-      if (getContainer()->castRay( location, targetLoc,
-            StaticShapeObjectType | StaticObjectType |
-            TerrainObjectType, &dummy)) {
-         if (mTargetInLOS) {
-            throwCallback( "onTargetExitLOS" );
-            mTargetInLOS = false;
-         }
-      }
-      else
-         if (!mTargetInLOS) {
-            throwCallback( "onTargetEnterLOS" );
+   if (mAimObject)
+   {
+      if (checkInLos(mAimObject.getPointer()))
+      {
+         if (!mTargetInLOS)
+         {
+            throwCallback("onTargetEnterLOS");
             mTargetInLOS = true;
          }
+      }
+      else if (mTargetInLOS)
+      {
+         throwCallback("onTargetExitLOS");
+         mTargetInLOS = false;
+      }
    }
 
    // Replicate the trigger state into the move so that
@@ -610,3 +605,112 @@ DefineEngineMethod( AIPlayer, getAimObject, S32, (),,
 	GameBase* obj = object->getAimObject();
    return obj? obj->getId(): -1;
 }
+
+bool AIPlayer::checkInLos(GameBase* target, bool _useMuzzle, bool _checkEnabled)
+{
+   if (!isServerObject()) return false;
+   if (!target)
+   {
+      target = mAimObject.getPointer();
+      if (!target)
+         return false;
+   }
+   if (_checkEnabled)
+   {
+       if (target->getTypeMask() & ShapeBaseObjectType)
+       {
+           ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
+           if (shapeBaseCheck)
+               if (shapeBaseCheck->getDamageState() != Enabled) return false;
+       }
+       else
+           return false;
+   }
+
+   RayInfo ri;
+
+   disableCollision();
+
+   S32 mountCount = target->getMountedObjectCount();
+   for (S32 i = 0; i < mountCount; i++)
+   {
+      target->getMountedObject(i)->disableCollision();
+   }
+
+   Point3F checkPoint ;
+   if (_useMuzzle)
+      getMuzzlePointAI(0, &checkPoint );
+   else
+   {
+      MatrixF eyeMat;
+      getEyeTransform(&eyeMat);
+      eyeMat.getColumn(3, &checkPoint );
+   }
+
+   bool hit = !gServerContainer.castRay(checkPoint, target->getBoxCenter(), sAIPlayerLoSMask, &ri);
+   enableCollision();
+
+   for (S32 i = 0; i < mountCount; i++)
+   {
+      target->getMountedObject(i)->enableCollision();
+   }
+   return hit;
+}
+
+DefineEngineMethod(AIPlayer, checkInLos, bool, (ShapeBase* obj,  bool useMuzzle, bool checkEnabled),(NULL, false, false),
+   "@brief Check whether an object is in line of sight.\n"
+   "@obj Object to check. (If blank, it will check the current target).\n"
+   "@useMuzzle Use muzzle position. Otherwise use eye position. (defaults to false).\n"
+   "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
+{
+   return object->checkInLos(obj, useMuzzle, checkEnabled);
+}
+
+bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled)
+{
+   if (!isServerObject()) return false;
+   if (!target)
+   {
+      target = mAimObject.getPointer();
+      if (!target)
+         return false;
+   }
+   if (_checkEnabled)
+   {
+       if (target->getTypeMask() & ShapeBaseObjectType)
+       {
+           ShapeBase *shapeBaseCheck = static_cast<ShapeBase *>(target);
+           if (shapeBaseCheck)
+               if (shapeBaseCheck->getDamageState() != Enabled) return false;
+       }
+       else
+           return false;
+   }
+
+   MatrixF cam = getTransform();
+   Point3F camPos;
+   VectorF camDir;
+
+   cam.getColumn(3, &camPos);
+   cam.getColumn(1, &camDir);
+
+   camFov = mDegToRad(camFov) / 2;
+
+   Point3F shapePos = target->getBoxCenter();
+   VectorF shapeDir = shapePos - camPos;
+   // Test to see if it's within our viewcone, this test doesn't
+   // actually match the viewport very well, should consider
+   // projection and box test.
+   shapeDir.normalize();
+   F32 dot = mDot(shapeDir, camDir);
+   return (dot > camFov);
+}
+
+DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (NULL, 45.0f, false),
+   "@brief Check whether an object is within a specified veiw cone.\n"
+   "@obj Object to check. (If blank, it will check the current target).\n"
+   "@fov view angle in degrees.(Defaults to 45)\n"
+   "@checkEnabled check whether the object can take damage and if so is still alive.(Defaults to false)\n")
+{
+   return object->checkInFoV(obj, fov, checkEnabled);
+}

+ 2 - 0
Engine/source/T3D/aiPlayer.h

@@ -80,6 +80,8 @@ public:
    void setAimLocation( const Point3F &location );
    Point3F getAimLocation() const { return mAimLocation; }
    void clearAim();
+   bool checkInLos(GameBase* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
+   bool checkInFoV(GameBase* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
 
    // Movement sets/gets
    void setMoveSpeed( const F32 speed );