mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-23 06:41:08 +00:00
prevent running in circles around path points
addresses http://bugs.openmw.org/issues/2229
This commit is contained in:
parent
03a35c38df
commit
72786fef9d
@ -19,12 +19,15 @@
|
|||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "coordinateconverter.hpp"
|
#include "coordinateconverter.hpp"
|
||||||
|
|
||||||
|
#include <osg/Quat>
|
||||||
|
|
||||||
MWMechanics::AiPackage::~AiPackage() {}
|
MWMechanics::AiPackage::~AiPackage() {}
|
||||||
|
|
||||||
MWMechanics::AiPackage::AiPackage() :
|
MWMechanics::AiPackage::AiPackage() :
|
||||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||||
mIsShortcutting(false),
|
mIsShortcutting(false),
|
||||||
mShortcutProhibited(false), mShortcutFailPos()
|
mShortcutProhibited(false), mShortcutFailPos(),
|
||||||
|
mRotateOnTheRunChecks(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +107,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
|||||||
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
|
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
|
||||||
{
|
{
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
||||||
|
mRotateOnTheRunChecks = 3;
|
||||||
|
|
||||||
// give priority to go directly on target if there is minimal opportunity
|
// give priority to go directly on target if there is minimal opportunity
|
||||||
if (destInLOS && mPathFinder.getPath().size() > 1)
|
if (destInLOS && mPathFinder.getPath().size() > 1)
|
||||||
@ -143,7 +147,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // run to target
|
if (mRotateOnTheRunChecks == 0
|
||||||
|
|| isReachableRotatingOnTheRun(actor, *mPathFinder.getPath().begin())) // to prevent circling around a path point
|
||||||
|
{
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // move to the target
|
||||||
|
if (mRotateOnTheRunChecks > 0) mRotateOnTheRunChecks--;
|
||||||
|
}
|
||||||
|
|
||||||
// handle obstacles on the way
|
// handle obstacles on the way
|
||||||
evadeObstacles(actor, duration, pos);
|
evadeObstacles(actor, duration, pos);
|
||||||
}
|
}
|
||||||
@ -292,3 +302,32 @@ bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& actor, const ESM::Pathgrid::Point& dest)
|
||||||
|
{
|
||||||
|
// get actor's shortest radius for moving in circle
|
||||||
|
float speed = actor.getClass().getSpeed(actor);
|
||||||
|
speed += speed * 0.1f; // 10% real speed inaccuracy
|
||||||
|
float radius = speed / MAX_VEL_ANGULAR_RADIANS;
|
||||||
|
|
||||||
|
// get radius direction to the center
|
||||||
|
const float* rot = actor.getRefData().getPosition().rot;
|
||||||
|
osg::Quat quatRot(rot[0], -osg::X_AXIS, rot[1], -osg::Y_AXIS, rot[2], -osg::Z_AXIS);
|
||||||
|
osg::Vec3f dir = quatRot * osg::Y_AXIS; // actor's orientation direction is a tangent to circle
|
||||||
|
osg::Vec3f radiusDir = dir ^ osg::Z_AXIS; // radius is perpendicular to a tangent
|
||||||
|
radiusDir.normalize();
|
||||||
|
radiusDir *= radius;
|
||||||
|
|
||||||
|
// pick up the nearest center candidate
|
||||||
|
osg::Vec3f dest_ = PathFinder::MakeOsgVec3(dest);
|
||||||
|
osg::Vec3f pos = actor.getRefData().getPosition().asVec3();
|
||||||
|
osg::Vec3f center1 = pos - radiusDir;
|
||||||
|
osg::Vec3f center2 = pos + radiusDir;
|
||||||
|
osg::Vec3f center = (center1 - dest_).length2() < (center2 - dest_).length2() ? center1 : center2;
|
||||||
|
|
||||||
|
float distToDest = (center - dest_).length();
|
||||||
|
|
||||||
|
// if pathpoint is reachable for the actor rotating on the run:
|
||||||
|
// no points of actor's circle should be farther from the center than destination point
|
||||||
|
return (radius <= distToDest);
|
||||||
|
}
|
||||||
|
@ -97,6 +97,9 @@ namespace MWMechanics
|
|||||||
|
|
||||||
bool isTargetMagicallyHidden(const MWWorld::Ptr& target);
|
bool isTargetMagicallyHidden(const MWWorld::Ptr& target);
|
||||||
|
|
||||||
|
/// Return if actor's rotation speed is sufficient to rotate to the destination pathpoint on the run. Otherwise actor should rotate while standing.
|
||||||
|
static bool isReachableRotatingOnTheRun(const MWWorld::Ptr& actor, const ESM::Pathgrid::Point& dest);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Handles path building and shortcutting with obstacles avoiding
|
/// Handles path building and shortcutting with obstacles avoiding
|
||||||
/** \return If the actor has arrived at his destination **/
|
/** \return If the actor has arrived at his destination **/
|
||||||
@ -123,6 +126,8 @@ namespace MWMechanics
|
|||||||
|
|
||||||
osg::Vec3f mLastActorPos;
|
osg::Vec3f mLastActorPos;
|
||||||
|
|
||||||
|
short mRotateOnTheRunChecks; // attempts to check rotation to the pathpoint on the run possibility
|
||||||
|
|
||||||
bool mIsShortcutting; // if shortcutting at the moment
|
bool mIsShortcutting; // if shortcutting at the moment
|
||||||
bool mShortcutProhibited; // shortcutting may be prohibited after unsuccessful attempt
|
bool mShortcutProhibited; // shortcutting may be prohibited after unsuccessful attempt
|
||||||
ESM::Pathgrid::Point mShortcutFailPos; // position of last shortcut fail
|
ESM::Pathgrid::Point mShortcutFailPos; // position of last shortcut fail
|
||||||
|
Loading…
x
Reference in New Issue
Block a user