mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-15 00:24:40 +00:00
completed list of roughly ported over scripthooks.
todo: need to figure out why followobject is only hitting the first path node. likely amixup with goal handling
This commit is contained in:
parent
e37ae27bc0
commit
4fb92f02a3
16 changed files with 386 additions and 40 deletions
|
|
@ -28,7 +28,7 @@ struct AIAimTarget : AIInfo
|
||||||
typedef AIInfo Parent;
|
typedef AIInfo Parent;
|
||||||
Point3F mAimOffset;
|
Point3F mAimOffset;
|
||||||
bool mTargetInLOS; // Is target object visible?
|
bool mTargetInLOS; // Is target object visible?
|
||||||
Point3F getPosition() { return ((mObj) ? mObj->getPosition() : mPosition) + mAimOffset; }
|
Point3F getPosition() { return ((mObj.isValid()) ? mObj->getPosition() : mPosition) + mAimOffset; }
|
||||||
bool checkInLos(SceneObject* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
|
bool checkInLos(SceneObject* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
|
||||||
bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
|
bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
|
||||||
F32 getTargetDistance(SceneObject* target, bool _checkEnabled);
|
F32 getTargetDistance(SceneObject* target, bool _checkEnabled);
|
||||||
|
|
|
||||||
|
|
@ -82,25 +82,25 @@ bool AIController::getAIMove(Move* movePtr)
|
||||||
{
|
{
|
||||||
if (mMovement.mMoveState != ModeStop)
|
if (mMovement.mMoveState != ModeStop)
|
||||||
getNav()->updateNavMesh();
|
getNav()->updateNavMesh();
|
||||||
if (!getGoal()->mObj.isNull())
|
if (getGoal() && !getGoal()->mObj.isNull())
|
||||||
{
|
{
|
||||||
if (getNav()->mPathData.path.isNull())
|
if (getNav()->mPathData.path.isNull())
|
||||||
{
|
{
|
||||||
if (getGoal()->getDist() > mControllerData->mMoveTolerance)
|
if (getGoal()->getDist() > mControllerData->mFollowTolerance)
|
||||||
getNav()->followObject(getGoal());
|
getNav()->followObject(getGoal()->mObj, mControllerData->mFollowTolerance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (getGoal()->getDist() > mControllerData->mMoveTolerance)
|
if (getGoal()->getDist() > mControllerData->mFollowTolerance)
|
||||||
getNav()->repath();
|
getNav()->repath();
|
||||||
|
|
||||||
if (getAim()->getDist() < mControllerData->mMoveTolerance)
|
if (getGoal()->getDist() < mControllerData->mFollowTolerance)
|
||||||
{
|
{
|
||||||
getNav()->clearPath();
|
getNav()->clearPath();
|
||||||
mMovement.mMoveState = ModeStop;
|
mMovement.mMoveState = ModeStop;
|
||||||
throwCallback("onTargetInRange");
|
throwCallback("onTargetInRange");
|
||||||
}
|
}
|
||||||
else if (getAim()->getDist() < mControllerData->mAttackRadius)
|
else if (getGoal()->getDist() < mControllerData->mAttackRadius)
|
||||||
{
|
{
|
||||||
throwCallback("onTargetInFiringRange");
|
throwCallback("onTargetInFiringRange");
|
||||||
}
|
}
|
||||||
|
|
@ -178,11 +178,29 @@ bool AIController::getAIMove(Move* movePtr)
|
||||||
void AIController::clearCover()
|
void AIController::clearCover()
|
||||||
{
|
{
|
||||||
// Notify cover that we are no longer on our way.
|
// Notify cover that we are no longer on our way.
|
||||||
if (!getCover()->mCoverPoint.isNull())
|
if (getCover() && !getCover()->mCoverPoint.isNull())
|
||||||
getCover()->mCoverPoint->setOccupied(false);
|
getCover()->mCoverPoint->setOccupied(false);
|
||||||
SAFE_DELETE(mCover);
|
SAFE_DELETE(mCover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIController::Movement::stopMove()
|
||||||
|
{
|
||||||
|
mMoveState = ModeStop;
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
mControllerRef->getNav()->clearPath();
|
||||||
|
mControllerRef->clearCover();
|
||||||
|
mControllerRef->getNav()->clearFollow();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
void AIController::Movement::onStuck()
|
||||||
|
{
|
||||||
|
mControllerRef->throwCallback("onMoveStuck");
|
||||||
|
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||||
|
if (!mControllerRef->getNav()->getPath().isNull())
|
||||||
|
mControllerRef->getNav()->repath();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), ,
|
DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), ,
|
||||||
"@brief Sets the move speed for an AI object.\n\n"
|
"@brief Sets the move speed for an AI object.\n\n"
|
||||||
|
|
||||||
|
|
@ -205,6 +223,60 @@ DefineEngineMethod(AIController, getMoveSpeed, F32, (), ,
|
||||||
return object->mMovement.getMoveSpeed();
|
return object->mMovement.getMoveSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, stop, void, (), ,
|
||||||
|
"@brief Tells the AIPlayer to stop moving.\n\n")
|
||||||
|
{
|
||||||
|
object->mMovement.stopMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the state of a movement trigger.
|
||||||
|
*
|
||||||
|
* @param slot The trigger slot to set
|
||||||
|
* @param isSet set/unset the trigger
|
||||||
|
*/
|
||||||
|
void AIController::TriggerState::setMoveTrigger(U32 slot, const bool isSet)
|
||||||
|
{
|
||||||
|
if (slot >= MaxTriggerKeys)
|
||||||
|
{
|
||||||
|
Con::errorf("Attempting to set an invalid trigger slot (%i)", slot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mMoveTriggers[slot] = isSet; // set the trigger
|
||||||
|
mControllerRef->getAIInfo()->mObj->setMaskBits(ShapeBase::NoWarpMask); // force the client to updateMove
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the state of a movement trigger.
|
||||||
|
*
|
||||||
|
* @param slot The trigger slot to query
|
||||||
|
* @return True if the trigger is set, false if it is not set
|
||||||
|
*/
|
||||||
|
bool AIController::TriggerState::getMoveTrigger(U32 slot) const
|
||||||
|
{
|
||||||
|
if (slot >= MaxTriggerKeys)
|
||||||
|
{
|
||||||
|
Con::errorf("Attempting to get an invalid trigger slot (%i)", slot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return mMoveTriggers[slot];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the trigger state for all movement triggers.
|
||||||
|
*/
|
||||||
|
void AIController::TriggerState::clearMoveTriggers()
|
||||||
|
{
|
||||||
|
for (U32 i = 0; i < MaxTriggerKeys; i++)
|
||||||
|
setMoveTrigger(i, false);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_CO_DATABLOCK_V1(AIControllerData);
|
IMPLEMENT_CO_DATABLOCK_V1(AIControllerData);
|
||||||
|
|
@ -341,6 +413,7 @@ void AIControllerData::resolveStuck(AIController* obj)
|
||||||
if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
|
if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
|
||||||
{
|
{
|
||||||
obj->mMovement.mMoveState = AIController::ModeStuck;
|
obj->mMovement.mMoveState = AIController::ModeStuck;
|
||||||
|
obj->mMovement.onStuck();
|
||||||
obj->throwCallback("onStuck");
|
obj->throwCallback("onStuck");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@
|
||||||
#include "AICover.h"
|
#include "AICover.h"
|
||||||
#include "AINavigation.h"
|
#include "AINavigation.h"
|
||||||
class AIControllerData;
|
class AIControllerData;
|
||||||
class AIController;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
class AIController : public SimObject {
|
class AIController : public SimObject {
|
||||||
|
|
@ -83,6 +82,7 @@ public:
|
||||||
AINavigation* getNav() { return mNav; };
|
AINavigation* getNav() { return mNav; };
|
||||||
struct Movement
|
struct Movement
|
||||||
{
|
{
|
||||||
|
AIController* mControllerRef;
|
||||||
MoveState mMoveState;
|
MoveState mMoveState;
|
||||||
F32 mMoveSpeed = 1.0;
|
F32 mMoveSpeed = 1.0;
|
||||||
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
|
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
|
||||||
|
|
@ -99,6 +99,8 @@ public:
|
||||||
|
|
||||||
struct TriggerState
|
struct TriggerState
|
||||||
{
|
{
|
||||||
|
AIController* mControllerRef;
|
||||||
|
bool mMoveTriggers[MaxTriggerKeys];
|
||||||
// Trigger sets/gets
|
// Trigger sets/gets
|
||||||
void setMoveTrigger(U32 slot, const bool isSet = true);
|
void setMoveTrigger(U32 slot, const bool isSet = true);
|
||||||
bool getMoveTrigger(U32 slot) const;
|
bool getMoveTrigger(U32 slot) const;
|
||||||
|
|
@ -109,12 +111,18 @@ public:
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
AIController()
|
AIController()
|
||||||
{
|
{
|
||||||
|
for (S32 i = 0; i < MaxTriggerKeys; i++)
|
||||||
|
mTriggerState.mMoveTriggers[i] = false;
|
||||||
|
|
||||||
|
mMovement.mControllerRef = this;
|
||||||
|
mTriggerState.mControllerRef = this;
|
||||||
mControllerData = NULL;
|
mControllerData = NULL;
|
||||||
mAIInfo = new AIInfo(this);
|
mAIInfo = new AIInfo(this);
|
||||||
mGoal = new AIGoal(this);
|
mGoal = new AIGoal(this);
|
||||||
mAimTarget = new AIAimTarget(this);
|
mAimTarget = new AIAimTarget(this);
|
||||||
mCover = new AICover(this);
|
mCover = new AICover(this);
|
||||||
mNav = new AINavigation(this);
|
mNav = new AINavigation(this);
|
||||||
|
mMovement.mMoveState = ModeStop;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_CONOBJECT(AIController);
|
DECLARE_CONOBJECT(AIController);
|
||||||
|
|
@ -127,7 +135,16 @@ class AIControllerData : public SimDataBlock {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AIControllerData() { mMoveTolerance = 0.25; mFollowTolerance = 1.0; mAttackRadius = 2.0; mMoveStuckTolerance = 0.01f; mMoveStuckTestDelay = 30;};
|
AIControllerData()
|
||||||
|
{
|
||||||
|
mMoveTolerance = 0.25;
|
||||||
|
mFollowTolerance = 1.0;
|
||||||
|
mAttackRadius = 2.0;
|
||||||
|
mMoveStuckTolerance = 0.01f;
|
||||||
|
mMoveStuckTestDelay = 30;
|
||||||
|
mLinkTypes = LinkData(AllFlags);
|
||||||
|
mNavSize = AINavigation::Regular;
|
||||||
|
};
|
||||||
~AIControllerData() {};
|
~AIControllerData() {};
|
||||||
|
|
||||||
static void initPersistFields();
|
static void initPersistFields();
|
||||||
|
|
@ -140,7 +157,7 @@ public:
|
||||||
S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck
|
S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck
|
||||||
/// Types of link we can use.
|
/// Types of link we can use.
|
||||||
LinkData mLinkTypes;
|
LinkData mLinkTypes;
|
||||||
|
AINavigation::NavSize mNavSize;
|
||||||
void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
|
void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
|
||||||
void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {};
|
void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {};
|
||||||
void resolveRoll(AIController* obj, Point3F location, Move* movePtr);
|
void resolveRoll(AIController* obj, Point3F location, Move* movePtr);
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,90 @@
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
#include "AICover.h"
|
||||||
|
#include "AIController.h"
|
||||||
|
|
||||||
|
struct CoverSearch
|
||||||
|
{
|
||||||
|
Point3F loc;
|
||||||
|
Point3F from;
|
||||||
|
F32 dist;
|
||||||
|
F32 best;
|
||||||
|
CoverPoint* point;
|
||||||
|
CoverSearch() : loc(0, 0, 0), from(0, 0, 0)
|
||||||
|
{
|
||||||
|
best = -FLT_MAX;
|
||||||
|
point = NULL;
|
||||||
|
dist = FLT_MAX;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void findCoverCallback(SceneObject* obj, void* key)
|
||||||
|
{
|
||||||
|
CoverPoint* p = dynamic_cast<CoverPoint*>(obj);
|
||||||
|
if (!p || p->isOccupied())
|
||||||
|
return;
|
||||||
|
CoverSearch* s = static_cast<CoverSearch*>(key);
|
||||||
|
Point3F dir = s->from - p->getPosition();
|
||||||
|
dir.normalizeSafe();
|
||||||
|
// Score first based on angle of cover point to enemy.
|
||||||
|
F32 score = mDot(p->getNormal(), dir);
|
||||||
|
// Score also based on distance from seeker.
|
||||||
|
score -= (p->getPosition() - s->loc).len() / s->dist;
|
||||||
|
// Finally, consider cover size.
|
||||||
|
score += (p->getSize() + 1) / CoverPoint::NumSizes;
|
||||||
|
score *= p->getQuality();
|
||||||
|
if (score > s->best)
|
||||||
|
{
|
||||||
|
s->best = score;
|
||||||
|
s->point = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIController::findCover(const Point3F& from, F32 radius)
|
||||||
|
{
|
||||||
|
if (radius <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Create a search state.
|
||||||
|
CoverSearch s;
|
||||||
|
s.loc = getAIInfo()->getPosition();
|
||||||
|
s.dist = radius;
|
||||||
|
// Direction we seek cover FROM.
|
||||||
|
s.from = from;
|
||||||
|
|
||||||
|
// Find cover points.
|
||||||
|
Box3F box(radius * 2.0f);
|
||||||
|
box.setCenter(getAIInfo()->getPosition());
|
||||||
|
getAIInfo()->mObj->getContainer()->findObjects(box, MarkerObjectType, findCoverCallback, &s);
|
||||||
|
|
||||||
|
// Go to cover!
|
||||||
|
if (s.point)
|
||||||
|
{
|
||||||
|
// Calling setPathDestination clears cover...
|
||||||
|
bool foundPath = getNav()->setPathDestination(s.point->getPosition());
|
||||||
|
setCover(s.point);
|
||||||
|
s.point->setOccupied(true);
|
||||||
|
return foundPath;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, findCover, S32, (Point3F from, F32 radius), ,
|
||||||
|
"@brief Tells the AI to find cover nearby.\n\n"
|
||||||
|
|
||||||
|
"@param from Location to find cover from (i.e., enemy position).\n"
|
||||||
|
"@param radius Distance to search for cover.\n"
|
||||||
|
"@return Cover point ID if cover was found, -1 otherwise.\n\n")
|
||||||
|
{
|
||||||
|
if (object->findCover(from, radius))
|
||||||
|
{
|
||||||
|
CoverPoint* cover = object->getCover()->mCoverPoint.getObject();
|
||||||
|
return cover ? cover->getId() : -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@
|
||||||
#define _AICOVER_H_
|
#define _AICOVER_H_
|
||||||
|
|
||||||
#include "AIInfo.h"
|
#include "AIInfo.h"
|
||||||
|
#include "navigation/coverPoint.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct AICover : AIInfo
|
struct AICover : AIInfo
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +33,7 @@ struct AICover : AIInfo
|
||||||
/// Pointer to a cover point.
|
/// Pointer to a cover point.
|
||||||
SimObjectPtr<CoverPoint> mCoverPoint;
|
SimObjectPtr<CoverPoint> mCoverPoint;
|
||||||
AICover(AIController* controller) : Parent(controller) {};
|
AICover(AIController* controller) : Parent(controller) {};
|
||||||
AICover(AIController* controller, SimObjectPtr<SceneObject> objIn, F32 radIn) : Parent(controller, objIn, radIn) {};
|
AICover(AIController* controller, SimObjectPtr<SceneObject> objIn, F32 radIn) : Parent(controller, objIn, radIn) { mCoverPoint = dynamic_cast<CoverPoint*>(objIn.getPointer());};
|
||||||
AICover(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) {};
|
AICover(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ AIInfo::AIInfo(AIController* controller, Point3F pointIn, F32 radIn)
|
||||||
F32 AIInfo::getDist()
|
F32 AIInfo::getDist()
|
||||||
{
|
{
|
||||||
AIInfo* controlObj = getCtrl()->getAIInfo();
|
AIInfo* controlObj = getCtrl()->getAIInfo();
|
||||||
F32 ret = VectorF(controlObj->mObj->getPosition() - getPosition()).len();
|
F32 ret = VectorF(controlObj->getPosition() - getPosition()).len();
|
||||||
ret -= controlObj->mRadius + mRadius;
|
ret -= controlObj->mRadius + mRadius;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct AIInfo
|
||||||
Point3F mPosition, mLastPos;
|
Point3F mPosition, mLastPos;
|
||||||
bool mPosSet;
|
bool mPosSet;
|
||||||
F32 mRadius;
|
F32 mRadius;
|
||||||
Point3F getPosition() { return (mObj) ? mObj->getPosition() : mPosition; }
|
Point3F getPosition() { return (mObj.isValid()) ? mObj->getPosition() : mPosition; }
|
||||||
F32 getDist();
|
F32 getDist();
|
||||||
AIInfo() = delete;
|
AIInfo() = delete;
|
||||||
AIInfo(AIController* controller);
|
AIInfo(AIController* controller);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ AINavigation::AINavigation(AIController* controller)
|
||||||
{
|
{
|
||||||
mControllerRef = controller;
|
mControllerRef = controller;
|
||||||
mJump = None;
|
mJump = None;
|
||||||
|
mNavSize = Regular;
|
||||||
}
|
}
|
||||||
|
|
||||||
NavMesh* AINavigation::findNavMesh() const
|
NavMesh* AINavigation::findNavMesh() const
|
||||||
|
|
@ -40,6 +41,19 @@ NavMesh* AINavigation::findNavMesh() const
|
||||||
NavMesh* m = static_cast<NavMesh*>(set->at(i));
|
NavMesh* m = static_cast<NavMesh*>(set->at(i));
|
||||||
if (m->getWorldBox().isContained(gbo->getWorldBox()))
|
if (m->getWorldBox().isContained(gbo->getWorldBox()))
|
||||||
{
|
{
|
||||||
|
// Check that mesh size is appropriate.
|
||||||
|
if (gbo->isMounted())
|
||||||
|
{
|
||||||
|
if (!m->mVehicles)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((getNavSize() == Small && !m->mSmallCharacters) ||
|
||||||
|
(getNavSize() == Regular && !m->mRegularCharacters) ||
|
||||||
|
(getNavSize() == Large && !m->mLargeCharacters))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
|
if (!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
|
||||||
mesh = m;
|
mesh = m;
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +115,8 @@ void AINavigation::repath()
|
||||||
if (mPathData.path.isNull() || !mPathData.owned)
|
if (mPathData.path.isNull() || !mPathData.owned)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!mControllerRef->getGoal()) return;
|
||||||
|
|
||||||
// If we're following, get their position.
|
// If we're following, get their position.
|
||||||
mPathData.path->mTo = mControllerRef->getGoal()->getPosition();
|
mPathData.path->mTo = mControllerRef->getGoal()->getPosition();
|
||||||
// Update from position and replan.
|
// Update from position and replan.
|
||||||
|
|
@ -212,24 +228,21 @@ bool AINavigation::setPathDestination(const Point3F& pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AINavigation::followObject(AIInfo* targ)
|
void AINavigation::followObject()
|
||||||
{
|
{
|
||||||
if (!targ) return;
|
if ((mControllerRef->getGoal()->mLastPos - mControllerRef->getAIInfo()->getPosition()).len() < mControllerRef->mControllerData->mMoveTolerance)
|
||||||
|
|
||||||
if (targ->getDist() < mControllerRef->mControllerData->mMoveTolerance)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (setPathDestination(targ->getPosition()))
|
if (setPathDestination(mControllerRef->getGoal()->getPosition()))
|
||||||
{
|
{
|
||||||
mControllerRef->clearCover();
|
mControllerRef->clearCover();
|
||||||
mControllerRef->setGoal(targ);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AINavigation::followObject(SceneObject* obj, F32 radius)
|
void AINavigation::followObject(SceneObject* obj, F32 radius)
|
||||||
{
|
{
|
||||||
mControllerRef->setGoal(obj, radius);
|
mControllerRef->setGoal(obj, radius);
|
||||||
followObject(mControllerRef->getGoal());
|
followObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AINavigation::clearFollow()
|
void AINavigation::clearFollow()
|
||||||
|
|
@ -289,3 +302,107 @@ DefineEngineMethod(AIController, getMoveDestination, Point3F, (), ,
|
||||||
return object->getNav()->getMoveDestination();
|
return object->getNav()->getMoveDestination();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, setPathDestination, bool, (Point3F goal), ,
|
||||||
|
"@brief Tells the AI to find a path to the location provided\n\n"
|
||||||
|
|
||||||
|
"@param goal Coordinates in world space representing location to move to.\n"
|
||||||
|
"@return True if a path was found.\n\n"
|
||||||
|
|
||||||
|
"@see getPathDestination()\n"
|
||||||
|
"@see setMoveDestination()\n")
|
||||||
|
{
|
||||||
|
return object->getNav()->setPathDestination(goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, getPathDestination, Point3F, (), ,
|
||||||
|
"@brief Get the AIPlayer's current pathfinding destination.\n\n"
|
||||||
|
|
||||||
|
"@return Returns a point containing the \"x y z\" position "
|
||||||
|
"of the AIPlayer's current path destination. If no path destination "
|
||||||
|
"has yet been set, this returns \"0 0 0\"."
|
||||||
|
|
||||||
|
"@see setPathDestination()\n")
|
||||||
|
{
|
||||||
|
return object->getNav()->getPathDestination();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, followNavPath, void, (SimObjectId obj), ,
|
||||||
|
"@brief Tell the AIPlayer to follow a path.\n\n"
|
||||||
|
|
||||||
|
"@param obj ID of a NavPath object for the character to follow.")
|
||||||
|
{
|
||||||
|
NavPath* path;
|
||||||
|
if (Sim::findObject(obj, path))
|
||||||
|
object->getNav()->followNavPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, followObject, void, (SimObjectId obj, F32 radius), ,
|
||||||
|
"@brief Tell the AIPlayer to follow another object.\n\n"
|
||||||
|
|
||||||
|
"@param obj ID of the object to follow.\n"
|
||||||
|
"@param radius Maximum distance we let the target escape to.")
|
||||||
|
{
|
||||||
|
SceneObject* follow;
|
||||||
|
object->getNav()->clearPath();
|
||||||
|
object->clearCover();
|
||||||
|
object->getNav()->clearFollow();
|
||||||
|
|
||||||
|
if (Sim::findObject(obj, follow))
|
||||||
|
object->getNav()->followObject(follow, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, repath, void, (), ,
|
||||||
|
"@brief Tells the AI to re-plan its path. Does nothing if the character "
|
||||||
|
"has no path, or if it is following a mission path.\n\n")
|
||||||
|
{
|
||||||
|
object->getNav()->repath();
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, findNavMesh, S32, (), ,
|
||||||
|
"@brief Get the NavMesh object this AIPlayer is currently using.\n\n"
|
||||||
|
|
||||||
|
"@return The ID of the NavPath object this character is using for "
|
||||||
|
"pathfinding. This is determined by the character's location, "
|
||||||
|
"navigation type and other factors. Returns -1 if no NavMesh is "
|
||||||
|
"found.")
|
||||||
|
{
|
||||||
|
NavMesh* mesh = object->getNav()->getNavMesh();
|
||||||
|
return mesh ? mesh->getId() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, getNavMesh, S32, (), ,
|
||||||
|
"@brief Return the NavMesh this AIPlayer is using to navigate.\n\n")
|
||||||
|
{
|
||||||
|
NavMesh* m = object->getNav()->getNavMesh();
|
||||||
|
return m ? m->getId() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, setNavSize, void, (const char* size), ,
|
||||||
|
"@brief Set the size of NavMesh this character uses. One of \"Small\", \"Regular\" or \"Large\".")
|
||||||
|
{
|
||||||
|
if (!String::compare(size, "Small"))
|
||||||
|
object->getNav()->setNavSize(AINavigation::Small);
|
||||||
|
else if (!String::compare(size, "Regular"))
|
||||||
|
object->getNav()->setNavSize(AINavigation::Regular);
|
||||||
|
else if (!String::compare(size, "Large"))
|
||||||
|
object->getNav()->setNavSize(AINavigation::Large);
|
||||||
|
else
|
||||||
|
Con::errorf("AIPlayer::setNavSize: no such size '%s'.", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIController, getNavSize, const char*, (), ,
|
||||||
|
"@brief Return the size of NavMesh this character uses for pathfinding.")
|
||||||
|
{
|
||||||
|
switch (object->getNav()->getNavSize())
|
||||||
|
{
|
||||||
|
case AINavigation::Small:
|
||||||
|
return "Small";
|
||||||
|
case AINavigation::Regular:
|
||||||
|
return "Regular";
|
||||||
|
case AINavigation::Large:
|
||||||
|
return "Large";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@ struct AINavigation
|
||||||
Ledge, ///< Jump when we walk off a ledge.
|
Ledge, ///< Jump when we walk off a ledge.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum NavSize {
|
||||||
|
Small,
|
||||||
|
Regular,
|
||||||
|
Large
|
||||||
|
} mNavSize;
|
||||||
|
void setNavSize(NavSize size) { mNavSize = size; updateNavMesh(); }
|
||||||
|
NavSize getNavSize() const { return mNavSize; }
|
||||||
|
|
||||||
Point3F mMoveDestination;
|
Point3F mMoveDestination;
|
||||||
void setMoveDestination(const Point3F& location, bool slowdown);
|
void setMoveDestination(const Point3F& location, bool slowdown);
|
||||||
Point3F getMoveDestination() { return mMoveDestination; };
|
Point3F getMoveDestination() { return mMoveDestination; };
|
||||||
|
|
@ -68,6 +76,7 @@ struct AINavigation
|
||||||
SimObjectPtr<NavMesh> mNavMesh;
|
SimObjectPtr<NavMesh> mNavMesh;
|
||||||
NavMesh* findNavMesh() const;
|
NavMesh* findNavMesh() const;
|
||||||
void updateNavMesh();
|
void updateNavMesh();
|
||||||
|
NavMesh* getNavMesh() const { return mNavMesh; }
|
||||||
PathData mPathData;
|
PathData mPathData;
|
||||||
JumpStates mJump;
|
JumpStates mJump;
|
||||||
|
|
||||||
|
|
@ -81,7 +90,7 @@ struct AINavigation
|
||||||
SimObjectPtr<NavPath> getPath() { return mPathData.path; };
|
SimObjectPtr<NavPath> getPath() { return mPathData.path; };
|
||||||
void followNavPath(NavPath* path);
|
void followNavPath(NavPath* path);
|
||||||
|
|
||||||
void followObject(AIInfo* targ);
|
void followObject();
|
||||||
void followObject(SceneObject* obj, F32 radius);
|
void followObject(SceneObject* obj, F32 radius);
|
||||||
void clearFollow();
|
void clearFollow();
|
||||||
/// Move to the specified node in the current path.
|
/// Move to the specified node in the current path.
|
||||||
|
|
|
||||||
|
|
@ -2259,14 +2259,14 @@ void Player::advanceTime(F32 dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Player::setAIController(S32 controller)
|
bool Player::setAIController(SimObjectId controller)
|
||||||
{
|
{
|
||||||
if (Sim::findObject(controller, mAIController))
|
if (Sim::findObject(controller, mAIController))
|
||||||
{
|
{
|
||||||
mAIController->setAIInfo(this);
|
mAIController->setAIInfo(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Con::errorf("unable to find AIController : %i", controller);
|
||||||
mAIController = NULL;
|
mAIController = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -763,7 +763,7 @@ public:
|
||||||
void setMomentum(const Point3F &momentum) override;
|
void setMomentum(const Point3F &momentum) override;
|
||||||
bool displaceObject(const Point3F& displaceVector) override;
|
bool displaceObject(const Point3F& displaceVector) override;
|
||||||
virtual bool getAIMove(Move*);
|
virtual bool getAIMove(Move*);
|
||||||
bool setAIController(S32 controller);
|
bool setAIController(SimObjectId controller);
|
||||||
AIController* getAIController() { return mAIController; };
|
AIController* getAIController() { return mAIController; };
|
||||||
|
|
||||||
bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here?
|
bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here?
|
||||||
|
|
|
||||||
|
|
@ -225,8 +225,18 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
|
||||||
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
|
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
|
||||||
missionCleanup->addObject(obj);
|
missionCleanup->addObject(obj);
|
||||||
}
|
}
|
||||||
mPlayer = static_cast<AIPlayer*>(obj);
|
mPlayer = obj;
|
||||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
Player* po = dynamic_cast<Player*>(obj);
|
||||||
|
if (!po) return; //todo, more types
|
||||||
|
if (po->getAIController())
|
||||||
|
{
|
||||||
|
if (po->getAIController()->mControllerData)
|
||||||
|
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con::executef(this, "onPlayerSelected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -383,16 +393,34 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
|
||||||
// Select/move character
|
// Select/move character
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri))
|
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||||
{
|
{
|
||||||
if(dynamic_cast<AIPlayer*>(ri.object))
|
if(ri.object)
|
||||||
{
|
{
|
||||||
mPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
mPlayer = ri.object;
|
||||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
Player* po = dynamic_cast<Player*>(ri.object);
|
||||||
|
if (!po) return; //todo, more types
|
||||||
|
if (po->getAIController())
|
||||||
|
{
|
||||||
|
if (po->getAIController()->mControllerData)
|
||||||
|
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con::executef(this, "onPlayerSelected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||||
|
{
|
||||||
|
Player* po = dynamic_cast<Player*>(mPlayer.getPointer());
|
||||||
|
if (!po) return; //todo, more types
|
||||||
|
if (po->getAIController())
|
||||||
|
{
|
||||||
|
if (po->getAIController()->mControllerData)
|
||||||
|
po->getAIController()->getNav()->setPathDestination(ri.point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
|
||||||
mPlayer->setPathDestination(ri.point);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -455,8 +483,8 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
|
||||||
|
|
||||||
if(mMode == mTestMode)
|
if(mMode == mTestMode)
|
||||||
{
|
{
|
||||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri))
|
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||||
mCurPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
mCurPlayer = ri.object;
|
||||||
else
|
else
|
||||||
mCurPlayer = NULL;
|
mCurPlayer = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,8 +155,8 @@ protected:
|
||||||
/// @name Test mode
|
/// @name Test mode
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
SimObjectPtr<AIPlayer> mPlayer;
|
SimObjectPtr<SceneObject> mPlayer;
|
||||||
SimObjectPtr<AIPlayer> mCurPlayer;
|
SimObjectPtr<SceneObject> mCurPlayer;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,3 +169,8 @@ datablock LightAnimData( SpinLightAnim )
|
||||||
rotKeys[2] = "az";
|
rotKeys[2] = "az";
|
||||||
rotSmooth[2] = true;
|
rotSmooth[2] = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
datablock AIPlayerControllerData( aiPlayerControl )
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -104,6 +104,7 @@ function ENavEditorSettingsPage::init(%this)
|
||||||
{
|
{
|
||||||
// Initialises the settings controls in the settings dialog box.
|
// Initialises the settings controls in the settings dialog box.
|
||||||
%this-->SpawnClassOptions.clear();
|
%this-->SpawnClassOptions.clear();
|
||||||
|
%this-->SpawnClassOptions.add("Player");
|
||||||
%this-->SpawnClassOptions.add("AIPlayer");
|
%this-->SpawnClassOptions.add("AIPlayer");
|
||||||
%this-->SpawnClassOptions.setFirstSelected();
|
%this-->SpawnClassOptions.setFirstSelected();
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +241,7 @@ function NavEditorPlugin::initSettings(%this)
|
||||||
{
|
{
|
||||||
EditorSettings.beginGroup("NavEditor", true);
|
EditorSettings.beginGroup("NavEditor", true);
|
||||||
|
|
||||||
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer");
|
EditorSettings.setDefaultValue("SpawnClass", "Player");
|
||||||
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
|
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
|
||||||
|
|
||||||
EditorSettings.endGroup();
|
EditorSettings.endGroup();
|
||||||
|
|
|
||||||
|
|
@ -459,6 +459,12 @@ function NavEditorGui::onLinkSelected(%this, %flags)
|
||||||
|
|
||||||
function NavEditorGui::onPlayerSelected(%this, %flags)
|
function NavEditorGui::onPlayerSelected(%this, %flags)
|
||||||
{
|
{
|
||||||
|
if (!isObject(%this.getPlayer().aiController))
|
||||||
|
{
|
||||||
|
%this.getPlayer().aiController = new AIController(){ ControllerData = aiPlayerControl; };
|
||||||
|
%this.getPlayer().setAIController(%this.getPlayer().aiController);
|
||||||
|
}
|
||||||
|
NavMeshIgnore(%this.getPlayer(), true);
|
||||||
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
|
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -526,7 +532,7 @@ function NavEditorGui::findCover(%this)
|
||||||
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
|
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
|
||||||
if(%text !$= "")
|
if(%text !$= "")
|
||||||
%pos = eval("return " @ %text);
|
%pos = eval("return " @ %text);
|
||||||
%this.getPlayer().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
%this.getPlayer().getAIController().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -547,7 +553,7 @@ function NavEditorGui::followObject(%this)
|
||||||
toolsMessageBoxOk("Error", "Cannot find object" SPC %text);
|
toolsMessageBoxOk("Error", "Cannot find object" SPC %text);
|
||||||
}
|
}
|
||||||
if(isObject(%obj))
|
if(isObject(%obj))
|
||||||
%this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
%this.getPlayer().getAIController().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue