mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:53:50 +00:00
Movement solver: add usage of 'on slope' flag to improve handling of steep slopes
Previously we were handling 'on slope' synonymously with 'in air' which caused some odd effects. Practical changes: - Sliding down a slope no longer applies fall damage. - Fixed a climbing exploit that would allow climbing steep slopes with repeated use of the Jump function.
This commit is contained in:
parent
cce42b6e9d
commit
541fbb4792
3 changed files with 29 additions and 10 deletions
|
@ -18,7 +18,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world)
|
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world)
|
||||||
: mCanWaterWalk(false), mWalkingOnWater(false)
|
: mCanWaterWalk(false), mWalkingOnWater(false)
|
||||||
, mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false)
|
, mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false), mOnSlope(false)
|
||||||
, mInternalCollisionMode(true)
|
, mInternalCollisionMode(true)
|
||||||
, mExternalCollisionMode(true)
|
, mExternalCollisionMode(true)
|
||||||
, mCollisionWorld(world)
|
, mCollisionWorld(world)
|
||||||
|
@ -180,6 +180,11 @@ void Actor::setOnGround(bool grounded)
|
||||||
mOnGround = grounded;
|
mOnGround = grounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actor::setOnSlope(bool slope)
|
||||||
|
{
|
||||||
|
mOnSlope = slope;
|
||||||
|
}
|
||||||
|
|
||||||
bool Actor::isWalkingOnWater() const
|
bool Actor::isWalkingOnWater() const
|
||||||
{
|
{
|
||||||
return mWalkingOnWater;
|
return mWalkingOnWater;
|
||||||
|
|
|
@ -124,6 +124,13 @@ namespace MWPhysics
|
||||||
return mInternalCollisionMode && mOnGround;
|
return mInternalCollisionMode && mOnGround;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOnSlope(bool slope);
|
||||||
|
|
||||||
|
bool getOnSlope() const
|
||||||
|
{
|
||||||
|
return mInternalCollisionMode && mOnSlope;
|
||||||
|
}
|
||||||
|
|
||||||
btCollisionObject* getCollisionObject() const
|
btCollisionObject* getCollisionObject() const
|
||||||
{
|
{
|
||||||
return mCollisionObject.get();
|
return mCollisionObject.get();
|
||||||
|
@ -160,6 +167,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
osg::Vec3f mForce;
|
osg::Vec3f mForce;
|
||||||
bool mOnGround;
|
bool mOnGround;
|
||||||
|
bool mOnSlope;
|
||||||
bool mInternalCollisionMode;
|
bool mInternalCollisionMode;
|
||||||
bool mExternalCollisionMode;
|
bool mExternalCollisionMode;
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,8 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
actor->setOnGround(true);
|
||||||
|
|
||||||
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
||||||
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
||||||
// intersects with other geometry if the actor's base is taken into account
|
// intersects with other geometry if the actor's base is taken into account
|
||||||
|
@ -266,11 +268,13 @@ namespace MWPhysics
|
||||||
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|
||||||
|| !isWalkableSlope(tracer.mPlaneNormal)))
|
|| !isWalkableSlope(tracer.mPlaneNormal)))
|
||||||
{
|
{
|
||||||
actor->setOnGround(isWalkableSlope(resultCallback1.m_hitNormalWorld));
|
actor->setOnSlope(isWalkableSlope(resultCallback1.m_hitNormalWorld));
|
||||||
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
actor->setOnGround(isWalkableSlope(tracer.mPlaneNormal));
|
{
|
||||||
|
actor->setOnSlope(isWalkableSlope(tracer.mPlaneNormal));
|
||||||
|
}
|
||||||
|
|
||||||
return tracer.mEndPos;
|
return tracer.mEndPos;
|
||||||
}
|
}
|
||||||
|
@ -322,12 +326,10 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
||||||
|
|
||||||
if (velocity.z() > 0.f && physicActor->getOnGround())
|
if (velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
|
||||||
inertia = velocity;
|
inertia = velocity;
|
||||||
else if(!physicActor->getOnGround())
|
else if(!physicActor->getOnGround() || physicActor->getOnSlope())
|
||||||
{
|
|
||||||
velocity = velocity + physicActor->getInertialForce();
|
velocity = velocity + physicActor->getInertialForce();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dead actors underwater will float to the surface, if the CharacterController tells us to do so
|
// dead actors underwater will float to the surface, if the CharacterController tells us to do so
|
||||||
|
@ -440,13 +442,14 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOnGround = false;
|
bool isOnGround = false;
|
||||||
|
bool isOnSlope = false;
|
||||||
if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel))
|
if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel))
|
||||||
{
|
{
|
||||||
osg::Vec3f from = newPosition;
|
osg::Vec3f from = newPosition;
|
||||||
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
||||||
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
||||||
tracer.doTrace(colobj, from, to, collisionWorld);
|
tracer.doTrace(colobj, from, to, collisionWorld);
|
||||||
if(tracer.mFraction < 1.0f && isWalkableSlope(tracer.mPlaneNormal)
|
if(tracer.mFraction < 1.0f
|
||||||
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
||||||
{
|
{
|
||||||
const btCollisionObject* standingOn = tracer.mHitObject;
|
const btCollisionObject* standingOn = tracer.mHitObject;
|
||||||
|
@ -460,6 +463,8 @@ namespace MWPhysics
|
||||||
newPosition.z() = tracer.mEndPos.z() + 1.0f;
|
newPosition.z() = tracer.mEndPos.z() + 1.0f;
|
||||||
|
|
||||||
isOnGround = true;
|
isOnGround = true;
|
||||||
|
|
||||||
|
isOnSlope = !isWalkableSlope(tracer.mPlaneNormal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -483,7 +488,7 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isOnGround || newPosition.z() < swimlevel || isFlying)
|
if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || isFlying)
|
||||||
physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f));
|
physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -497,6 +502,7 @@ namespace MWPhysics
|
||||||
physicActor->setInertialForce(inertia);
|
physicActor->setInertialForce(inertia);
|
||||||
}
|
}
|
||||||
physicActor->setOnGround(isOnGround);
|
physicActor->setOnGround(isOnGround);
|
||||||
|
physicActor->setOnSlope(isOnSlope);
|
||||||
|
|
||||||
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
||||||
return newPosition;
|
return newPosition;
|
||||||
|
|
Loading…
Reference in a new issue