elevated mAicontroller to shapebase

aiwheeleedveiclecontrollerdata resolvespeed now only touches throttle
objects assigned aicontrollers now reflect that by thier objecttype
basic flocking
This commit is contained in:
AzaezelX 2025-04-19 04:25:36 -05:00
parent d36cf31707
commit 3210325f3f
15 changed files with 352 additions and 185 deletions

View file

@ -122,6 +122,27 @@ bool AIController::getAIMove(Move* movePtr)
Point3F location = eye.getPosition();
Point3F rotation = sbo->getTransform().toEuler();
// 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 (getAim() && getAim()->mObj)
{
GameBase* gbo = dynamic_cast<GameBase*>(getAIInfo()->mObj.getPointer());
if (getAim()->checkInLos(gbo))
{
if (!getAim()->mTargetInLOS)
{
throwCallback("onTargetEnterLOS");
getAim()->mTargetInLOS = true;
}
}
else if (getAim()->mTargetInLOS)
{
throwCallback("onTargetExitLOS");
getAim()->mTargetInLOS = false;
}
}
#ifdef TORQUE_NAVIGATION_ENABLED
if (sbo->getDamageState() == ShapeBase::Enabled && getGoal())
{
@ -181,6 +202,7 @@ bool AIController::getAIMove(Move* movePtr)
}
#endif // TORQUE_NAVIGATION_ENABLED
getNav()->flock();
// Orient towards the aim point, aim object, or towards
// our destination.
if (getAim() || mMovement.mMoveState != ModeStop)
@ -189,7 +211,7 @@ bool AIController::getAIMove(Move* movePtr)
if (getAim())
mMovement.mAimLocation = getAim()->getPosition();
else
mMovement.mAimLocation = getNav()->mMoveDestination;
mMovement.mAimLocation = getNav()->getMoveDestination();
mControllerData->resolveYawPtr(this, location, movePtr);
mControllerData->resolvePitchPtr(this, location, movePtr);
@ -197,11 +219,10 @@ bool AIController::getAIMove(Move* movePtr)
if (mMovement.mMoveState != AIController::ModeStop)
{
F32 xDiff = getNav()->mMoveDestination.x - location.x;
F32 yDiff = getNav()->mMoveDestination.y - location.y;
F32 xDiff = getNav()->getMoveDestination().x - location.x;
F32 yDiff = getNav()->getMoveDestination().y - location.y;
if (mFabs(xDiff) < mControllerData->mMoveTolerance && mFabs(yDiff) < mControllerData->mMoveTolerance)
{
mMovement.mMoveState = AIController::ModeStop;
getNav()->onReachDestination();
}
else
@ -214,27 +235,7 @@ bool AIController::getAIMove(Move* movePtr)
mControllerData->resolveTriggerStatePtr(this, 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 (getAim() && getAim()->mObj)
{
GameBase* gbo = dynamic_cast<GameBase*>(getAIInfo()->mObj.getPointer());
if (getAim()->checkInLos(gbo))
{
if (!getAim()->mTargetInLOS)
{
throwCallback("onTargetEnterLOS");
getAim()->mTargetInLOS = true;
}
}
else if (getAim()->mTargetInLOS)
{
throwCallback("onTargetExitLOS");
getAim()->mTargetInLOS = false;
}
}
getAIInfo()->mLastPos = getAIInfo()->getPosition();
return true;
}
@ -250,17 +251,18 @@ void AIController::Movement::stopMove()
{
mMoveState = ModeStop;
#ifdef TORQUE_NAVIGATION_ENABLED
mControllerRef->getNav()->clearPath();
mControllerRef->clearCover();
mControllerRef->getNav()->clearFollow();
getCtrl()->getNav()->clearPath();
getCtrl()->clearCover();
getCtrl()->getNav()->clearFollow();
#endif
}
void AIController::Movement::onStuck()
{
mControllerRef->throwCallback("onMoveStuck");
mMoveState = AIController::ModeStuck;
getCtrl()->throwCallback("onMoveStuck");
#ifdef TORQUE_NAVIGATION_ENABLED
if (!mControllerRef->getNav()->getPath().isNull())
mControllerRef->getNav()->repath();
if (!getCtrl()->getNav()->getPath().isNull())
getCtrl()->getNav()->repath();
#endif
}
@ -386,28 +388,28 @@ void AIControllerData::resolveRoll(AIController* obj, Point3F location, Move* mo
void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr)
{
F32 xDiff = obj->getNav()->mMoveDestination.x - location.x;
F32 yDiff = obj->getNav()->mMoveDestination.y - location.y;
F32 xDiff = obj->getNav()->getMoveDestination().x - location.x;
F32 yDiff = obj->getNav()->getMoveDestination().y - location.y;
Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler();
// Build move direction in world space
if (mIsZero(xDiff))
movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -1.0f : 1.0f;
movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
else
if (mIsZero(yDiff))
movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -1.0f : 1.0f;
movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
else
if (mFabs(xDiff) > mFabs(yDiff))
{
F32 value = mFabs(yDiff / xDiff);
movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -value : value;
movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -1.0f : 1.0f;
movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -value : value;
movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
}
else
{
F32 value = mFabs(xDiff / yDiff);
movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -value : value;
movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -1.0f : 1.0f;
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
@ -430,15 +432,11 @@ void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* m
speed *= dist / maxDist;
movePtr->x *= speed;
movePtr->y *= speed;
obj->mMovement.mMoveState = AIController::ModeSlowing;
}
else
{
movePtr->x *= obj->mMovement.mMoveSpeed;
movePtr->y *= obj->mMovement.mMoveSpeed;
obj->mMovement.mMoveState = AIController::ModeMove;
}
}
@ -453,36 +451,57 @@ void AIControllerData::resolveTriggerState(AIController* obj, Move* movePtr)
void AIControllerData::resolveStuck(AIController* obj)
{
if (obj->mMovement.mMoveState == AIController::ModeStop) return;
if (obj->mMovement.mMoveState == AIController::ModeStuck) return;
if (!obj->getGoal()) return;
ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj->getAIInfo()->mObj.getPointer());
// Don't check for ai stuckness if animation during
// an anim-clip effect override.
if (sbo->getDamageState() == ShapeBase::Enabled && !(sbo->anim_clip_flags & ShapeBase::ANIM_OVERRIDDEN) && !sbo->isAnimationLocked())
{
if (obj->mMovement.mMoveStuckTestCountdown > 0)
--obj->mMovement.mMoveStuckTestCountdown;
else
// We should check to see if we are stuck...
F32 locationDelta = (obj->getAIInfo()->getPosition() - obj->getAIInfo()->mLastPos).len();
if (locationDelta < mMoveStuckTolerance)
{
// We should check to see if we are stuck...
F32 locationDelta = (obj->getAIInfo()->getPosition() - obj->getAIInfo()->mLastPos).len();
if (locationDelta < mMoveStuckTolerance)
if (obj->mMovement.mMoveStuckTestCountdown > 0)
--obj->mMovement.mMoveStuckTestCountdown;
else
{
// If we are slowing down, then it's likely that our location delta will be less than
// our move stuck tolerance. Because we can be both slowing and stuck
// we should TRY to check if we've moved. This could use better detection.
if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
{
obj->mMovement.mMoveState = AIController::ModeStuck;
obj->mMovement.onStuck();
obj->throwCallback("onStuck");
}
obj->mMovement.mMoveStuckTestCountdown = obj->mControllerData->mMoveStuckTestDelay;
}
}
obj->getAIInfo()->mLastPos = obj->getAIInfo()->getPosition();
}
}
AIControllerData::AIControllerData()
{
mMoveTolerance = 0.25;
mFollowTolerance = 1.0;
mAttackRadius = 2.0;
mMoveStuckTolerance = 0.01f;
mMoveStuckTestDelay = 30;
mLinkTypes = LinkData(AllFlags);
mNavSize = AINavigation::Regular;
mFlocking.mChance = 100;
mFlocking.mMin = 1.0f;
mFlocking.mMax = 3.0f;
mFlocking.mSideStep = 0.125f;
resolveYawPtr.bind(this, &AIControllerData::resolveYaw);
resolvePitchPtr.bind(this, &AIControllerData::resolvePitch);
resolveRollPtr.bind(this, &AIControllerData::resolveRoll);
resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState);
resolveStuckPtr.bind(this, &AIControllerData::resolveStuck);
}
void AIControllerData::initPersistFields()
{
docsURL;
@ -518,6 +537,14 @@ void AIControllerData::initPersistFields()
addFieldV("AttackRadius", TypeRangedF32, Offset(mAttackRadius, AIControllerData), &CommonValidators::PositiveFloat,
"@brief Distance considered in firing range for callback purposes.");
addFieldV("FlockChance", TypeRangedS32, Offset(mFlocking.mChance, AIControllerData), &CommonValidators::S32Percent,
"@brief chance of flocking.");
addFieldV("FlockMin", TypeRangedF32, Offset(mFlocking.mMin, AIControllerData), &CommonValidators::PositiveFloat,
"@brief min flocking separation distance.");
addFieldV("FlockMax", TypeRangedF32, Offset(mFlocking.mMax, AIControllerData), &CommonValidators::PositiveFloat,
"@brief max flocking clustering distance.");
addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat,
"@brief Distance from destination before we stop moving out of the way.");
endGroup("AI");
#ifdef TORQUE_NAVIGATION_ENABLED
@ -626,7 +653,7 @@ F32 AIWheeledVehicleControllerData::getSteeringAngle(AIController* obj, Point3F
// What is our target
Point3F desired;
desired = obj->getNav()->mMoveDestination;
desired = obj->getNav()->getMoveDestination();
MatrixF mat = wvo->getTransform();
Point3F center, front;
@ -739,4 +766,60 @@ void AIWheeledVehicleControllerData::resolveYaw(AIController* obj, Point3F locat
movePtr->yaw = getSteeringAngle(obj, location);
}
};
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();
Point2F movTarg;
// Build move direction in world space
if (mIsZero(xDiff))
movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
else
{
if (mIsZero(yDiff))
movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
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;
}
}
}
// 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 = obj->mMovement.mMoveSpeed;
F32 dist = mSqrt(xDiff * xDiff + yDiff * yDiff);
F32 maxDist = mMoveTolerance * 2;
if (dist < maxDist)
throttle *= dist / maxDist;
movePtr->y *= throttle;
}
else
{
movePtr->y *= obj->mMovement.mMoveSpeed;
}
}
#endif //_AICONTROLLER_H_

View file

@ -84,6 +84,7 @@ public:
struct Movement
{
AIController* mControllerRef;
AIController* getCtrl() { return mControllerRef; };
MoveState mMoveState;
F32 mMoveSpeed = 1.0;
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
@ -101,6 +102,7 @@ public:
struct TriggerState
{
AIController* mControllerRef;
AIController* getCtrl() { return mControllerRef; };
bool mMoveTriggers[MaxTriggerKeys];
// Trigger sets/gets
void setMoveTrigger(U32 slot, const bool isSet = true);
@ -143,23 +145,7 @@ class AIControllerData : public SimDataBlock {
public:
AIControllerData()
{
mMoveTolerance = 0.25;
mFollowTolerance = 1.0;
mAttackRadius = 2.0;
mMoveStuckTolerance = 0.01f;
mMoveStuckTestDelay = 30;
mLinkTypes = LinkData(AllFlags);
mNavSize = AINavigation::Regular;
resolveYawPtr.bind(this, &AIControllerData::resolveYaw);
resolvePitchPtr.bind(this, &AIControllerData::resolvePitch);
resolveRollPtr.bind(this, &AIControllerData::resolveRoll);
resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState);
resolveStuckPtr.bind(this, &AIControllerData::resolveStuck);
};
AIControllerData();
~AIControllerData() {};
void packData(BitStream* stream) override {};
void unpackData(BitStream* stream) override {};
@ -171,6 +157,14 @@ 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
struct Flocking {
U32 mChance; // chance of flocking
F32 mMin; // min flocking separation distance
F32 mMax; // max flocking clustering distance
F32 mSideStep; // Distance from destination before we stop moving out of the way
} mFlocking;
/// Types of link we can use.
LinkData mLinkTypes;
AINavigation::NavSize mNavSize;
@ -223,9 +217,11 @@ public:
AIWheeledVehicleControllerData()
{
resolveYawPtr.bind(this, &AIWheeledVehicleControllerData::resolveYaw);
resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
}
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);
};
#endif // TORQUE_NAVIGATION_ENABLED

View file

@ -22,8 +22,8 @@
#ifndef _AIINFO_H_
#define _AIINFO_H_
#ifndef _SHAPEBASE_H_
#include "T3D/shapeBase.h"
#ifndef _SCENEOBJECT_H_
#include "scene/sceneObject.h"
#endif
class AIController;

View file

@ -21,6 +21,9 @@
//-----------------------------------------------------------------------------
#include "AINavigation.h"
#include "AIController.h"
#include "T3D/shapeBase.h"
static U32 sAILoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType | AIObjectType;
AINavigation::AINavigation(AIController* controller)
{
@ -283,6 +286,127 @@ void AINavigation::clearPath()
mPathData = PathData();
}
void AINavigation::flock()
{
AIControllerData::Flocking flockingData = getCtrl()->mControllerData->mFlocking;
SimObjectPtr<SceneObject> obj = getCtrl()->getAIInfo()->mObj;
if (mRandI(0,100) > flockingData.mChance)
return;
obj->disableCollision();
Point3F pos = obj->getBoxCenter();
Point3F searchArea = Point3F(flockingData.mMin / 2, flockingData.mMax / 2, getCtrl()->getAIInfo()->mObj->getObjBox().maxExtents.z / 2);
F32 maxFlocksq = flockingData.mMax * flockingData.mMax;
if (getCtrl()->getGoal())
{
Point3F dest = mMoveDestination;
if (getCtrl()->mMovement.mMoveState == AIController::ModeStuck)
{
Point3F shuffle = Point3F(mRandF() - 0.5, mRandF() - 0.5, 0);
shuffle.normalize();
dest += shuffle * flockingData.mMin;
}
dest.z = pos.z;
if ((pos - dest).len() > flockingData.mSideStep)
{
//find closest object
SimpleQueryList sql;
Box3F queryBox = Box3F(pos - searchArea, pos + searchArea);
obj->getContainer()->findObjects(queryBox, AIObjectType, SimpleQueryList::insertionCallback, &sql);
sql.mList.remove(obj);
Point3F avoidanceOffset = Point3F::Zero;
U32 found = 0;
//avoid objects in the way
RayInfo info;
if (obj->getContainer()->castRay(pos, dest + Point3F(0, 0, obj->getObjBox().len_z() / 2), sAILoSMask, &info))
{
Point3F blockerOffset = (info.point - dest);
blockerOffset.z = 0;
avoidanceOffset += blockerOffset;
}
//avoid bots that are too close
for (U32 i = 0; i < sql.mList.size(); i++)
{
ShapeBase* other = dynamic_cast<ShapeBase*>(sql.mList[i]);
Point3F objectCenter = other->getBoxCenter();
F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin;
sumRad += getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius;
Point3F offset = (pos - objectCenter);
F32 offsetLensq = offset.lenSquared(); //square roots are expensive, so use squared val compares
if ((flockingData.mMin > 0) && (offsetLensq < (sumRad * sumRad)))
{
other->disableCollision();
if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info))
{
found++;
offset.normalizeSafe();
offset *= sumRad;
avoidanceOffset += offset; //accumulate total group, move away from that
}
other->enableCollision();
}
}
//if we don't have to worry about bumping into one another (nothing found lower than minFLock), see about grouping up
if (found == 0)
{
for (U32 i = 0; i < sql.mList.size(); i++)
{
ShapeBase* other = static_cast<ShapeBase*>(sql.mList[i]);
Point3F objectCenter = other->getBoxCenter();
F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin;
sumRad += getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius;
Point3F offset = (pos - objectCenter);
if ((flockingData.mMin > 0) && ((sumRad * sumRad) < (maxFlocksq)))
{
other->disableCollision();
if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info))
{
found++;
offset.normalizeSafe();
offset *= sumRad;
avoidanceOffset -= offset; // subtract total group, move toward it
}
other->enableCollision();
}
}
}
avoidanceOffset.z = 0;
avoidanceOffset.x = (mRandF() * avoidanceOffset.x) * 0.5 + avoidanceOffset.x * 0.75;
avoidanceOffset.y = (mRandF() * avoidanceOffset.y) * 0.5 + avoidanceOffset.y * 0.75;
if (avoidanceOffset.lenSquared() < (maxFlocksq))
{
avoidanceOffset.normalizeSafe();
dest += avoidanceOffset;
}
//if we're not jumping...
if ((mPathData.path) && !(mPathData.path->getFlags(mPathData.index) & JumpFlag))
{
//make sure we don't run off a cliff
Point3F zlen(0, 0, getCtrl()->getAIInfo()->mRadius);
if (obj->getContainer()->castRay(dest + zlen, dest - zlen, TerrainObjectType | StaticShapeObjectType | StaticObjectType, &info))
{
mMoveDestination = dest;
}
}
}
}
obj->enableCollision();
}
DefineEngineMethod(AIController, setMoveDestination, void, (Point3F goal, bool slowDown), (true),
"@brief Tells the AI to move to the location provided\n\n"

View file

@ -96,6 +96,7 @@ struct AINavigation
/// Move to the specified node in the current path.
void moveToNode(S32 node);
void flock();
};
#endif

View file

@ -669,6 +669,7 @@ static void RegisterGameFunctions()
Con::setIntVariable("$TypeMasks::PathShapeObjectType", PathShapeObjectType);
// PATHSHAPE END
Con::setIntVariable("$TypeMasks::TurretObjectType", TurretObjectType);
Con::setIntVariable("$TypeMasks::AIObjectType", AIObjectType);
Con::addVariable("Ease::InOut", TypeS32, &gEaseInOut,
"InOut ease for curve movement.\n"

View file

@ -174,7 +174,7 @@ enum SceneObjectTypes
/// @see TurretShape
TurretObjectType = BIT(29),
N_A_31 = BIT(30),
N_A_32 = BIT(31),
AIObjectType = BIT(31),
/// @}
};

View file

@ -461,7 +461,6 @@ PlayerData::PlayerData()
physicsPlayerType = StringTable->EmptyString();
mControlMap = StringTable->EmptyString();
mAIControllData = NULL;
dMemset( actionList, 0, sizeof(actionList) );
}
@ -742,8 +741,6 @@ void PlayerData::initPersistFields()
addGroup( "Movement" );
addField("controlMap", TypeString, Offset(mControlMap, PlayerData),
"@brief movemap used by these types of objects.\n\n");
addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, PlayerData),
"@brief ai controller used by these types of objects.\n\n");
addFieldV( "maxStepHeight", TypeRangedF32, Offset(maxStepHeight, PlayerData), &CommonValidators::PositiveFloat,
"@brief Maximum height the player can step up.\n\n"
@ -1645,7 +1642,6 @@ Player::Player()
mLastAbsoluteYaw = 0.0f;
mLastAbsolutePitch = 0.0f;
mLastAbsoluteRoll = 0.0f;
mAIController = NULL;
afx_init();
}
@ -1656,7 +1652,6 @@ Player::~Player()
delete mShapeFPInstance[i];
mShapeFPInstance[i] = 0;
}
if (mAIController) mAIController->deleteObject();
}
@ -2260,42 +2255,6 @@ void Player::advanceTime(F32 dt)
}
}
}
bool Player::setAIController(SimObjectId controller)
{
if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
{
mAIController->setAIInfo(this);
return true;
}
Con::errorf("unable to find AIController : %i", controller);
mAIController = NULL;
return false;
}
DefineEngineMethod(Player, setAIController, bool, (S32 controller), , "")
{
return object->setAIController(controller);
}
DefineEngineMethod(Player, getAIController, AIController*, (), , "")
{
return object->getAIController();
}
bool Player::getAIMove(Move* move)
{
if (!isServerObject()) return false;
if (mAIController)
{
mAIController->getAIMove(move); //actual result
return true;
}
return false;
}
void Player::setState(ActionState state, U32 recoverTicks)
{
if (state != mState) {

View file

@ -55,7 +55,6 @@ class OpenVRTrackedObject;
#include "navigation/navMesh.h"
#include "navigation/coverPoint.h"
#endif // TORQUE_NAVIGATION_ENABLED
#include "AI/AIController.h"
//----------------------------------------------------------------------------
@ -354,7 +353,6 @@ struct PlayerData: public ShapeBaseData {
// Jump off surfaces at their normal rather than straight up
bool jumpTowardsNormal;
StringTableEntry mControlMap;
AIControllerData* mAIControllData;
// For use if/when mPhysicsPlayer is created
StringTableEntry physicsPlayerType;
@ -496,7 +494,6 @@ protected:
SimObjectPtr<ShapeBase> mControlObject; ///< Controlling object
AIController* mAIController;
/// @name Animation threads & data
/// @{
@ -762,10 +759,6 @@ public:
Point3F getMomentum() const override;
void setMomentum(const Point3F &momentum) override;
bool displaceObject(const Point3F& displaceVector) override;
virtual bool getAIMove(Move*);
bool setAIController(SimObjectId controller);
AIController* getAIController() { return mAIController; };
bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here?
//

View file

@ -69,6 +69,7 @@
#include "core/stream/fileStream.h"
#include "T3D/accumulationVolume.h"
#include "console/persistenceManager.h"
#include "AI/AIController.h"
IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseData);
@ -195,7 +196,8 @@ ShapeBaseData::ShapeBaseData()
useEyePoint( false ),
isInvincible( false ),
renderWhenDestroyed( true ),
inheritEnergyFromMount( false )
inheritEnergyFromMount( false ),
mAIControllData(NULL)
{
INIT_ASSET(Shape);
INIT_ASSET(DebrisShape);
@ -544,6 +546,10 @@ void ShapeBaseData::initPersistFields()
addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
endGroup( "Shapes" );
addGroup("Movement");
addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, ShapeBaseData),
"@brief ai controller used by these types of objects.\n\n");
endGroup("Movement");
addGroup("Particle Effects");
addField( "explosion", TYPEID< ExplosionData >(), Offset(explosion, ShapeBaseData),
@ -981,7 +987,8 @@ ShapeBase::ShapeBase()
mCameraFov( 90.0f ),
mIsControlled( false ),
mLastRenderFrame( 0 ),
mLastRenderDistance( 0.0f )
mLastRenderDistance( 0.0f ),
mAIController(NULL)
{
mTypeMask |= ShapeBaseObjectType | LightObjectType;
@ -1032,6 +1039,7 @@ ShapeBase::~ShapeBase()
cur->next = sFreeTimeoutList;
sFreeTimeoutList = cur;
}
if (mAIController) mAIController->deleteObject();
}
void ShapeBase::initPersistFields()
@ -5449,3 +5457,43 @@ DefineEngineMethod(ShapeBase, getNodePoint, Point3F, (const char* nodeName), ,
return pos;
}
bool ShapeBase::setAIController(SimObjectId controller)
{
if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
{
mAIController->setAIInfo(this);
mTypeMask |= AIObjectType;
return true;
}
Con::errorf("unable to find AIController : %i", controller);
mAIController = NULL;
mTypeMask |= ~AIObjectType;
return false;
}
bool ShapeBase::getAIMove(Move* move)
{
if (!isServerObject()) return false;
if (!(mTypeMask & VehicleObjectType || mTypeMask & PlayerObjectType)) return false; //only support players and vehicles for now
if (mAIController)
{
mAIController->getAIMove(move); //actual result
mTypeMask |= AIObjectType;
return true;
}
mAIController = NULL;
mTypeMask &= ~AIObjectType;
return false;
}
DefineEngineMethod(ShapeBase, setAIController, bool, (S32 controller), , "")
{
return object->setAIController(controller);
}
DefineEngineMethod(ShapeBase, getAIController, AIController*, (), , "")
{
return object->getAIController();
}

View file

@ -88,6 +88,8 @@ class ShapeBase;
class SFXSource;
class SFXTrack;
class SFXProfile;
struct AIController;
struct AIControllerData;
typedef void* Light;
@ -555,6 +557,7 @@ public:
U32 cubeDescId;
ReflectorDesc *reflectorDesc;
AIControllerData* mAIControllData;
/// @name Destruction
///
/// Everyone likes to blow things up!
@ -1754,6 +1757,11 @@ public:
/// Returns true if this object is controlling by something
bool isControlled() { return(mIsControlled); }
AIController* mAIController;
bool setAIController(SimObjectId controller);
AIController* getAIController() { return mAIController; };
virtual bool getAIMove(Move* move);
/// Returns true if this object is being used as a camera in first person
bool isFirstPerson() const;

View file

@ -148,7 +148,6 @@ VehicleData::VehicleData()
collDamageMultiplier = 0.05f;
enablePhysicsRep = true;
mControlMap = StringTable->EmptyString();
mAIControllData = NULL;
}
@ -325,9 +324,7 @@ void VehicleData::initPersistFields()
addGroup("Movement");
addField("controlMap", TypeString, Offset(mControlMap, VehicleData),
"@brief movemap used by these types of objects.\n\n");
addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, VehicleData),
"@brief ai controller used by these types of objects.\n\n");
endGroup("Collision");
endGroup("Movement");
addGroup("Steering");
addFieldV( "jetForce", TypeRangedF32, Offset(jetForce, VehicleData), &CommonValidators::PositiveFloat,
@ -414,7 +411,6 @@ Vehicle::Vehicle()
mWorkingQueryBoxCountDown = sWorkingQueryBoxStaleThreshold;
mPhysicsRep = NULL;
mAIController = NULL;
}
U32 Vehicle::getCollisionMask()
@ -481,7 +477,6 @@ bool Vehicle::onAdd()
void Vehicle::onRemove()
{
SAFE_DELETE(mPhysicsRep);
if (mAIController) mAIController->deleteObject();
U32 i=0;
for( i=0; i<VehicleData::VC_NUM_DAMAGE_EMITTERS; i++ )
@ -1236,37 +1231,3 @@ void Vehicle::_renderMuzzleVector( ObjectRenderInst *ri, SceneRenderState *state
PrimBuild::end();
}
bool Vehicle::setAIController(SimObjectId controller)
{
if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
{
mAIController->setAIInfo(this);
return true;
}
Con::errorf("unable to find AIController : %i", controller);
mAIController = NULL;
return false;
}
bool Vehicle::getAIMove(Move* move)
{
if (!isServerObject()) return false;
if (mAIController)
{
mAIController->getAIMove(move); //actual result
return true;
}
return false;
}
DefineEngineMethod(Vehicle, setAIController, bool, (S32 controller), , "")
{
return object->setAIController(controller);
}
DefineEngineMethod(Vehicle, getAIController, AIController*, (), , "")
{
return object->getAIController();
}

View file

@ -73,7 +73,6 @@ struct VehicleData : public RigidShapeData
bool enablePhysicsRep;
StringTableEntry mControlMap;
AIControllerData* mAIControllData;
//
VehicleData();
@ -102,7 +101,6 @@ class Vehicle : public RigidShape
Point2F mSteering;
F32 mThrottle;
bool mJetting;
AIController* mAIController;
GFXStateBlockRef mSolidSB;
SimObjectPtr<ParticleEmitter> mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS];
@ -152,9 +150,6 @@ public:
Point2F getSteering() { return mSteering; };
F32 getThrottle() { return mThrottle;};
bool setAIController(SimObjectId controller);
AIController* getAIController() { return mAIController; };
virtual bool getAIMove(Move*);
/// Interpolates between move ticks @see processTick
/// @param dt Change in time between the last call and this call to the function

View file

@ -82,7 +82,7 @@ ImplementBitfieldType(GameTypeMasksType,
{ SceneObjectTypes::PathShapeObjectType, "$TypeMasks::PathShapeObjectType", "Path-following Objects.\n" },
{ SceneObjectTypes::TurretObjectType, "$TypeMasks::TurretObjectType", "Turret Objects.\n" },
{ SceneObjectTypes::N_A_31, "$TypeMasks::N_A_31", "unused 31st bit.\n" },
{ SceneObjectTypes::N_A_32, "$TypeMasks::N_A_32", "unused 32nd bit.\n" },
{ SceneObjectTypes::AIObjectType, "$TypeMasks::AIObjectType", "AIObjectType.\n" },
EndImplementBitfieldType;

View file

@ -37,6 +37,7 @@
#include "gui/buttons/guiButtonCtrl.h"
#include "gui/worldEditor/undoActions.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/AI/AIController.h"
IMPLEMENT_CONOBJECT(GuiNavEditorCtrl);
@ -226,12 +227,11 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
missionCleanup->addObject(obj);
}
mPlayer = obj;
Player* po = dynamic_cast<Player*>(obj);
if (!po) return; //todo, more types
if (po->getAIController())
ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj);
if (sbo->getAIController())
{
if (po->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
if (sbo->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
}
else
{
@ -398,12 +398,11 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
if(ri.object)
{
mPlayer = ri.object;
Player* po = dynamic_cast<Player*>(ri.object);
if (!po) return; //todo, more types
if (po->getAIController())
ShapeBase* sbo = dynamic_cast<ShapeBase*>(ri.object);
if (sbo->getAIController())
{
if (po->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
if (sbo->getAIController()->mControllerData)
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
}
else
{
@ -413,12 +412,11 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
}
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())
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
if (sbo->getAIController())
{
if (po->getAIController()->mControllerData)
po->getAIController()->getNav()->setPathDestination(ri.point,true);
if (sbo->getAIController()->mControllerData)
sbo->getAIController()->getNav()->setPathDestination(ri.point,true);
}
}
}