mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 07:53:51 +00:00
Separate Stepper
This commit is contained in:
parent
5d625c12dc
commit
ca6cce0c7e
7 changed files with 200 additions and 152 deletions
|
@ -71,7 +71,7 @@ add_openmw_dir (mwworld
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
add_openmw_dir (mwphysics
|
||||||
physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback
|
physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback
|
||||||
contacttestresultcallback deepestnotmecontacttestresultcallback
|
contacttestresultcallback deepestnotmecontacttestresultcallback stepper
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwclass
|
add_openmw_dir (mwclass
|
||||||
|
|
16
apps/openmw/mwphysics/constants.hpp
Normal file
16
apps/openmw/mwphysics/constants.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef OPENMW_MWPHYSICS_CONSTANTS_H
|
||||||
|
#define OPENMW_MWPHYSICS_CONSTANTS_H
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
static const float sStepSizeUp = 34.0f;
|
||||||
|
static const float sStepSizeDown = 62.0f;
|
||||||
|
static const float sMinStep = 10.f;
|
||||||
|
static const float sGroundOffset = 1.0f;
|
||||||
|
static const float sMaxSlope = 49.0f;
|
||||||
|
|
||||||
|
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
||||||
|
static const int sMaxIterations = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -49,17 +49,11 @@
|
||||||
#include "deepestnotmecontacttestresultcallback.hpp"
|
#include "deepestnotmecontacttestresultcallback.hpp"
|
||||||
#include "closestnotmerayresultcallback.hpp"
|
#include "closestnotmerayresultcallback.hpp"
|
||||||
#include "contacttestresultcallback.hpp"
|
#include "contacttestresultcallback.hpp"
|
||||||
|
#include "stepper.hpp"
|
||||||
|
#include "constants.hpp"
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
|
|
||||||
static const float sStepSizeDown = 62.0f;
|
|
||||||
static const float sMinStep = 10.f;
|
|
||||||
static const float sGroundOffset = 1.0f;
|
|
||||||
|
|
||||||
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
|
||||||
static const int sMaxIterations = 8;
|
|
||||||
|
|
||||||
static bool isActor(const btCollisionObject *obj)
|
static bool isActor(const btCollisionObject *obj)
|
||||||
{
|
{
|
||||||
assert(obj);
|
assert(obj);
|
||||||
|
@ -73,146 +67,6 @@ namespace MWPhysics
|
||||||
return (normal.z() > sMaxSlopeCos);
|
return (normal.z() > sMaxSlopeCos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canStepDown(const ActorTracer &stepper)
|
|
||||||
{
|
|
||||||
return stepper.mHitObject && isWalkableSlope(stepper.mPlaneNormal) && !isActor(stepper.mHitObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Stepper
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const btCollisionWorld *mColWorld;
|
|
||||||
const btCollisionObject *mColObj;
|
|
||||||
|
|
||||||
ActorTracer mTracer, mUpStepper, mDownStepper;
|
|
||||||
bool mHaveMoved;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj)
|
|
||||||
: mColWorld(colWorld)
|
|
||||||
, mColObj(colObj)
|
|
||||||
, mHaveMoved(true)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Slide up an incline or set of stairs. Should be called only after a
|
|
||||||
* collision detection otherwise unnecessary tracing will be performed.
|
|
||||||
*
|
|
||||||
* NOTE: with a small change this method can be used to step over an obstacle
|
|
||||||
* of height sStepSize.
|
|
||||||
*
|
|
||||||
* If successful return 'true' and update 'position' to the new possible
|
|
||||||
* location and adjust 'remainingTime'.
|
|
||||||
*
|
|
||||||
* If not successful return 'false'. May fail for these reasons:
|
|
||||||
* - can't move directly up from current position
|
|
||||||
* - having moved up by between epsilon() and sStepSize, can't move forward
|
|
||||||
* - having moved forward by between epsilon() and toMove,
|
|
||||||
* = moved down between 0 and just under sStepSize but slope was too steep, or
|
|
||||||
* = moved the full sStepSize down (FIXME: this could be a bug)
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Starting position. Obstacle or stairs with height upto sStepSize in front.
|
|
||||||
*
|
|
||||||
* +--+ +--+ |XX
|
|
||||||
* | | -------> toMove | | +--+XX
|
|
||||||
* | | | | |XXXXX
|
|
||||||
* | | +--+ | | +--+XXXXX
|
|
||||||
* | | |XX| | | |XXXXXXXX
|
|
||||||
* +--+ +--+ +--+ +--------
|
|
||||||
* ==============================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try moving up sStepSize using stepper.
|
|
||||||
* FIXME: does not work in case there is no front obstacle but there is one above
|
|
||||||
*
|
|
||||||
* +--+ +--+
|
|
||||||
* | | | |
|
|
||||||
* | | | | |XX
|
|
||||||
* | | | | +--+XX
|
|
||||||
* | | | | |XXXXX
|
|
||||||
* +--+ +--+ +--+ +--+XXXXX
|
|
||||||
* |XX| |XXXXXXXX
|
|
||||||
* +--+ +--------
|
|
||||||
* ==============================================
|
|
||||||
*/
|
|
||||||
if (mHaveMoved)
|
|
||||||
{
|
|
||||||
mHaveMoved = false;
|
|
||||||
mUpStepper.doTrace(mColObj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), mColWorld);
|
|
||||||
if(mUpStepper.mFraction < std::numeric_limits<float>::epsilon())
|
|
||||||
return false; // didn't even move the smallest representable amount
|
|
||||||
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try moving from the elevated position using tracer.
|
|
||||||
*
|
|
||||||
* +--+ +--+
|
|
||||||
* | | |YY| FIXME: collision with object YY
|
|
||||||
* | | +--+
|
|
||||||
* | |
|
|
||||||
* <------------------->| |
|
|
||||||
* +--+ +--+
|
|
||||||
* |XX| the moved amount is toMove*tracer.mFraction
|
|
||||||
* +--+
|
|
||||||
* ==============================================
|
|
||||||
*/
|
|
||||||
osg::Vec3f tracerPos = mUpStepper.mEndPos;
|
|
||||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld);
|
|
||||||
if(mTracer.mFraction < std::numeric_limits<float>::epsilon())
|
|
||||||
return false; // didn't even move the smallest representable amount
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try moving back down sStepSizeDown using stepper.
|
|
||||||
* NOTE: if there is an obstacle below (e.g. stairs), we'll be "stepping up".
|
|
||||||
* Below diagram is the case where we "stepped over" an obstacle in front.
|
|
||||||
*
|
|
||||||
* +--+
|
|
||||||
* |YY|
|
|
||||||
* +--+ +--+
|
|
||||||
* | |
|
|
||||||
* | |
|
|
||||||
* +--+ | |
|
|
||||||
* |XX| | |
|
|
||||||
* +--+ +--+
|
|
||||||
* ==============================================
|
|
||||||
*/
|
|
||||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
|
||||||
if (!canStepDown(mDownStepper))
|
|
||||||
{
|
|
||||||
// Try again with increased step length
|
|
||||||
if (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
osg::Vec3f direction = toMove;
|
|
||||||
direction.normalize();
|
|
||||||
mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld);
|
|
||||||
if (mTracer.mFraction < 0.001f)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
|
||||||
if (!canStepDown(mDownStepper))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mDownStepper.mFraction < 1.0f)
|
|
||||||
{
|
|
||||||
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
|
||||||
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
|
||||||
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
|
||||||
position = mDownStepper.mEndPos;
|
|
||||||
remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance
|
|
||||||
mHaveMoved = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MovementSolver
|
class MovementSolver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -50,9 +50,6 @@ namespace MWPhysics
|
||||||
class Object;
|
class Object;
|
||||||
class Actor;
|
class Actor;
|
||||||
|
|
||||||
static const float sMaxSlope = 49.0f;
|
|
||||||
static const float sStepSizeUp = 34.0f;
|
|
||||||
|
|
||||||
class PhysicsSystem
|
class PhysicsSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
148
apps/openmw/mwphysics/stepper.cpp
Normal file
148
apps/openmw/mwphysics/stepper.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include "stepper.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||||
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
|
|
||||||
|
#include "collisiontype.hpp"
|
||||||
|
#include "constants.hpp"
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
static bool canStepDown(const ActorTracer &stepper)
|
||||||
|
{
|
||||||
|
if (!stepper.mHitObject)
|
||||||
|
return false;
|
||||||
|
static const float sMaxSlopeCos = std::cos(osg::DegreesToRadians(sMaxSlope));
|
||||||
|
if (stepper.mPlaneNormal.z() <= sMaxSlopeCos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stepper::Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj)
|
||||||
|
: mColWorld(colWorld)
|
||||||
|
, mColObj(colObj)
|
||||||
|
, mHaveMoved(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Stepper::step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Slide up an incline or set of stairs. Should be called only after a
|
||||||
|
* collision detection otherwise unnecessary tracing will be performed.
|
||||||
|
*
|
||||||
|
* NOTE: with a small change this method can be used to step over an obstacle
|
||||||
|
* of height sStepSize.
|
||||||
|
*
|
||||||
|
* If successful return 'true' and update 'position' to the new possible
|
||||||
|
* location and adjust 'remainingTime'.
|
||||||
|
*
|
||||||
|
* If not successful return 'false'. May fail for these reasons:
|
||||||
|
* - can't move directly up from current position
|
||||||
|
* - having moved up by between epsilon() and sStepSize, can't move forward
|
||||||
|
* - having moved forward by between epsilon() and toMove,
|
||||||
|
* = moved down between 0 and just under sStepSize but slope was too steep, or
|
||||||
|
* = moved the full sStepSize down (FIXME: this could be a bug)
|
||||||
|
*
|
||||||
|
* Starting position. Obstacle or stairs with height upto sStepSize in front.
|
||||||
|
*
|
||||||
|
* +--+ +--+ |XX
|
||||||
|
* | | -------> toMove | | +--+XX
|
||||||
|
* | | | | |XXXXX
|
||||||
|
* | | +--+ | | +--+XXXXX
|
||||||
|
* | | |XX| | | |XXXXXXXX
|
||||||
|
* +--+ +--+ +--+ +--------
|
||||||
|
* ==============================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try moving up sStepSize using stepper.
|
||||||
|
* FIXME: does not work in case there is no front obstacle but there is one above
|
||||||
|
*
|
||||||
|
* +--+ +--+
|
||||||
|
* | | | |
|
||||||
|
* | | | | |XX
|
||||||
|
* | | | | +--+XX
|
||||||
|
* | | | | |XXXXX
|
||||||
|
* +--+ +--+ +--+ +--+XXXXX
|
||||||
|
* |XX| |XXXXXXXX
|
||||||
|
* +--+ +--------
|
||||||
|
* ==============================================
|
||||||
|
*/
|
||||||
|
if (mHaveMoved)
|
||||||
|
{
|
||||||
|
mHaveMoved = false;
|
||||||
|
|
||||||
|
mUpStepper.doTrace(mColObj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), mColWorld);
|
||||||
|
if (mUpStepper.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
|
return false; // didn't even move the smallest representable amount
|
||||||
|
// (TODO: shouldn't this be larger? Why bother with such a small amount?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try moving from the elevated position using tracer.
|
||||||
|
*
|
||||||
|
* +--+ +--+
|
||||||
|
* | | |YY| FIXME: collision with object YY
|
||||||
|
* | | +--+
|
||||||
|
* | |
|
||||||
|
* <------------------->| |
|
||||||
|
* +--+ +--+
|
||||||
|
* |XX| the moved amount is toMove*tracer.mFraction
|
||||||
|
* +--+
|
||||||
|
* ==============================================
|
||||||
|
*/
|
||||||
|
osg::Vec3f tracerPos = mUpStepper.mEndPos;
|
||||||
|
mTracer.doTrace(mColObj, tracerPos, tracerPos + toMove, mColWorld);
|
||||||
|
if (mTracer.mFraction < std::numeric_limits<float>::epsilon())
|
||||||
|
return false; // didn't even move the smallest representable amount
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try moving back down sStepSizeDown using stepper.
|
||||||
|
* NOTE: if there is an obstacle below (e.g. stairs), we'll be "stepping up".
|
||||||
|
* Below diagram is the case where we "stepped over" an obstacle in front.
|
||||||
|
*
|
||||||
|
* +--+
|
||||||
|
* |YY|
|
||||||
|
* +--+ +--+
|
||||||
|
* | |
|
||||||
|
* | |
|
||||||
|
* +--+ | |
|
||||||
|
* |XX| | |
|
||||||
|
* +--+ +--+
|
||||||
|
* ==============================================
|
||||||
|
*/
|
||||||
|
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||||
|
if (!canStepDown(mDownStepper))
|
||||||
|
{
|
||||||
|
// Try again with increased step length
|
||||||
|
if (mTracer.mFraction < 1.0f || toMove.length2() > sMinStep*sMinStep)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
osg::Vec3f direction = toMove;
|
||||||
|
direction.normalize();
|
||||||
|
mTracer.doTrace(mColObj, tracerPos, tracerPos + direction*sMinStep, mColWorld);
|
||||||
|
if (mTracer.mFraction < 0.001f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mDownStepper.doTrace(mColObj, mTracer.mEndPos, mTracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), mColWorld);
|
||||||
|
if (!canStepDown(mDownStepper))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDownStepper.mFraction < 1.0f)
|
||||||
|
{
|
||||||
|
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
||||||
|
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
|
||||||
|
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
|
||||||
|
position = mDownStepper.mEndPos;
|
||||||
|
remainingTime *= (1.0f-mTracer.mFraction); // remaining time is proportional to remaining distance
|
||||||
|
mHaveMoved = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
32
apps/openmw/mwphysics/stepper.hpp
Normal file
32
apps/openmw/mwphysics/stepper.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef OPENMW_MWPHYSICS_STEPPER_H
|
||||||
|
#define OPENMW_MWPHYSICS_STEPPER_H
|
||||||
|
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
class btCollisionObject;
|
||||||
|
class btCollisionWorld;
|
||||||
|
|
||||||
|
namespace osg
|
||||||
|
{
|
||||||
|
class Vec3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWPhysics
|
||||||
|
{
|
||||||
|
class Stepper
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const btCollisionWorld *mColWorld;
|
||||||
|
const btCollisionObject *mColObj;
|
||||||
|
|
||||||
|
ActorTracer mTracer, mUpStepper, mDownStepper;
|
||||||
|
bool mHaveMoved;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Stepper(const btCollisionWorld *colWorld, const btCollisionObject *colObj);
|
||||||
|
|
||||||
|
bool step(osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -56,6 +56,7 @@
|
||||||
#include "../mwphysics/actor.hpp"
|
#include "../mwphysics/actor.hpp"
|
||||||
#include "../mwphysics/collisiontype.hpp"
|
#include "../mwphysics/collisiontype.hpp"
|
||||||
#include "../mwphysics/object.hpp"
|
#include "../mwphysics/object.hpp"
|
||||||
|
#include "../mwphysics/constants.hpp"
|
||||||
|
|
||||||
#include "player.hpp"
|
#include "player.hpp"
|
||||||
#include "manualref.hpp"
|
#include "manualref.hpp"
|
||||||
|
|
Loading…
Reference in a new issue