mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-16 10:50:53 +00:00
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:
parent
d36cf31707
commit
3210325f3f
15 changed files with 352 additions and 185 deletions
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ struct AINavigation
|
|||
/// Move to the specified node in the current path.
|
||||
void moveToNode(S32 node);
|
||||
|
||||
void flock();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ enum SceneObjectTypes
|
|||
/// @see TurretShape
|
||||
TurretObjectType = BIT(29),
|
||||
N_A_31 = BIT(30),
|
||||
N_A_32 = BIT(31),
|
||||
AIObjectType = BIT(31),
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue