mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-21 15:43:45 +00:00
added navmesh tester tool
Added ground work for tester tool tester tool works but needs to fill out list of acceptable datablocks and spawnclasses navpaths now share 1 navmeshquery AIControllerData now has a vector of area costs for different polyareas General cleanup
This commit is contained in:
parent
edf4d47be0
commit
6d36e17d91
17 changed files with 604 additions and 421 deletions
|
|
@ -535,6 +535,10 @@ AIControllerData::AIControllerData()
|
|||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
mLinkTypes = LinkData(AllFlags);
|
||||
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||
mFilter.setExcludeFlags(0);
|
||||
mAreaCosts.setSize(PolyAreas::NumAreas);
|
||||
mAreaCosts.fill(1.0f);
|
||||
mNavSize = AINavigation::Regular;
|
||||
mFlocking.mChance = 90;
|
||||
mFlocking.mMin = 1.0f;
|
||||
|
|
@ -560,6 +564,8 @@ AIControllerData::AIControllerData(const AIControllerData& other, bool temp_clon
|
|||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
mLinkTypes = other.mLinkTypes;
|
||||
mFilter = other.mFilter;
|
||||
mAreaCosts = other.mAreaCosts;
|
||||
mNavSize = other.mNavSize;
|
||||
mFlocking.mChance = other.mFlocking.mChance;
|
||||
mFlocking.mMin = other.mFlocking.mMin;
|
||||
|
|
@ -629,6 +635,8 @@ void AIControllerData::initPersistFields()
|
|||
addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat,
|
||||
"@brief Distance from destination before we stop moving out of the way.");
|
||||
|
||||
addField("areaCosts", TypeF32Vector, Offset(mAreaCosts, AIControllerData),
|
||||
"Vector of costs for each PolyArea.");
|
||||
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIControllerData),
|
||||
"Allow the character to walk on dry land.");
|
||||
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIControllerData),
|
||||
|
|
@ -662,6 +670,10 @@ void AIControllerData::packData(BitStream* stream)
|
|||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
//enums
|
||||
stream->write(mAreaCosts.size());
|
||||
for (U32 i = 0; i < mAreaCosts.size(); i++) {
|
||||
stream->write(mAreaCosts[i]);
|
||||
}
|
||||
stream->write(mLinkTypes.getFlags());
|
||||
stream->write((U32)mNavSize);
|
||||
// end enums
|
||||
|
|
@ -684,10 +696,23 @@ void AIControllerData::unpackData(BitStream* stream)
|
|||
stream->read(&mFollowTolerance);
|
||||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
U32 num;
|
||||
stream->read(&num);
|
||||
mAreaCosts.setSize(num);
|
||||
for (U32 i = 0; i < num; i++)
|
||||
{
|
||||
stream->read(&mAreaCosts[i]);
|
||||
}
|
||||
//enums
|
||||
U16 linkFlags;
|
||||
stream->read(&linkFlags);
|
||||
mLinkTypes = LinkData(linkFlags);
|
||||
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||
mFilter.setExcludeFlags(mLinkTypes.getExcludeFlags());
|
||||
for (U32 i = 0; i < PolyAreas::NumAreas; i++)
|
||||
{
|
||||
mFilter.setAreaCost((PolyAreas)i, mAreaCosts[i]);
|
||||
}
|
||||
U32 navSize;
|
||||
stream->read(&navSize);
|
||||
mNavSize = (AINavigation::NavSize)(navSize);
|
||||
|
|
|
|||
|
|
@ -168,6 +168,8 @@ public:
|
|||
|
||||
/// Types of link we can use.
|
||||
LinkData mLinkTypes;
|
||||
dtQueryFilter mFilter;
|
||||
Vector<F32> mAreaCosts;
|
||||
AINavigation::NavSize mNavSize;
|
||||
#endif
|
||||
Delegate<void(AIController* obj, Point3F location, Move* movePtr)> resolveYawPtr;
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ bool AINavigation::setPathDestination(const Point3F& pos, bool replace)
|
|||
path->mAlwaysRender = true;
|
||||
path->mLinkTypes = getCtrl()->mControllerData->mLinkTypes;
|
||||
path->mXray = true;
|
||||
path->mFilter = getCtrl()->mControllerData->mFilter;
|
||||
// Paths plan automatically upon being registered.
|
||||
if (!path->registerObject())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ AIPlayer::AIPlayer()
|
|||
mJump = None;
|
||||
mNavSize = Regular;
|
||||
mLinkTypes = LinkData(AllFlags);
|
||||
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||
mFilter.setExcludeFlags(0);
|
||||
mAreaCosts.setSize(PolyAreas::NumAreas);
|
||||
mAreaCosts.fill(1.0f);
|
||||
#endif
|
||||
|
||||
mIsAiControlled = true;
|
||||
|
|
@ -163,7 +167,8 @@ void AIPlayer::initPersistFields()
|
|||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
addGroup("Pathfinding");
|
||||
|
||||
addField("areaCosts", TypeF32Vector, Offset(mAreaCosts, AIPlayer),
|
||||
"Vector of costs for each PolyArea.");
|
||||
addField("allowWalk", TypeBool, Offset(mLinkTypes.walk, AIPlayer),
|
||||
"Allow the character to walk on dry land.");
|
||||
addField("allowJump", TypeBool, Offset(mLinkTypes.jump, AIPlayer),
|
||||
|
|
@ -785,6 +790,7 @@ void AIPlayer::moveToNode(S32 node)
|
|||
|
||||
bool AIPlayer::setPathDestination(const Point3F &pos)
|
||||
{
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
// Pathfinding only happens on the server.
|
||||
if(!isServerObject())
|
||||
return false;
|
||||
|
|
@ -799,6 +805,13 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
|
|||
return false;
|
||||
}
|
||||
|
||||
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||
mFilter.setExcludeFlags(mLinkTypes.getExcludeFlags());
|
||||
for (U32 i = 0; i < PolyAreas::NumAreas; i++)
|
||||
{
|
||||
mFilter.setAreaCost((PolyAreas)i, mAreaCosts[i]);
|
||||
}
|
||||
|
||||
// Create a new path.
|
||||
NavPath *path = new NavPath();
|
||||
|
||||
|
|
@ -808,6 +821,7 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
|
|||
path->mFromSet = path->mToSet = true;
|
||||
path->mAlwaysRender = true;
|
||||
path->mLinkTypes = mLinkTypes;
|
||||
path->mFilter = mFilter;
|
||||
path->mXray = true;
|
||||
// Paths plan automatically upon being registered.
|
||||
if(!path->registerObject())
|
||||
|
|
@ -839,6 +853,9 @@ bool AIPlayer::setPathDestination(const Point3F &pos)
|
|||
path->deleteObject();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
setMoveDestination(pos, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIPlayer, setPathDestination, bool, (Point3F goal),,
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ GuiNavEditorCtrl::GuiNavEditorCtrl()
|
|||
mIsDirty = false;
|
||||
mStartDragMousePoint = InvalidMousePoint;
|
||||
mMesh = NULL;
|
||||
mPlayer = mCurPlayer = NULL;
|
||||
mSpawnClass = mSpawnDatablock = "";
|
||||
}
|
||||
|
||||
GuiNavEditorCtrl::~GuiNavEditorCtrl()
|
||||
|
|
@ -97,11 +95,6 @@ void GuiNavEditorCtrl::initPersistFields()
|
|||
docsURL;
|
||||
addField("isDirty", TypeBool, Offset(mIsDirty, GuiNavEditorCtrl));
|
||||
|
||||
addField("spawnClass", TypeRealString, Offset(mSpawnClass, GuiNavEditorCtrl),
|
||||
"Class of object to spawn in test mode.");
|
||||
addField("spawnDatablock", TypeRealString, Offset(mSpawnDatablock, GuiNavEditorCtrl),
|
||||
"Datablock to give new objects in test mode.");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
|
@ -140,79 +133,6 @@ DefineEngineMethod(GuiNavEditorCtrl, getMesh, S32, (),,
|
|||
return object->getMeshId();
|
||||
}
|
||||
|
||||
S32 GuiNavEditorCtrl::getPlayerId()
|
||||
{
|
||||
return mPlayer.isNull() ? 0 : mPlayer->getId();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiNavEditorCtrl, getPlayer, S32, (),,
|
||||
"@brief Select a NavMesh object.")
|
||||
{
|
||||
return object->getPlayerId();
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::deselect()
|
||||
{
|
||||
if(!mMesh.isNull())
|
||||
mMesh->setSelected(false);
|
||||
mMesh = NULL;
|
||||
mPlayer = mCurPlayer = NULL;
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiNavEditorCtrl, deselect, void, (),,
|
||||
"@brief Deselect whatever is currently selected in the editor.")
|
||||
{
|
||||
object->deselect();
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
|
||||
{
|
||||
SceneObject *obj = (SceneObject*)Sim::spawnObject(mSpawnClass, mSpawnDatablock);
|
||||
if(obj)
|
||||
{
|
||||
MatrixF mat(true);
|
||||
mat.setPosition(pos);
|
||||
obj->setTransform(mat);
|
||||
SimObject* cleanup = Sim::findObject("MissionCleanup");
|
||||
if(cleanup)
|
||||
{
|
||||
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
|
||||
missionCleanup->addObject(obj);
|
||||
}
|
||||
mPlayer = obj;
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(obj);
|
||||
if (asAIPlayer) //try direct
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj);
|
||||
if (sbo->getAIController())
|
||||
{
|
||||
if (sbo->getAIController()->mControllerData)
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiNavEditorCtrl, spawnPlayer, void, (),,
|
||||
"@brief Spawn an AIPlayer at the centre of the screen.")
|
||||
{
|
||||
Point3F c;
|
||||
if(object->get3DCentre(c))
|
||||
object->spawnPlayer(c);
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::get3DCursor(GuiCursor *&cursor,
|
||||
bool &visible,
|
||||
const Gui3DMouseEvent &event_)
|
||||
|
|
@ -277,89 +197,6 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
|
|||
mouseLock();
|
||||
|
||||
return;
|
||||
|
||||
// Construct a LineSegment from the camera position to 1000 meters away in
|
||||
// the direction clicked.
|
||||
// If that segment hits the terrain, truncate the ray to only be that length.
|
||||
|
||||
Point3F startPnt = event.pos;
|
||||
Point3F endPnt = event.pos + event.vec * 1000.0f;
|
||||
|
||||
RayInfo ri;
|
||||
|
||||
U8 keys = Input::getModifierKeys();
|
||||
bool shift = keys & SI_LSHIFT;
|
||||
bool ctrl = keys & SI_LCTRL;
|
||||
|
||||
if(mMode == mTestMode)
|
||||
{
|
||||
// Spawn new character
|
||||
if(ctrl)
|
||||
{
|
||||
if(gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
spawnPlayer(ri.point);
|
||||
}
|
||||
// Deselect character
|
||||
else if(shift)
|
||||
{
|
||||
mPlayer = NULL;
|
||||
Con::executef(this, "onPlayerDeselected");
|
||||
}
|
||||
// Select/move character
|
||||
else
|
||||
{
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
{
|
||||
if(ri.object)
|
||||
{
|
||||
mPlayer = ri.object;
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
|
||||
if (asAIPlayer) //try direct
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
|
||||
if (sbo->getAIController())
|
||||
{
|
||||
if (sbo->getAIController()->mControllerData)
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
}
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
{
|
||||
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
|
||||
if (asAIPlayer) //try direct
|
||||
{
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
asAIPlayer->setPathDestination(ri.point);
|
||||
#else
|
||||
asAIPlayer->setMoveDestination(ri.point,false);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
|
||||
if (sbo->getAIController())
|
||||
{
|
||||
if (sbo->getAIController()->mControllerData)
|
||||
sbo->getAIController()->getNav()->setPathDestination(ri.point, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::on3DMouseUp(const Gui3DMouseEvent & event)
|
||||
|
|
@ -385,22 +222,6 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
|
|||
mTool->on3DMouseMove(event);
|
||||
|
||||
return;
|
||||
|
||||
//if(mSelRiver != NULL && mSelNode != -1)
|
||||
//mGizmo->on3DMouseMove(event);
|
||||
|
||||
Point3F startPnt = event.pos;
|
||||
Point3F endPnt = event.pos + event.vec * 1000.0f;
|
||||
|
||||
RayInfo ri;
|
||||
|
||||
if(mMode == mTestMode)
|
||||
{
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
mCurPlayer = ri.object;
|
||||
else
|
||||
mCurPlayer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event)
|
||||
|
|
@ -443,22 +264,6 @@ void GuiNavEditorCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
return;
|
||||
}
|
||||
|
||||
static void renderBoxOutline(const Box3F &box, const ColorI &col)
|
||||
{
|
||||
if(box != Box3F::Invalid)
|
||||
{
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setCullMode(GFXCullNone);
|
||||
desc.setFillModeSolid();
|
||||
desc.setZReadWrite(true, false);
|
||||
desc.setBlend(true);
|
||||
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 20));
|
||||
desc.setFillModeWireframe();
|
||||
desc.setBlend(false);
|
||||
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 255));
|
||||
}
|
||||
}
|
||||
|
||||
void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
|
||||
{
|
||||
GFX->setStateBlock(mZDisableSB);
|
||||
|
|
@ -479,14 +284,6 @@ void GuiNavEditorCtrl::renderScene(const RectI & updateRect)
|
|||
if (mTool)
|
||||
mTool->onRender3D();
|
||||
|
||||
if(mMode == mTestMode)
|
||||
{
|
||||
if(!mCurPlayer.isNull())
|
||||
renderBoxOutline(mCurPlayer->getWorldBox(), ColorI::BLUE);
|
||||
if(!mPlayer.isNull())
|
||||
renderBoxOutline(mPlayer->getWorldBox(), ColorI::GREEN);
|
||||
}
|
||||
|
||||
duDebugDrawTorque d;
|
||||
if(!mMesh.isNull())
|
||||
mMesh->renderLinks(d);
|
||||
|
|
|
|||
|
|
@ -103,17 +103,8 @@ public:
|
|||
String getMode() { return mMode; }
|
||||
|
||||
void selectMesh(NavMesh *mesh);
|
||||
void deselect();
|
||||
|
||||
S32 getMeshId();
|
||||
S32 getPlayerId();
|
||||
|
||||
String mSpawnClass;
|
||||
String mSpawnDatablock;
|
||||
|
||||
void deleteLink();
|
||||
void setLinkFlags(const LinkData &d);
|
||||
void spawnPlayer(const Point3F &pos);
|
||||
|
||||
/// @}
|
||||
void setActiveTool(NavMeshTool* tool);
|
||||
|
|
@ -148,14 +139,6 @@ protected:
|
|||
|
||||
/// @}
|
||||
|
||||
/// @name Test mode
|
||||
/// @{
|
||||
|
||||
SimObjectPtr<SceneObject> mPlayer;
|
||||
SimObjectPtr<SceneObject> mCurPlayer;
|
||||
|
||||
/// @}
|
||||
|
||||
Gui3DMouseEvent mLastMouseEvent;
|
||||
|
||||
#define InvalidMousePoint Point2I(-100,-100)
|
||||
|
|
|
|||
|
|
@ -225,10 +225,13 @@ NavMesh::NavMesh()
|
|||
|
||||
mWaterVertStart = 0;
|
||||
mWaterTriStart = 0;
|
||||
|
||||
mQuery = NULL;
|
||||
}
|
||||
|
||||
NavMesh::~NavMesh()
|
||||
{
|
||||
dtFreeNavMeshQuery(mQuery);
|
||||
dtFreeNavMesh(nm);
|
||||
nm = NULL;
|
||||
delete ctx;
|
||||
|
|
@ -677,32 +680,6 @@ bool NavMesh::build(bool background, bool saveIntermediates)
|
|||
return false;
|
||||
}
|
||||
|
||||
Box3F worldBox = getWorldBox();
|
||||
SceneContainer::CallbackInfo info;
|
||||
info.context = PLC_Navigation;
|
||||
info.boundingBox = worldBox;
|
||||
m_geo = new RecastPolyList;
|
||||
info.polyList = m_geo;
|
||||
info.key = this;
|
||||
getContainer()->findObjects(worldBox, StaticObjectType | DynamicShapeObjectType, buildCallback, &info);
|
||||
|
||||
// Parse water objects into the same list, but remember how much geometry was /not/ water.
|
||||
mWaterVertStart = m_geo->getVertCount();
|
||||
mWaterTriStart = m_geo->getTriCount();
|
||||
if (mWaterMethod != Ignore)
|
||||
{
|
||||
getContainer()->findObjects(worldBox, WaterObjectType, buildCallback, &info);
|
||||
}
|
||||
|
||||
// Check for no geometry.
|
||||
if (!m_geo->getVertCount())
|
||||
{
|
||||
m_geo->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_geo->getChunkyMesh();
|
||||
|
||||
// Needed for the recast config and generation params.
|
||||
Box3F rc_box = DTStoRC(getWorldBox());
|
||||
S32 gw = 0, gh = 0;
|
||||
|
|
@ -803,33 +780,6 @@ void NavMesh::createNewFile()
|
|||
mFileName = StringTable->insert(fileName.c_str());
|
||||
}
|
||||
|
||||
void NavMesh::updateConfig()
|
||||
{
|
||||
//// Build rcConfig object from our console members.
|
||||
//dMemset(&cfg, 0, sizeof(cfg));
|
||||
//cfg.cs = mCellSize;
|
||||
//cfg.ch = mCellHeight;
|
||||
//Box3F box = DTStoRC(getWorldBox());
|
||||
//rcVcopy(cfg.bmin, box.minExtents);
|
||||
//rcVcopy(cfg.bmax, box.maxExtents);
|
||||
//rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
|
||||
|
||||
//cfg.walkableHeight = mCeil(mWalkableHeight / mCellHeight);
|
||||
//cfg.walkableClimb = mCeil(mWalkableClimb / mCellHeight);
|
||||
//cfg.walkableRadius = mCeil(mWalkableRadius / mCellSize);
|
||||
//cfg.walkableSlopeAngle = mWalkableSlope;
|
||||
//cfg.borderSize = cfg.walkableRadius + 3;
|
||||
|
||||
//cfg.detailSampleDist = mDetailSampleDist;
|
||||
//cfg.detailSampleMaxError = mDetailSampleMaxError;
|
||||
//cfg.maxEdgeLen = mMaxEdgeLen;
|
||||
//cfg.maxSimplificationError = mMaxSimplificationError;
|
||||
//cfg.maxVertsPerPoly = mMaxVertsPerPoly;
|
||||
//cfg.minRegionArea = mMinRegionArea;
|
||||
//cfg.mergeRegionArea = mMergeRegionArea;
|
||||
//cfg.tileSize = mTileSize / cfg.cs;
|
||||
}
|
||||
|
||||
S32 NavMesh::getTile(const Point3F& pos)
|
||||
{
|
||||
if(mBuilding)
|
||||
|
|
@ -938,6 +888,8 @@ void NavMesh::buildNextTile()
|
|||
|
||||
if(!mDirtyTiles.empty())
|
||||
{
|
||||
dtFreeNavMeshQuery(mQuery);
|
||||
mQuery = NULL;
|
||||
// Pop a single dirty tile and process it.
|
||||
U32 i = mDirtyTiles.front();
|
||||
mDirtyTiles.pop_front();
|
||||
|
|
@ -1002,6 +954,12 @@ void NavMesh::buildNextTile()
|
|||
// Did we just build the last tile?
|
||||
if(mDirtyTiles.empty())
|
||||
{
|
||||
mQuery = dtAllocNavMeshQuery();
|
||||
if (dtStatusFailed(mQuery->init(nm, 2048)))
|
||||
{
|
||||
Con::errorf("NavMesh - Failed to create navmesh query");
|
||||
}
|
||||
|
||||
ctx->stopTimer(RC_TIMER_TOTAL);
|
||||
if(getEventManager())
|
||||
{
|
||||
|
|
@ -1012,6 +970,15 @@ void NavMesh::buildNextTile()
|
|||
mBuilding = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mQuery == NULL)
|
||||
{
|
||||
mQuery = dtAllocNavMeshQuery();
|
||||
if (dtStatusFailed(mQuery->init(nm, 2048)))
|
||||
{
|
||||
Con::errorf("NavMesh - Failed to create navmesh query");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *NavMesh::buildTileData(const Tile &tile, U32 &dataSize)
|
||||
|
|
@ -1614,11 +1581,13 @@ void NavMesh::renderToDrawer()
|
|||
m_drawMode == DRAWMODE_NAVMESH_INVIS))
|
||||
{
|
||||
if (m_drawMode != DRAWMODE_NAVMESH_INVIS)
|
||||
duDebugDrawNavMesh(&mDbgDraw, *n->nm, 0);
|
||||
duDebugDrawNavMeshWithClosedList(&mDbgDraw, *n->nm, *n->mQuery, 0);
|
||||
if(m_drawMode == DRAWMODE_NAVMESH_BVTREE)
|
||||
duDebugDrawNavMeshBVTree(&mDbgDraw, *n->nm);
|
||||
if(m_drawMode == DRAWMODE_NAVMESH_PORTALS)
|
||||
duDebugDrawNavMeshPortals(&mDbgDraw, *n->nm);
|
||||
if (m_drawMode == DRAWMODE_NAVMESH_NODES)
|
||||
duDebugDrawNavMeshNodes(&mDbgDraw, *n->mQuery);
|
||||
}
|
||||
|
||||
mDbgDraw.depthMask(true, false);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,8 @@ public:
|
|||
/// Delete the selected link.
|
||||
void deleteLink(U32 idx);
|
||||
|
||||
dtNavMeshQuery* getNavMeshQuery() { return mQuery; }
|
||||
|
||||
/// @}
|
||||
|
||||
/// Should small characters use this mesh?
|
||||
|
|
@ -381,16 +383,9 @@ private:
|
|||
|
||||
/// @}
|
||||
|
||||
/// @name Intermediate data
|
||||
/// @{
|
||||
|
||||
/// Updates our config from console members.
|
||||
void updateConfig();
|
||||
|
||||
dtNavMesh *nm;
|
||||
rcContext *ctx;
|
||||
|
||||
/// @}
|
||||
dtNavMeshQuery* mQuery;
|
||||
|
||||
/// @name Cover
|
||||
/// @{
|
||||
|
|
|
|||
302
Engine/source/navigation/navMeshTools/navMeshTestTool.cpp
Normal file
302
Engine/source/navigation/navMeshTools/navMeshTestTool.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
#include "navMeshTestTool.h"
|
||||
#include "navigation/guiNavEditorCtrl.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "T3D/AI/AIController.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(NavMeshTestTool);
|
||||
|
||||
//// take control
|
||||
// GameConnection* conn = GameConnection::getConnectionToServer();
|
||||
// if (conn)
|
||||
// conn->setControlObject(static_cast<GameBase*>(obj));
|
||||
//}
|
||||
|
||||
static void renderBoxOutline(const Box3F& box, const ColorI& col)
|
||||
{
|
||||
if (box != Box3F::Invalid)
|
||||
{
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setCullMode(GFXCullNone);
|
||||
desc.setFillModeSolid();
|
||||
desc.setZReadWrite(true, false);
|
||||
desc.setBlend(true);
|
||||
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 20));
|
||||
desc.setFillModeWireframe();
|
||||
desc.setBlend(false);
|
||||
GFX->getDrawUtil()->drawCube(desc, box, ColorI(col, 255));
|
||||
}
|
||||
}
|
||||
|
||||
void NavMeshTestTool::spawnPlayer(const Point3F& position)
|
||||
{
|
||||
if (mSpawnClass.isEmpty() || mSpawnDatablock.isEmpty())
|
||||
{
|
||||
Con::warnf("NavMeshTestTool::spawnPlayer - spawn class/datablock not set!");
|
||||
return;
|
||||
}
|
||||
|
||||
SimObject* spawned = Sim::spawnObject(mSpawnClass, mSpawnDatablock);
|
||||
SceneObject* obj = dynamic_cast<SceneObject*>(spawned);
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
Con::warnf("NavMeshTestTool::spawnPlayer - spawn failed or not a SceneObject");
|
||||
if (spawned)
|
||||
spawned->deleteObject();
|
||||
return;
|
||||
}
|
||||
|
||||
obj->setPosition(position);
|
||||
obj->registerObject();
|
||||
SimObject* cleanup = Sim::findObject("MissionCleanup");
|
||||
if (cleanup)
|
||||
{
|
||||
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
|
||||
missionCleanup->addObject(obj);
|
||||
}
|
||||
mPlayer = obj;
|
||||
|
||||
Con::executef(this, "onPlayerSpawned", obj->getIdString());
|
||||
}
|
||||
|
||||
void NavMeshTestTool::drawAgent(duDebugDrawTorque& dd, const F32* pos, F32 r, F32 h, F32 c, const U32 col)
|
||||
{
|
||||
dd.depthMask(false);
|
||||
|
||||
// Agent dimensions.
|
||||
duDebugDrawCylinderWire(&dd, pos[0] - r, pos[1] + 0.02f, pos[2] - r, pos[0] + r, pos[1] + h, pos[2] + r, col, 2.0f);
|
||||
|
||||
duDebugDrawCircle(&dd, pos[0], pos[1] + c, pos[2], r, duRGBA(0, 0, 0, 64), 1.0f);
|
||||
|
||||
U32 colb = duRGBA(0, 0, 0, 196);
|
||||
dd.begin(DU_DRAW_LINES);
|
||||
dd.vertex(pos[0], pos[1] - c, pos[2], colb);
|
||||
dd.vertex(pos[0], pos[1] + c, pos[2], colb);
|
||||
dd.vertex(pos[0] - r / 2, pos[1] + 0.02f, pos[2], colb);
|
||||
dd.vertex(pos[0] + r / 2, pos[1] + 0.02f, pos[2], colb);
|
||||
dd.vertex(pos[0], pos[1] + 0.02f, pos[2] - r / 2, colb);
|
||||
dd.vertex(pos[0], pos[1] + 0.02f, pos[2] + r / 2, colb);
|
||||
dd.end();
|
||||
|
||||
dd.depthMask(true);
|
||||
}
|
||||
|
||||
NavMeshTestTool::NavMeshTestTool()
|
||||
{
|
||||
mSpawnClass = String::EmptyString;
|
||||
mSpawnDatablock = String::EmptyString;
|
||||
mPlayer = NULL;
|
||||
mCurPlayer = NULL;
|
||||
|
||||
mPathStart = Point3F::Max;
|
||||
mPathEnd = Point3F::Max;
|
||||
}
|
||||
|
||||
void NavMeshTestTool::onActivated(const Gui3DMouseEvent& evt)
|
||||
{
|
||||
Con::executef(this, "onActivated");
|
||||
}
|
||||
|
||||
void NavMeshTestTool::onDeactivated()
|
||||
{
|
||||
Con::executef(this, "onDeactivated");
|
||||
}
|
||||
|
||||
void NavMeshTestTool::on3DMouseDown(const Gui3DMouseEvent& evt)
|
||||
{
|
||||
if (mNavMesh.isNull())
|
||||
return;
|
||||
|
||||
Point3F startPnt = evt.pos;
|
||||
Point3F endPnt = evt.pos + evt.vec * 1000.0f;
|
||||
|
||||
RayInfo ri;
|
||||
bool shift = evt.modifier & SI_LSHIFT;
|
||||
bool ctrl = evt.modifier & SI_LCTRL;
|
||||
|
||||
if (ctrl)
|
||||
{
|
||||
if (gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
{
|
||||
spawnPlayer(ri.point);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (shift)
|
||||
{
|
||||
mPlayer = NULL;
|
||||
Con::executef(this, "onPlayerDeselected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
{
|
||||
if (!ri.object)
|
||||
return;
|
||||
|
||||
mPlayer = ri.object;
|
||||
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
|
||||
if (asAIPlayer)
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(asAIPlayer->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
|
||||
if (sbo && sbo->getAIController() && sbo->getAIController()->mControllerData)
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
}
|
||||
}
|
||||
#else
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
#endif
|
||||
}
|
||||
else if (gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
{
|
||||
if (mPlayer.isNull())
|
||||
{
|
||||
if (mPathStart != Point3F::Max && mPathEnd != Point3F::Max) // start a new path.
|
||||
{
|
||||
mPathStart = Point3F::Max;
|
||||
mPathEnd = Point3F::Max;
|
||||
}
|
||||
|
||||
if (mPathStart != Point3F::Max)
|
||||
{
|
||||
mPathEnd = ri.point;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPathStart = ri.point;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AIPlayer* asAIPlayer = dynamic_cast<AIPlayer*>(mPlayer.getPointer());
|
||||
if (asAIPlayer) //try direct
|
||||
{
|
||||
asAIPlayer->setPathDestination(ri.point);
|
||||
mPathStart = mPlayer->getPosition();
|
||||
mPathEnd = ri.point;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
|
||||
if (sbo->getAIController())
|
||||
{
|
||||
if (sbo->getAIController()->mControllerData)
|
||||
{
|
||||
sbo->getAIController()->getNav()->setPathDestination(ri.point, true);
|
||||
mPathStart = mPlayer->getPosition();
|
||||
mPathEnd = ri.point;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NavMeshTestTool::on3DMouseMove(const Gui3DMouseEvent& evt)
|
||||
{
|
||||
if (mNavMesh.isNull())
|
||||
return;
|
||||
|
||||
Point3F startPnt = evt.pos;
|
||||
Point3F endPnt = evt.pos + evt.vec * 1000.0f;
|
||||
|
||||
RayInfo ri;
|
||||
|
||||
if (gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
mCurPlayer = ri.object;
|
||||
else
|
||||
mCurPlayer = NULL;
|
||||
|
||||
}
|
||||
|
||||
void NavMeshTestTool::onRender3D()
|
||||
{
|
||||
if (mNavMesh.isNull())
|
||||
return;
|
||||
|
||||
static const U32 startCol = duRGBA(128, 25, 0, 192);
|
||||
static const U32 endCol = duRGBA(51, 102, 0, 129);
|
||||
|
||||
const F32 agentRadius = mNavMesh->mWalkableRadius;
|
||||
const F32 agentHeight = mNavMesh->mWalkableHeight;
|
||||
const F32 agentClimb = mNavMesh->mWalkableClimb;
|
||||
|
||||
duDebugDrawTorque dd;
|
||||
dd.depthMask(false);
|
||||
if (mPathStart != Point3F::Max)
|
||||
{
|
||||
drawAgent(dd, DTStoRC(mPathStart), agentRadius, agentHeight, agentClimb, startCol);
|
||||
}
|
||||
|
||||
if (mPathEnd != Point3F::Max)
|
||||
{
|
||||
drawAgent(dd, DTStoRC(mPathEnd), agentRadius, agentHeight, agentClimb, endCol);
|
||||
}
|
||||
dd.depthMask(true);
|
||||
|
||||
dd.immediateRender();
|
||||
|
||||
if (!mCurPlayer.isNull())
|
||||
renderBoxOutline(mCurPlayer->getWorldBox(), ColorI::BLUE);
|
||||
if (!mPlayer.isNull())
|
||||
renderBoxOutline(mPlayer->getWorldBox(), ColorI::GREEN);
|
||||
}
|
||||
|
||||
bool NavMeshTestTool::updateGuiInfo()
|
||||
{
|
||||
SimObject* statusbar;
|
||||
Sim::findObject("EditorGuiStatusBar", statusbar);
|
||||
|
||||
GuiTextCtrl* selectionBar;
|
||||
Sim::findObject("EWorldEditorStatusBarSelection", selectionBar);
|
||||
|
||||
String text;
|
||||
|
||||
if (statusbar)
|
||||
Con::executef(statusbar, "setInfo", text.c_str());
|
||||
|
||||
text = "";
|
||||
|
||||
if (selectionBar)
|
||||
selectionBar->setText(text);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
S32 NavMeshTestTool::getPlayerId()
|
||||
{
|
||||
return mPlayer.isNull() ? 0 : mPlayer->getId();
|
||||
}
|
||||
|
||||
DefineEngineMethod(NavMeshTestTool, getPlayer, S32, (), ,
|
||||
"@brief Return the current player id.")
|
||||
{
|
||||
return object->getPlayerId();
|
||||
}
|
||||
|
||||
DefineEngineMethod(NavMeshTestTool, setSpawnClass, void, (String className), , "")
|
||||
{
|
||||
object->setSpawnClass(className);
|
||||
}
|
||||
|
||||
DefineEngineMethod(NavMeshTestTool, setSpawnDatablock, void, (String dbName), , "")
|
||||
{
|
||||
object->setSpawnDatablock(dbName);
|
||||
}
|
||||
47
Engine/source/navigation/navMeshTools/navMeshTestTool.h
Normal file
47
Engine/source/navigation/navMeshTools/navMeshTestTool.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef _NAVMESHTESTTOOL_H_
|
||||
#define _NAVMESHTESTTOOL_H_
|
||||
|
||||
|
||||
#ifndef _NAVMESH_TOOL_H_
|
||||
#include "navigation/navMeshTool.h"
|
||||
#endif
|
||||
|
||||
class NavMeshTestTool : public NavMeshTool
|
||||
{
|
||||
typedef NavMeshTool Parent;
|
||||
protected:
|
||||
String mSpawnClass;
|
||||
String mSpawnDatablock;
|
||||
SimObjectPtr<SceneObject> mPlayer;
|
||||
SimObjectPtr<SceneObject> mCurPlayer;
|
||||
Point3F mPathStart;
|
||||
Point3F mPathEnd;
|
||||
public:
|
||||
DECLARE_CONOBJECT(NavMeshTestTool);
|
||||
|
||||
void spawnPlayer(const Point3F& position);
|
||||
|
||||
void drawAgent(duDebugDrawTorque& dd, const F32* pos, F32 r, F32 h, F32 c, const U32 col);
|
||||
|
||||
NavMeshTestTool();
|
||||
|
||||
virtual ~NavMeshTestTool() {}
|
||||
|
||||
void onActivated(const Gui3DMouseEvent& evt) override;
|
||||
void onDeactivated() override;
|
||||
|
||||
void on3DMouseDown(const Gui3DMouseEvent& evt) override;
|
||||
void on3DMouseMove(const Gui3DMouseEvent& evt) override;
|
||||
void onRender3D() override;
|
||||
|
||||
bool updateGuiInfo() override;
|
||||
|
||||
S32 getPlayerId();
|
||||
|
||||
void setSpawnClass(String className) { mSpawnClass = className; }
|
||||
void setSpawnDatablock(String dbName) { mSpawnDatablock = dbName; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // !_NAVMESHTESTTOOL_H_
|
||||
|
|
@ -69,14 +69,11 @@ NavPath::NavPath() :
|
|||
mXray = false;
|
||||
mRenderSearch = false;
|
||||
|
||||
mQuery = NULL;
|
||||
mStatus = DT_FAILURE;
|
||||
}
|
||||
|
||||
NavPath::~NavPath()
|
||||
{
|
||||
dtFreeNavMeshQuery(mQuery);
|
||||
mQuery = NULL;
|
||||
}
|
||||
|
||||
void NavPath::checkAutoUpdate()
|
||||
|
|
@ -264,9 +261,6 @@ bool NavPath::onAdd()
|
|||
|
||||
if(isServerObject())
|
||||
{
|
||||
mQuery = dtAllocNavMeshQuery();
|
||||
if(!mQuery)
|
||||
return false;
|
||||
checkAutoUpdate();
|
||||
if(!plan())
|
||||
setProcessTick(true);
|
||||
|
|
@ -293,7 +287,8 @@ bool NavPath::init()
|
|||
return false;
|
||||
|
||||
// Initialise our query.
|
||||
if(dtStatusFailed(mQuery->init(mMesh->getNavMesh(), MaxPathLen)))
|
||||
mQuery = mMesh->getNavMeshQuery();
|
||||
if(!mQuery)
|
||||
return false;
|
||||
|
||||
mPoints.clear();
|
||||
|
|
@ -372,9 +367,6 @@ void NavPath::resize()
|
|||
bool NavPath::plan()
|
||||
{
|
||||
PROFILE_SCOPE(NavPath_plan);
|
||||
// Initialise filter.
|
||||
mFilter.setIncludeFlags(mLinkTypes.getFlags());
|
||||
|
||||
// Initialise query and visit locations.
|
||||
if(!init())
|
||||
return false;
|
||||
|
|
@ -641,6 +633,7 @@ void NavPath::renderSimple(ObjectRenderInst *ri, SceneRenderState *state, BaseMa
|
|||
{
|
||||
duDebugDrawTorque dd;
|
||||
duDebugDrawNavMeshNodes(&dd, *np->mQuery);
|
||||
dd.immediateRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public:
|
|||
|
||||
/// What sort of link types are we allowed to move on?
|
||||
LinkData mLinkTypes;
|
||||
|
||||
dtQueryFilter mFilter;
|
||||
/// Plan the path.
|
||||
bool plan();
|
||||
|
||||
|
|
@ -152,7 +152,6 @@ private:
|
|||
|
||||
dtNavMeshQuery *mQuery;
|
||||
dtStatus mStatus;
|
||||
dtQueryFilter mFilter;
|
||||
S32 mCurIndex;
|
||||
Vector<Point3F> mPoints;
|
||||
Vector<U16> mFlags;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ inline void rcCol(unsigned int col, U8 &r, U8 &g, U8 &b, U8 &a)
|
|||
}
|
||||
|
||||
enum PolyAreas {
|
||||
GroundArea = 1,
|
||||
NullArea = 0,
|
||||
GroundArea,
|
||||
WaterArea,
|
||||
OffMeshArea,
|
||||
NumAreas
|
||||
|
|
@ -99,6 +100,10 @@ struct LinkData {
|
|||
(climb ? ClimbFlag : 0) |
|
||||
(teleport ? TeleportFlag : 0);
|
||||
}
|
||||
U16 getExcludeFlags() const
|
||||
{
|
||||
return AllFlags & ~getFlags();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue