Merge pull request #2276 from elsid/aiwander

Improve AiWander pathfinding for locations without pathgrid
pull/541/head
Bret Curtis 6 years ago committed by GitHub
commit 92bed66e5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,6 +13,8 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwphysics/collisiontype.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "steering.hpp" #include "steering.hpp"
@ -45,6 +47,16 @@ namespace MWMechanics
std::string("idle9"), std::string("idle9"),
}; };
namespace
{
inline int getCountBeforeReset(const MWWorld::ConstPtr& actor)
{
if (actor.getClass().isPureWaterCreature(actor) || actor.getClass().isPureFlyingCreature(actor))
return 1;
return COUNT_BEFORE_RESET;
}
}
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle),
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)), mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
@ -298,7 +310,8 @@ namespace MWMechanics
const auto currentPosition = actor.getRefData().getPosition().asVec3(); const auto currentPosition = actor.getRefData().getPosition().asVec3();
std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here std::size_t attempts = 10; // If a unit can't wander out of water, don't want to hang here
bool isWaterCreature = actor.getClass().isPureWaterCreature(actor); const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
do { do {
// Determine a random location within radius of original position // Determine a random location within radius of original position
const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance; const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance;
@ -309,22 +322,31 @@ namespace MWMechanics
mDestination = osg::Vec3f(destinationX, destinationY, destinationZ); mDestination = osg::Vec3f(destinationX, destinationY, destinationZ);
// Check if land creature will walk onto water or if water creature will swim onto land // Check if land creature will walk onto water or if water creature will swim onto land
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) || if (!isWaterCreature && destinationIsAtWater(actor, mDestination))
(isWaterCreature && !destinationThroughGround(currentPosition, mDestination))) continue;
if ((isWaterCreature || isFlyingCreature) && destinationThroughGround(currentPosition, mDestination))
continue;
if (isWaterCreature || isFlyingCreature)
{
mPathFinder.buildStraightPath(mDestination);
}
else
{ {
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor); const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
mPathFinder.buildPath(actor, currentPosition, mDestination, actor.getCell(), mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents,
getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor)); getNavigatorFlags(actor));
mPathFinder.addPointToPath(mDestination); }
if (mPathFinder.isPathConstructed()) if (mPathFinder.isPathConstructed())
{ {
storage.setState(AiWanderStorage::Wander_Walking, true); storage.setState(AiWanderStorage::Wander_Walking, true);
mHasDestination = true; mHasDestination = true;
mUsePathgrid = false; mUsePathgrid = false;
}
return;
} }
break;
} while (--attempts); } while (--attempts);
} }
@ -342,8 +364,10 @@ namespace MWMechanics
* Returns true if the start to end point travels through a collision point (land). * Returns true if the start to end point travels through a collision point (land).
*/ */
bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) { bool AiWander::destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination) {
const int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Door;
return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(), return MWBase::Environment::get().getWorld()->castRay(startPoint.x(), startPoint.y(), startPoint.z(),
destination.x(), destination.y(), destination.z()); destination.x(), destination.y(), destination.z(),
mask);
} }
void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) {
@ -479,7 +503,7 @@ namespace MWMechanics
} }
// if stuck for sufficiently long, act like current location was the destination // if stuck for sufficiently long, act like current location was the destination
if (storage.mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset if (storage.mStuckCount >= getCountBeforeReset(actor)) // something has gone wrong, reset
{ {
mObstacleCheck.clear(); mObstacleCheck.clear();
stopWalking(actor, storage); stopWalking(actor, storage);

@ -2,6 +2,8 @@
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
@ -121,17 +123,19 @@ namespace MWMechanics
* u = how long to move sideways * u = how long to move sideways
* *
*/ */
void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance) void ObstacleCheck::update(const MWWorld::Ptr& actor, float duration)
{ {
const MWWorld::Class& cls = actor.getClass(); const ESM::Position pos = actor.getRefData().getPosition();
ESM::Position pos = actor.getRefData().getPosition();
if(mDistSameSpot == -1) if (mDistSameSpot == -1)
mDistSameSpot = DIST_SAME_SPOT * cls.getSpeed(actor) * scaleMinimumDistance; {
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
float distSameSpot = mDistSameSpot * duration; mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y());
}
bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot; const float distSameSpot = mDistSameSpot * duration;
const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2();
const bool samePosition = squaredMovedDistance < distSameSpot * distSameSpot;
// update position // update position
mPrevX = pos.pos[0]; mPrevX = pos.pos[0];

@ -30,7 +30,7 @@ namespace MWMechanics
bool isEvading() const; bool isEvading() const;
// Updates internal state, call each frame for moving actor // Updates internal state, call each frame for moving actor
void update(const MWWorld::Ptr& actor, float duration, float scaleMinimumDistance = 1.0f); void update(const MWWorld::Ptr& actor, float duration);
// change direction to try to fix "stuck" actor // change direction to try to fix "stuck" actor
void takeEvasiveAction(MWMechanics::Movement& actorMovement) const; void takeEvasiveAction(MWMechanics::Movement& actorMovement) const;

@ -269,6 +269,13 @@ namespace MWMechanics
mPath.pop_front(); mPath.pop_front();
} }
void PathFinder::buildStraightPath(const osg::Vec3f& endPoint)
{
mPath.clear();
mPath.push_back(endPoint);
mConstructed = true;
}
void PathFinder::buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, void PathFinder::buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph) const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph)
{ {
@ -280,6 +287,16 @@ namespace MWMechanics
mConstructed = true; mConstructed = true;
} }
void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags)
{
mPath.clear();
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath));
mConstructed = true;
}
void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
const DetourNavigator::Flags flags) const DetourNavigator::Flags flags)

@ -72,9 +72,14 @@ namespace MWMechanics
mCell = nullptr; mCell = nullptr;
} }
void buildStraightPath(const osg::Vec3f& endPoint);
void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, void buildPathByPathgrid(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph); const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags);
void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents, const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
const DetourNavigator::Flags flags); const DetourNavigator::Flags flags);

Loading…
Cancel
Save