From d1d6ba3ed0728e87289bd479d105a0b240e6a6cd Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 7 Oct 2019 20:19:12 +0200 Subject: [PATCH] Fix rebuild path for walking actors Ignore z coordinate for not swimming nor flying actors to calculate distance from actor destination to last path point. If walking actor destination point is floating above the ground then a point on navmesh may be too far away when z coordinate is included. In this case path will be rebuild on each AI_REACTION_TIME. --- apps/openmw/mwmechanics/aipackage.cpp | 29 +++++++++++++++++++++++---- apps/openmw/mwmechanics/aipackage.hpp | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 646b37669..8336ca971 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -22,6 +22,27 @@ #include +namespace MWMechanics +{ + static float distance(const osg::Vec2f& lhs, const osg::Vec2f& rhs) + { + return (lhs - rhs).length2(); + } + + static float distanceIgnoreZ(const osg::Vec3f& lhs, const osg::Vec3f& rhs) + { + return distance(osg::Vec2f(lhs.x(), lhs.y()), osg::Vec2f(rhs.x(), rhs.y())); + } + + static float distance(const osg::Vec3f& lhs, const osg::Vec3f& rhs, const MWWorld::Ptr& actor) + { + const auto world = MWBase::Environment::get().getWorld(); + if (world->isSwimming(actor) || world->isFlying(actor)) + return distance(lhs, rhs); + return distanceIgnoreZ(lhs, rhs); + } +} + MWMechanics::AiPackage::~AiPackage() {} MWMechanics::AiPackage::AiPackage() : @@ -133,7 +154,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& if (!mIsShortcutting) { - if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path + if (wasShortcutting || doesPathNeedRecalc(dest, actor)) // if need to rebuild path { const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), @@ -328,11 +349,11 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin return false; } -bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell) +bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::Ptr& actor) const { return mPathFinder.getPath().empty() - || (distance(mPathFinder.getPath().back(), newDest) > 10) - || mPathFinder.getPathCell() != currentCell; + || distance(mPathFinder.getPath().back(), newDest, actor) > 10 + || mPathFinder.getPathCell() != actor.getCell(); } bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 6bb12342a..20b4c390e 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -120,7 +120,7 @@ namespace MWMechanics /// Check if the way to the destination is clear, taking into account actor speed bool checkWayIsClearForActor(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::Ptr& actor); - bool doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell); + bool doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::Ptr& actor) const; void evadeObstacles(const MWWorld::Ptr& actor);