mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 09:04:38 +00:00
helper functions for AI: testing if an object is in line of sight (and optionally if it's enabled), if a point is clear, and if an object is within a given angular field of view (optionally specified beyond a stock 45 degrees, as well as optionally checking if the target is enabled)
This commit is contained in:
parent
7a517d3cb1
commit
9342115b1e
2 changed files with 118 additions and 20 deletions
|
|
@ -28,6 +28,10 @@
|
||||||
#include "T3D/gameBase/moveManager.h"
|
#include "T3D/gameBase/moveManager.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
|
||||||
|
static U32 AIPLAYER_LOSMASK = TerrainObjectType | WaterObjectType |
|
||||||
|
ShapeBaseObjectType | StaticShapeObjectType |
|
||||||
|
PlayerObjectType | ItemObjectType;
|
||||||
|
|
||||||
IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
|
IMPLEMENT_CO_NETOBJECT_V1(AIPlayer);
|
||||||
|
|
||||||
ConsoleDocClass( AIPlayer,
|
ConsoleDocClass( AIPlayer,
|
||||||
|
|
@ -417,28 +421,19 @@ bool AIPlayer::getAIMove(Move *movePtr)
|
||||||
// Test for target location in sight if it's an object. The LOS is
|
// 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,
|
// run from the eye position to the center of the object's bounding,
|
||||||
// which is not very accurate.
|
// which is not very accurate.
|
||||||
if (mAimObject) {
|
if (mAimObject)
|
||||||
MatrixF eyeMat;
|
{
|
||||||
getEyeTransform(&eyeMat);
|
mTargetInLOS = checkInLos(mAimObject.getPointer(), false);
|
||||||
eyeMat.getColumn(3,&location);
|
if (mTargetInLOS)
|
||||||
Point3F targetLoc = mAimObject->getBoxCenter();
|
{
|
||||||
|
throwCallback("onTargetEnterLOS");
|
||||||
// This ray ignores non-static shapes. Cast Ray returns true
|
mTargetInLOS = true;
|
||||||
// if it hit something.
|
|
||||||
RayInfo dummy;
|
|
||||||
if (getContainer()->castRay( location, targetLoc,
|
|
||||||
StaticShapeObjectType | StaticObjectType |
|
|
||||||
TerrainObjectType, &dummy)) {
|
|
||||||
if (mTargetInLOS) {
|
|
||||||
throwCallback( "onTargetExitLOS" );
|
|
||||||
mTargetInLOS = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (!mTargetInLOS) {
|
{
|
||||||
throwCallback( "onTargetEnterLOS" );
|
throwCallback("onTargetExitLOS");
|
||||||
mTargetInLOS = true;
|
mTargetInLOS = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replicate the trigger state into the move so that
|
// Replicate the trigger state into the move so that
|
||||||
|
|
@ -610,3 +605,103 @@ DefineEngineMethod( AIPlayer, getAimObject, S32, (),,
|
||||||
GameBase* obj = object->getAimObject();
|
GameBase* obj = object->getAimObject();
|
||||||
return obj? obj->getId(): -1;
|
return obj? obj->getId(): -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AIPlayer::checkInLos(GameBase* target, bool _checkEnabled = false)
|
||||||
|
{
|
||||||
|
if (!isServerObject()) return false;
|
||||||
|
if (!(bool(target))) return false;
|
||||||
|
if (_checkEnabled)
|
||||||
|
{
|
||||||
|
ShapeBase *shapeBaseCheck = dynamic_cast<ShapeBase *>(target);
|
||||||
|
if (shapeBaseCheck)
|
||||||
|
if (shapeBaseCheck->getDamageState() != Enabled) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RayInfo ri;
|
||||||
|
|
||||||
|
disableCollision();
|
||||||
|
|
||||||
|
S32 mountCount = target->getMountedObjectCount();
|
||||||
|
for (S32 i = 0; i < mountCount; i++)
|
||||||
|
{
|
||||||
|
target->getMountedObject(i)->disableCollision();
|
||||||
|
}
|
||||||
|
Point3F muzzlePoint;
|
||||||
|
getMuzzlePointAI(0, &muzzlePoint);
|
||||||
|
bool hit = gServerContainer.castRay(muzzlePoint, target->getBoxCenter(), AIPLAYER_LOSMASK, &ri);
|
||||||
|
enableCollision();
|
||||||
|
|
||||||
|
for (S32 i = 0; i < mountCount; i++)
|
||||||
|
{
|
||||||
|
target->getMountedObject(i)->enableCollision();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
if (target != dynamic_cast<GameBase*>(ri.object)) hit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPlayer::checkLosClear(Point3F _pos)
|
||||||
|
{
|
||||||
|
if (!isServerObject()) return false;
|
||||||
|
|
||||||
|
RayInfo ri;
|
||||||
|
|
||||||
|
disableCollision();
|
||||||
|
|
||||||
|
Point3F muzzlePoint;
|
||||||
|
getMuzzlePointAI(0, &muzzlePoint);
|
||||||
|
gServerContainer.castRay(muzzlePoint, _pos, AIPLAYER_LOSMASK, &ri);
|
||||||
|
bool emptySpace = bool(ri.object == NULL);
|
||||||
|
enableCollision();
|
||||||
|
return emptySpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, checkInLos, bool, (ShapeBase* obj, bool checkEnabled), (0, false),
|
||||||
|
"@brief Check for an object in line of sight.\n")
|
||||||
|
{
|
||||||
|
return object->checkInLos(obj, checkEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIPlayer::checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled = false)
|
||||||
|
{
|
||||||
|
if (!isServerObject()) return false;
|
||||||
|
if (!(bool(target))) return false;
|
||||||
|
if (_checkEnabled)
|
||||||
|
{
|
||||||
|
ShapeBase *shapeBaseCheck = dynamic_cast<ShapeBase *>(target);
|
||||||
|
if (shapeBaseCheck)
|
||||||
|
if (shapeBaseCheck->getDamageState() != Enabled) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatrixF cam = getTransform();
|
||||||
|
Point3F camPos;
|
||||||
|
VectorF camDir;
|
||||||
|
|
||||||
|
cam.getColumn(3, &camPos);
|
||||||
|
cam.getColumn(1, &camDir);
|
||||||
|
|
||||||
|
camFov = mDegToRad(camFov) / 2;
|
||||||
|
|
||||||
|
Point3F shapePos;
|
||||||
|
// Use the render transform instead of the box center
|
||||||
|
// otherwise it'll jitter.
|
||||||
|
MatrixF srtMat = target->getTransform();
|
||||||
|
srtMat.getColumn(3, &shapePos);
|
||||||
|
VectorF shapeDir = shapePos - camPos;
|
||||||
|
// Test to see if it's within our viewcone, this test doesn't
|
||||||
|
// actually match the viewport very well, should consider
|
||||||
|
// projection and box test.
|
||||||
|
shapeDir.normalize();
|
||||||
|
F32 dot = mDot(shapeDir, camDir);
|
||||||
|
return (dot > camFov);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineEngineMethod(AIPlayer, checkInFoV, bool, (ShapeBase* obj, F32 fov, bool checkEnabled), (0, 45, false),
|
||||||
|
"@brief Check for an object within a specified veiw cone.\n")
|
||||||
|
{
|
||||||
|
return object->checkInFoV(obj, fov, checkEnabled);
|
||||||
|
}
|
||||||
|
|
@ -80,6 +80,9 @@ public:
|
||||||
void setAimLocation( const Point3F &location );
|
void setAimLocation( const Point3F &location );
|
||||||
Point3F getAimLocation() const { return mAimLocation; }
|
Point3F getAimLocation() const { return mAimLocation; }
|
||||||
void clearAim();
|
void clearAim();
|
||||||
|
bool checkInLos(GameBase* target, bool _checkEnabled);
|
||||||
|
bool checkLosClear(Point3F _pos);
|
||||||
|
bool checkInFoV(GameBase* target, F32 camFov, bool _checkEnabled);
|
||||||
|
|
||||||
// Movement sets/gets
|
// Movement sets/gets
|
||||||
void setMoveSpeed( const F32 speed );
|
void setMoveSpeed( const F32 speed );
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue