Browse Source

add a calibrateable mHeightTolerance
for players this defaults to 0.001, for wheeledvehicles, 2.0, and for flyingvehicles, 200
fix naveditor cript not looking up the object.datablock.aicontrollerdata
fix AIWheeledVehicleControllerData not binding the relevant ::resolvespeed
also the relevant ::resolvespeed now lowers the throttle post-turning
add AIFlyingVehicleControllerData

AzaezelX 5 months ago
parent
commit
6200a6f1fb

+ 169 - 50
Engine/source/T3D/AI/AIController.cpp

@@ -24,6 +24,7 @@
 #include "T3D/player.h"
 #include "T3D/rigidShape.h"
 #include "T3D/vehicles/wheeledVehicle.h"
+#include "T3D/vehicles/flyingVehicle.h"
 
 
 IMPLEMENT_CONOBJECT(AIController);
@@ -164,16 +165,13 @@ bool AIController::getAIMove(Move* movePtr)
       {
          if (getGoal()->getDist() > mControllerData->mFollowTolerance)
          {
-            F32 raylength = 2.0; //for vehicles
             SceneObject* obj = getAIInfo()->mObj->getObjectMount();
             if (!obj)
             {
                obj = getAIInfo()->mObj;
-               raylength = 0.001f; //for jumping
             }
-
             RayInfo info;
-            if (obj->getContainer()->castRay(obj->getPosition(), obj->getPosition() - Point3F(0, 0, raylength), StaticShapeObjectType, &info))
+            if (obj->getContainer()->castRay(obj->getPosition(), obj->getPosition() - Point3F(0, 0, mControllerData->mHeightTolerance), StaticShapeObjectType, &info))
             {
                getNav()->repath();
             }
@@ -399,9 +397,11 @@ void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* m
    if (mIsZero(xDiff))
       movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
    else
+   {
       if (mIsZero(yDiff))
          movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
       else
+      {
          if (mFabs(xDiff) > mFabs(yDiff))
          {
             F32 value = mFabs(yDiff / xDiff);
@@ -414,7 +414,8 @@ void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* m
             movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -value : value;
             movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
          }
-
+      }
+   }
    // Rotate the move into object space (this really only needs
    // a 2D matrix)
    Point3F newMove;
@@ -484,13 +485,14 @@ void AIControllerData::resolveStuck(AIController* obj)
 
 AIControllerData::AIControllerData()
 {
-   mMoveTolerance = 0.25;
-   mFollowTolerance = 1.0;
-   mAttackRadius = 2.0;
+   mMoveTolerance = 0.25f;
+   mFollowTolerance = 1.0f;
+   mAttackRadius = 2.0f;
    mMoveStuckTolerance = 0.01f;
    mMoveStuckTestDelay = 30;
    mLinkTypes = LinkData(AllFlags);
    mNavSize = AINavigation::Regular;
+   mHeightTolerance = 0.001f;
 
    mFlocking.mChance = 90;
    mFlocking.mMin = 1.0f;
@@ -638,6 +640,8 @@ void AIPlayerControllerData::resolveTriggerState(AIController* obj, Move* movePt
 #endif // TORQUE_NAVIGATION_ENABLED
 }
 
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
 IMPLEMENT_CO_DATABLOCK_V1(AIWheeledVehicleControllerData);
 // Build a Triangle .. calculate angle of rotation required to meet target..
 // man there has to be a better way! >:)
@@ -772,57 +776,172 @@ void AIWheeledVehicleControllerData::resolveYaw(AIController* obj, Point3F locat
 
 void AIWheeledVehicleControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr)
 {
-   F32 xDiff = obj->getNav()->getMoveDestination().x - location.x;
-   F32 yDiff = obj->getNav()->getMoveDestination().y - location.y;
-   Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler();
+   WheeledVehicle* wvo = dynamic_cast<WheeledVehicle*>(obj->getAIInfo()->mObj.getPointer());
+   if (!wvo)
+   {
+      //cover the case of a connection controling an object in turn controlling another
+      if (obj->getAIInfo()->mObj->getObjectMount())
+         wvo = dynamic_cast<WheeledVehicle*>(obj->getAIInfo()->mObj->getObjectMount());
+   }
+   if (!wvo) return;//not a WheeledVehicle
 
-   Point2F movTarg;
+   Parent::resolveSpeed(obj, location, movePtr);
 
-   // Build move direction in world space
-   if (mIsZero(xDiff))
-      movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
-   else
+   VehicleData* db =  static_cast<VehicleData *>(wvo->getDataBlock());
+   movePtr->x = 0;// 1.1 - wvo->getSteering().x / db->maxSteeringAngle;
+   movePtr->y *= 1.1 - wvo->getSteering().y / db->maxSteeringAngle;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CO_DATABLOCK_V1(AIFlyingVehicleControllerData);
+// Build a Triangle .. calculate angle of rotation required to meet target..
+// man there has to be a better way! >:)
+F32 AIFlyingVehicleControllerData::getSteeringAngle(AIController* obj, Point3F location)
+{
+   FlyingVehicle* wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj.getPointer());
+   if (!wvo)
    {
-      if (mIsZero(yDiff))
-         movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
+      //cover the case of a connection controling an object in turn controlling another
+      if (obj->getAIInfo()->mObj->getObjectMount())
+         wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj->getObjectMount());
+   }
+   if (!wvo) return 0;//not a FlyingVehicle
+
+   DrivingState steerState = SteerNull;
+
+   // What is our target
+   Point3F desired;
+   desired = obj->getNav()->getMoveDestination();
+
+   MatrixF mat = wvo->getTransform();
+   Point3F center, front;
+   Point3F wFront;
+   Box3F box = wvo->getObjBox();
+
+   box.getCenter(&center);
+   front = center;
+   front.y = box.maxExtents.y; // should be true for all these objects
+
+   obj->getAIInfo()->mObj->getWorldBox().getCenter(&center);
+   front = center + front;
+
+   Point3F objFront = front;
+   Point3F offset = front - center;
+   EulerF rot;
+   rot = mat.toEuler();
+   MatrixF transform(rot);
+   transform.mulV(offset, &wFront);
+   front = wFront + center;
+
+   Point3F ftoc;
+   ftoc.x = mFabs(front.x - center.x);
+   ftoc.y = mFabs(front.y - center.y);
+   ftoc.z = mFabs(front.z - center.z);
+   F32 fToc = mSqrt((ftoc.x * ftoc.x) + (ftoc.y * ftoc.y));
+
+   Point3F ltoc;
+   ltoc.x = mFabs(desired.x - center.x);
+   ltoc.y = mFabs(desired.y - center.y);
+   ltoc.z = mFabs(desired.z - center.z);
+   F32 lToc = mSqrt((ltoc.x * ltoc.x) + (ltoc.y * ltoc.y));
+
+   Point3F ftol;
+   ftol.x = mFabs(front.x - desired.x);
+   ftol.y = mFabs(front.y - desired.y);
+   ftol.z = mFabs(front.z - desired.z);
+   F32 fTol = mSqrt((ftol.x * ftol.x) + (ftol.y * ftol.y));
+
+   F32 myAngle = mAcos(((lToc * lToc) + (fToc * fToc) - (fTol * fTol)) / (2 * lToc * fToc));
+
+   F32 finalYaw = mRadToDeg(myAngle);
+
+   F32 maxSteeringAngle = 0;
+
+   VehicleData* vd = (VehicleData*)(wvo->getDataBlock());
+   maxSteeringAngle = vd->maxSteeringAngle;
+
+   Point2F steering = wvo->getSteering();
+   if (finalYaw < 5 && steering.x != 0.0f)
+      steerState = Straight;
+   else if (finalYaw < 5)
+      steerState = SteerNull;
+   else
+   {// Quickly Hack out left or right turn info
+      Point3F rotData = objFront - desired;
+      MatrixF leftM(-rot);
+      Point3F leftP;
+      leftM.mulV(rotData, &leftP);
+      leftP = leftP + desired;
+
+      if (leftP.x < desired.x)
+         steerState = Right;
       else
-      {
-         if (mFabs(xDiff) > mFabs(yDiff))
-         {
-            F32 value = mFabs(yDiff / xDiff);
-            movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -value : value;
-            movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
-         }
-         else
-         {
-            F32 value = mFabs(xDiff / yDiff);
-            movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -value : value;
-            movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
-         }
-      }
+         steerState = Left;
    }
-   // Rotate the move into object space (this really only needs
-   // a 2D matrix)
-   Point3F newMove;
-   MatrixF moveMatrix;
-   moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw)));
-   moveMatrix.mulV(Point3F(movTarg.x, movTarg.y, 0.0f), &newMove);
-   movTarg.y = newMove.y;
 
-   // Set Throttle.  We'll slow down once we get close
-   // to try and stop on the spot...
-   if (obj->mMovement.mMoveSlowdown)
+   F32 throttle = wvo->getThrottle();
+   if (throttle < 0.0f && steerState != Straight)
    {
-      F32 throttle = obj->mMovement.mMoveSpeed;
-      F32 dist = mSqrt(xDiff * xDiff + yDiff * yDiff);
-      F32 maxDist = mMoveTolerance * 2;
-      if (dist < maxDist)
-         throttle *= dist / maxDist;
-      movePtr->y *= throttle;
+      F32 reverseReduction = 0.25;
+      steering.x = steering.x * reverseReduction * throttle;
    }
-   else
+   F32 turnAdjust = myAngle - steering.x;
+
+   F32 steer = 0;
+   switch (steerState)
    {
-      movePtr->y *= obj->mMovement.mMoveSpeed;
+   case Left:
+      steer = myAngle < maxSteeringAngle ? -turnAdjust : -maxSteeringAngle - steering.x;
+      break;
+   case Right:
+      steer = myAngle < maxSteeringAngle ? turnAdjust : maxSteeringAngle - steering.x;
+      break;
+   case Straight:
+      steer = -steering.x;
+      break;
+   default:
+      break;
+   };
+
+   //   Con::printf("AI Steering : %f", steer);
+   return steer;
+}
+
+
+void AIFlyingVehicleControllerData::resolveYaw(AIController* obj, Point3F location, Move* movePtr)
+{
+   FlyingVehicle* wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj.getPointer());
+   if (!wvo)
+   {
+      //cover the case of a connection controling an object in turn controlling another
+      if (obj->getAIInfo()->mObj->getObjectMount())
+         wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj->getObjectMount());
+   }
+   if (!wvo) return;//not a FlyingVehicle
+
+   // Orient towards our destination.
+   if (obj->mMovement.mMoveState == AIController::ModeMove || obj->mMovement.mMoveState == AIController::ModeReverse) {
+      movePtr->yaw = getSteeringAngle(obj, location);
    }
+};
+
+void AIFlyingVehicleControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr)
+{
+   FlyingVehicle* wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj.getPointer());
+   if (!wvo)
+   {
+      //cover the case of a connection controling an object in turn controlling another
+      if (obj->getAIInfo()->mObj->getObjectMount())
+         wvo = dynamic_cast<FlyingVehicle*>(obj->getAIInfo()->mObj->getObjectMount());
+   }
+   if (!wvo) return;//not a FlyingVehicle
+
+   Parent::resolveSpeed(obj, location, movePtr);
+
+   VehicleData* db = static_cast<VehicleData*>(wvo->getDataBlock());
+   movePtr->x = 0;// 1.1 - wvo->getSteering().x / db->maxSteeringAngle;
+   movePtr->y *= 1.1 - wvo->getSteering().y / db->maxSteeringAngle;
 }
 #endif //_AICONTROLLER_H_

+ 27 - 2
Engine/source/T3D/AI/AIController.h

@@ -157,7 +157,7 @@ public:
    F32 mAttackRadius;                  // Distance to trigger weaponry calcs
    F32 mMoveStuckTolerance;            // Distance tolerance on stuck check
    S32 mMoveStuckTestDelay;            // The number of ticks to wait before checking if the AI is stuck
-
+   F32 mHeightTolerance;               // how high above the navmesh are we before we stop trying to repath
    struct Flocking {
       U32 mChance;                     // chance of flocking
       F32 mMin;                        // min flocking separation distance
@@ -217,12 +217,37 @@ public:
    AIWheeledVehicleControllerData()
    {
       resolveYawPtr.bind(this, &AIWheeledVehicleControllerData::resolveYaw);
-      resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
+      resolveSpeedPtr.bind(this, &AIWheeledVehicleControllerData::resolveSpeed);
+      mHeightTolerance = 2.0f;
    }
    F32 getSteeringAngle(AIController* obj, Point3F location);
    void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
    void resolveSpeed(AIController* obj, Point3F location, Move* movePtr);
    DECLARE_CONOBJECT(AIWheeledVehicleControllerData);
 };
+
+class AIFlyingVehicleControllerData : public AIControllerData
+{
+   typedef AIControllerData Parent;
+
+   enum DrivingState {
+      SteerNull,
+      Left,
+      Right,
+      Straight
+   };
+
+public:
+   AIFlyingVehicleControllerData()
+   {
+      resolveYawPtr.bind(this, &AIFlyingVehicleControllerData::resolveYaw);
+      resolveSpeedPtr.bind(this, &AIFlyingVehicleControllerData::resolveSpeed);
+      mHeightTolerance = 200.0f;
+   }
+   F32 getSteeringAngle(AIController* obj, Point3F location);
+   void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
+   void resolveSpeed(AIController* obj, Point3F location, Move* movePtr);
+   DECLARE_CONOBJECT(AIFlyingVehicleControllerData);
+};
 #endif // TORQUE_NAVIGATION_ENABLED
 #endif //_AICONTROLLER_H_

+ 6 - 0
Templates/BaseGame/game/core/gameObjects/datablocks/defaultDatablocks.tscript

@@ -179,3 +179,9 @@ datablock AIWheeledVehicleControllerData( aiCarControl )
 {
     moveTolerance = 1.0; followTolerance = 2.0; mAttackRadius = 5.0;
 };
+
+datablock AIFlyingVehicleControllerData( aiPlaneControl )
+{
+    moveTolerance = 2.0; followTolerance = 5.0; mAttackRadius = 10.0;
+};
+

+ 1 - 1
Templates/BaseGame/game/tools/navEditor/navEditor.tscript

@@ -461,7 +461,7 @@ function NavEditorGui::onPlayerSelected(%this, %flags)
 {
    if (!isObject(%this.getPlayer().aiController) && (!(%this.getPlayer().isMemberOfClass("AIPlayer"))))
    {
-      %this.getPlayer().aiController = new AIController(){ ControllerData = aiPlayerControl; };
+      %this.getPlayer().aiController = new AIController(){ ControllerData = %this.getPlayer().getDatablock().aiControllerData; };
       %this.getPlayer().setAIController(%this.getPlayer().aiController);
    }
    NavMeshIgnore(%this.getPlayer(), true);