forked from mirror/openmw-tes3mp
prevent running in circles around path points
addresses http://bugs.openmw.org/issues/2229
This commit is contained in:
parent
03a35c38df
commit
72786fef9d
2 changed files with 46 additions and 2 deletions
|
@ -19,12 +19,15 @@
|
|||
#include "actorutil.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
|
||||
#include <osg/Quat>
|
||||
|
||||
MWMechanics::AiPackage::~AiPackage() {}
|
||||
|
||||
MWMechanics::AiPackage::AiPackage() :
|
||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||
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
|
||||
{
|
||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
||||
mRotateOnTheRunChecks = 3;
|
||||
|
||||
// give priority to go directly on target if there is minimal opportunity
|
||||
if (destInLOS && mPathFinder.getPath().size() > 1)
|
||||
|
@ -143,7 +147,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
|||
}
|
||||
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
|
||||
evadeObstacles(actor, duration, pos);
|
||||
}
|
||||
|
@ -292,3 +302,32 @@ bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos)
|
|||
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);
|
||||
|
||||
/// 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:
|
||||
/// Handles path building and shortcutting with obstacles avoiding
|
||||
/** \return If the actor has arrived at his destination **/
|
||||
|
@ -123,6 +126,8 @@ namespace MWMechanics
|
|||
|
||||
osg::Vec3f mLastActorPos;
|
||||
|
||||
short mRotateOnTheRunChecks; // attempts to check rotation to the pathpoint on the run possibility
|
||||
|
||||
bool mIsShortcutting; // if shortcutting at the moment
|
||||
bool mShortcutProhibited; // shortcutting may be prohibited after unsuccessful attempt
|
||||
ESM::Pathgrid::Point mShortcutFailPos; // position of last shortcut fail
|
||||
|
|
Loading…
Reference in a new issue