mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-21 10:23:52 +00:00
Merge pull request #2276 from elsid/aiwander
Improve AiWander pathfinding for locations without pathgrid
This commit is contained in:
commit
92bed66e5f
5 changed files with 75 additions and 25 deletions
|
@ -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,13 +322,22 @@ 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())
|
||||||
{
|
{
|
||||||
|
@ -323,8 +345,8 @@ namespace MWMechanics
|
||||||
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);
|
||||||
|
mDistSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) + 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
||||||
|
}
|
||||||
|
|
||||||
float distSameSpot = mDistSameSpot * duration;
|
const float distSameSpot = mDistSameSpot * duration;
|
||||||
|
const float squaredMovedDistance = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2();
|
||||||
bool samePosition = (osg::Vec2f(pos.pos[0], pos.pos[1]) - osg::Vec2f(mPrevX, mPrevY)).length2() < distSameSpot * distSameSpot;
|
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…
Reference in a new issue