AiCombat distance check takes into account collision box (Fixes #1699)

openmw-38
scrawl 9 years ago
parent 0bdfd1b0d7
commit 3453353091

@ -543,6 +543,9 @@ namespace MWBase
/// Return a vector aiming the actor's weapon towards a target.
/// @note The length of the vector is the distance between actor and target.
virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0;
/// Return the distance between actor's weapon and target's collision box.
virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target) = 0;
};
}

@ -347,7 +347,7 @@ namespace MWMechanics
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
float distToTarget = (vTargetPos - vActorPos).length();
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
osg::Vec3f& lastActorPos = storage.mLastActorPos;
bool& followTarget = storage.mFollowTarget;

@ -218,6 +218,7 @@ namespace MWPhysics
resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap;
collisionWorld->rayTest(from, to, resultCallback1);
if (resultCallback1.hasHit() &&
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length() > 30
|| getSlope(tracer.mPlaneNormal) > sMaxSlope))
@ -748,6 +749,36 @@ namespace MWPhysics
return std::make_pair(MWWorld::Ptr(), osg::Vec3f());
}
float PhysicsSystem::getHitDistance(const osg::Vec3f &point, const MWWorld::Ptr &target) const
{
btCollisionObject* targetCollisionObj = NULL;
const Actor* actor = getActor(target);
if (actor)
targetCollisionObj = actor->getCollisionObject();
if (!targetCollisionObj)
return 0.f;
btTransform rayFrom;
rayFrom.setIdentity();
rayFrom.setOrigin(toBullet(point));
// target the collision object's world origin, this should be the center of the collision object
btTransform rayTo;
rayTo.setIdentity();
rayTo.setOrigin(targetCollisionObj->getWorldTransform().getOrigin());
btCollisionWorld::ClosestRayResultCallback cb(rayFrom.getOrigin(), rayTo.getOrigin());
btCollisionWorld::rayTestSingle(rayFrom, rayTo, targetCollisionObj, targetCollisionObj->getCollisionShape(), targetCollisionObj->getWorldTransform(), cb);
if (!cb.hasHit())
{
// didn't hit the target. this could happen if point is already inside the collision box
return 0.f;
}
else
return (point - toOsg(cb.m_hitPointWorld)).length();
}
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
{
public:

@ -89,6 +89,13 @@ namespace MWPhysics
const osg::Quat &orientation,
float queryDistance);
/// Get distance from \a point to the collision shape of \a target. Uses a raycast to find where the
/// target vector hits the collision shape and then calculates distance from the intersection point.
/// This can be used to find out how much nearer we need to move to the target for a "getHitContact" to be successful.
/// \note Only Actor targets are supported at the moment.
float getHitDistance(const osg::Vec3f& point, const MWWorld::Ptr& target) const;
struct RayResult
{
bool mHit;

@ -3238,4 +3238,11 @@ namespace MWWorld
osg::Vec3f targetPos = mPhysics->getPosition(target);
return (targetPos - weaponPos);
}
float World::getHitDistance(const Ptr &actor, const Ptr &target)
{
osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering);
return mPhysics->getHitDistance(weaponPos, target);
}
}

@ -633,6 +633,9 @@ namespace MWWorld
/// Return a vector aiming the actor's weapon towards a target.
/// @note The length of the vector is the distance between actor and target.
virtual osg::Vec3f aimToTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
/// Return the distance between actor's weapon and target's collision box.
virtual float getHitDistance(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
};
}

Loading…
Cancel
Save