mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-03 11:45:34 +00:00
Explicitely store all the potential states an Actor can have into the
ActActorFrameData structure. It makes it easier to reason about the simulation (and hopefully simplify it). Remove atomics from Actor class as a side effect. Rename mFloatToSurface to mInert to make is explicit what it represent, not what it is used for Store the Actor rotation (1 Vec2) instead of the whole ESM::Position (2 Vec3)
This commit is contained in:
parent
9472728fa4
commit
1bfaf353be
6 changed files with 67 additions and 41 deletions
|
@ -82,7 +82,7 @@ Actor::~Actor()
|
|||
|
||||
void Actor::enableCollisionMode(bool collision)
|
||||
{
|
||||
mInternalCollisionMode.store(collision, std::memory_order_release);
|
||||
mInternalCollisionMode = collision;
|
||||
}
|
||||
|
||||
void Actor::enableCollisionBody(bool collision)
|
||||
|
@ -250,22 +250,22 @@ void Actor::setInertialForce(const osg::Vec3f &force)
|
|||
|
||||
void Actor::setOnGround(bool grounded)
|
||||
{
|
||||
mOnGround.store(grounded, std::memory_order_release);
|
||||
mOnGround = grounded;
|
||||
}
|
||||
|
||||
void Actor::setOnSlope(bool slope)
|
||||
{
|
||||
mOnSlope.store(slope, std::memory_order_release);
|
||||
mOnSlope = slope;
|
||||
}
|
||||
|
||||
bool Actor::isWalkingOnWater() const
|
||||
{
|
||||
return mWalkingOnWater.load(std::memory_order_acquire);
|
||||
return mWalkingOnWater;
|
||||
}
|
||||
|
||||
void Actor::setWalkingOnWater(bool walkingOnWater)
|
||||
{
|
||||
mWalkingOnWater.store(walkingOnWater, std::memory_order_release);
|
||||
mWalkingOnWater = walkingOnWater;
|
||||
}
|
||||
|
||||
void Actor::setCanWaterWalk(bool waterWalk)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef OPENMW_MWPHYSICS_ACTOR_H
|
||||
#define OPENMW_MWPHYSICS_ACTOR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
|
@ -37,7 +36,7 @@ namespace MWPhysics
|
|||
|
||||
bool getCollisionMode() const
|
||||
{
|
||||
return mInternalCollisionMode.load(std::memory_order_acquire);
|
||||
return mInternalCollisionMode;
|
||||
}
|
||||
|
||||
btConvexShape* getConvexShape() const { return mConvexShape; }
|
||||
|
@ -123,14 +122,14 @@ namespace MWPhysics
|
|||
|
||||
bool getOnGround() const
|
||||
{
|
||||
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnGround.load(std::memory_order_acquire);
|
||||
return mInternalCollisionMode && mOnGround;
|
||||
}
|
||||
|
||||
void setOnSlope(bool slope);
|
||||
|
||||
bool getOnSlope() const
|
||||
{
|
||||
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnSlope.load(std::memory_order_acquire);
|
||||
return mInternalCollisionMode && mOnSlope;
|
||||
}
|
||||
|
||||
btCollisionObject* getCollisionObject() const
|
||||
|
@ -182,7 +181,7 @@ namespace MWPhysics
|
|||
osg::Vec3f getScaledMeshTranslation() const;
|
||||
|
||||
bool mCanWaterWalk;
|
||||
std::atomic<bool> mWalkingOnWater;
|
||||
bool mWalkingOnWater;
|
||||
|
||||
bool mRotationallyInvariant;
|
||||
|
||||
|
@ -211,9 +210,9 @@ namespace MWPhysics
|
|||
osg::Vec3f mLastStuckPosition;
|
||||
|
||||
osg::Vec3f mForce;
|
||||
std::atomic<bool> mOnGround;
|
||||
std::atomic<bool> mOnSlope;
|
||||
std::atomic<bool> mInternalCollisionMode;
|
||||
bool mOnGround;
|
||||
bool mOnSlope;
|
||||
bool mInternalCollisionMode;
|
||||
bool mExternalCollisionMode;
|
||||
|
||||
PhysicsTaskScheduler* mTaskScheduler;
|
||||
|
|
|
@ -119,15 +119,14 @@ namespace MWPhysics
|
|||
WorldFrameData& worldData)
|
||||
{
|
||||
auto* physicActor = actor.mActorRaw;
|
||||
const ESM::Position& refpos = actor.mRefpos;
|
||||
|
||||
// Reset per-frame data
|
||||
physicActor->setWalkingOnWater(false);
|
||||
actor.mWalkingOnWater = false;
|
||||
// Anything to collide with?
|
||||
if(!physicActor->getCollisionMode() || actor.mSkipCollisionDetection)
|
||||
if(actor.mSkipCollisionDetection)
|
||||
{
|
||||
actor.mPosition += (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) *
|
||||
osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))
|
||||
actor.mPosition += (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) *
|
||||
osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))
|
||||
) * actor.mMovement * time;
|
||||
return;
|
||||
}
|
||||
|
@ -151,22 +150,22 @@ namespace MWPhysics
|
|||
|
||||
if (actor.mPosition.z() < swimlevel || actor.mFlying)
|
||||
{
|
||||
velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
velocity = (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
velocity = (osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
|
||||
if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
|
||||
|| (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope()))
|
||||
if ((velocity.z() > 0.f && actor.mIsOnGround && !actor.mIsOnSlope)
|
||||
|| (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && actor.mIsOnSlope))
|
||||
inertia = velocity;
|
||||
else if (!physicActor->getOnGround() || physicActor->getOnSlope())
|
||||
else if (!actor.mIsOnGround || actor.mIsOnSlope)
|
||||
velocity = velocity + inertia;
|
||||
}
|
||||
|
||||
// Dead and paralyzed actors underwater will float to the surface,
|
||||
// if the CharacterController tells us to do so
|
||||
if (actor.mMovement.z() > 0 && actor.mFloatToSurface && actor.mPosition.z() < swimlevel)
|
||||
if (actor.mMovement.z() > 0 && actor.mInert && actor.mPosition.z() < swimlevel)
|
||||
velocity = osg::Vec3f(0,0,1) * 25;
|
||||
|
||||
if (actor.mWantJump)
|
||||
|
@ -190,7 +189,7 @@ namespace MWPhysics
|
|||
* The initial velocity was set earlier (see above).
|
||||
*/
|
||||
float remainingTime = time;
|
||||
bool seenGround = physicActor->getOnGround() && !physicActor->getOnSlope() && !actor.mFlying;
|
||||
bool seenGround = actor.mIsOnGround && !actor.mIsOnSlope && !actor.mFlying;
|
||||
|
||||
int numTimesSlid = 0;
|
||||
osg::Vec3f lastSlideNormal(0,0,1);
|
||||
|
@ -349,7 +348,7 @@ namespace MWPhysics
|
|||
if (forceGroundTest || (inertia.z() <= 0.f && newPosition.z() >= swimlevel))
|
||||
{
|
||||
osg::Vec3f from = newPosition;
|
||||
auto dropDistance = 2*sGroundOffset + (physicActor->getOnGround() ? sStepSizeDown : 0);
|
||||
auto dropDistance = 2*sGroundOffset + (actor.mIsOnGround ? sStepSizeDown : 0);
|
||||
osg::Vec3f to = newPosition - osg::Vec3f(0,0,dropDistance);
|
||||
tracer.doTrace(colobj, from, to, collisionWorld);
|
||||
if(tracer.mFraction < 1.0f)
|
||||
|
@ -365,7 +364,7 @@ namespace MWPhysics
|
|||
actor.mStandingOn = ptrHolder->getPtr();
|
||||
|
||||
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water)
|
||||
physicActor->setWalkingOnWater(true);
|
||||
actor.mWalkingOnWater = true;
|
||||
if (!actor.mFlying && !isOnSlope)
|
||||
{
|
||||
if (tracer.mFraction*dropDistance > sGroundOffset)
|
||||
|
@ -408,8 +407,8 @@ namespace MWPhysics
|
|||
}
|
||||
physicActor->setInertialForce(inertia);
|
||||
}
|
||||
physicActor->setOnGround(isOnGround);
|
||||
physicActor->setOnSlope(isOnSlope);
|
||||
actor.mIsOnGround = isOnGround;
|
||||
actor.mIsOnSlope = isOnSlope;
|
||||
|
||||
actor.mPosition = newPosition;
|
||||
// remove what was added earlier in compensating for doTrace not taking interior transformation into account
|
||||
|
@ -426,7 +425,7 @@ namespace MWPhysics
|
|||
void MovementSolver::unstuck(ActorFrameData& actor, const btCollisionWorld* collisionWorld)
|
||||
{
|
||||
auto* physicActor = actor.mActorRaw;
|
||||
if(!physicActor->getCollisionMode() || actor.mSkipCollisionDetection) // noclipping/tcl
|
||||
if(actor.mSkipCollisionDetection) // noclipping/tcl
|
||||
return;
|
||||
|
||||
auto* collisionObject = physicActor->getCollisionObject();
|
||||
|
@ -448,9 +447,9 @@ namespace MWPhysics
|
|||
const auto verticalHalfExtent = osg::Vec3f(0.0, 0.0, physicActor->getHalfExtents().z());
|
||||
|
||||
// use a 3d approximation of the movement vector to better judge player intent
|
||||
auto velocity = (osg::Quat(actor.mRefpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRefpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
auto velocity = (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
|
||||
// try to pop outside of the world before doing anything else if we're inside of it
|
||||
if (!physicActor->getOnGround() || physicActor->getOnSlope())
|
||||
if (!actor.mIsOnGround || actor.mIsOnSlope)
|
||||
velocity += physicActor->getInertialForce();
|
||||
|
||||
// because of the internal collision box offset hack, and the fact that we're moving the collision box manually,
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
const float heightDiff = actorData.mPosition.z() - actorData.mOldHeight;
|
||||
|
||||
const bool isStillOnGround = (simulationPerformed && actorData.mWasOnGround && actorData.mActorRaw->getOnGround());
|
||||
const bool isStillOnGround = (simulationPerformed && actorData.mWasOnGround && actorData.mIsOnGround);
|
||||
|
||||
if (isStillOnGround || actorData.mFlying || actorData.mSwimming || actorData.mSlowFall < 1)
|
||||
actorData.mNeedLand = true;
|
||||
|
@ -256,7 +256,12 @@ namespace MWPhysics
|
|||
|
||||
// these variables are accessed directly from the main thread, update them here to prevent accessing "too new" values
|
||||
if (mAdvanceSimulation)
|
||||
{
|
||||
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
|
||||
data.mActorRaw->setOnGround(data.mIsOnGround);
|
||||
data.mActorRaw->setOnSlope(data.mIsOnSlope);
|
||||
data.mActorRaw->setWalkingOnWater(data.mWalkingOnWater);
|
||||
}
|
||||
data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt));
|
||||
}
|
||||
}
|
||||
|
@ -555,7 +560,12 @@ namespace MWPhysics
|
|||
actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt));
|
||||
updateMechanics(actorData);
|
||||
if (mAdvanceSimulation)
|
||||
{
|
||||
actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn);
|
||||
actorData.mActorRaw->setOnGround(actorData.mIsOnGround);
|
||||
actorData.mActorRaw->setOnSlope(actorData.mIsOnSlope);
|
||||
actorData.mActorRaw->setWalkingOnWater(actorData.mWalkingOnWater);
|
||||
}
|
||||
}
|
||||
refreshLOSCache();
|
||||
}
|
||||
|
|
|
@ -950,9 +950,24 @@ namespace MWPhysics
|
|||
|
||||
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn,
|
||||
bool waterCollision, float slowFall, float waterlevel)
|
||||
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
|
||||
mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision), mSkipCollisionDetection(actor->skipCollisions()),
|
||||
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(actor->velocity()), mPosition(), mRefpos()
|
||||
: mActor(actor)
|
||||
, mActorRaw(actor.get())
|
||||
, mStandingOn(standingOn)
|
||||
, mWasOnGround(actor->getOnGround())
|
||||
, mIsOnGround(actor->getOnGround())
|
||||
, mIsOnSlope(actor->getOnSlope())
|
||||
, mDidJump(false)
|
||||
, mNeedLand(false)
|
||||
, mWaterCollision(waterCollision)
|
||||
, mWalkingOnWater(false)
|
||||
, mSkipCollisionDetection(actor->skipCollisions() || !actor->getCollisionMode())
|
||||
, mWaterlevel(waterlevel)
|
||||
, mSlowFall(slowFall)
|
||||
, mOldHeight(0)
|
||||
, mFallHeight(0)
|
||||
, mMovement(actor->velocity())
|
||||
, mPosition()
|
||||
, mRotation()
|
||||
{
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const auto ptr = actor->getPtr();
|
||||
|
@ -961,8 +976,7 @@ namespace MWPhysics
|
|||
mWantJump = ptr.getClass().getMovementSettings(ptr).mPosition[2] != 0;
|
||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState();
|
||||
mFloatToSurface = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
|
||||
mWasOnGround = actor->getOnGround();
|
||||
mInert = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
|
||||
}
|
||||
|
||||
void ActorFrameData::updatePosition(btCollisionWorld* world)
|
||||
|
@ -975,7 +989,8 @@ namespace MWPhysics
|
|||
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition, false);
|
||||
}
|
||||
mOldHeight = mPosition.z();
|
||||
mRefpos = mActorRaw->getPtr().getRefData().getPosition();
|
||||
const auto rotation = mActorRaw->getPtr().getRefData().getPosition().asRotationVec3();
|
||||
mRotation = osg::Vec2f(rotation.x(), rotation.z());
|
||||
}
|
||||
|
||||
WorldFrameData::WorldFrameData()
|
||||
|
|
|
@ -86,11 +86,14 @@ namespace MWPhysics
|
|||
bool mFlying;
|
||||
bool mSwimming;
|
||||
bool mWasOnGround;
|
||||
bool mIsOnGround;
|
||||
bool mIsOnSlope;
|
||||
bool mWantJump;
|
||||
bool mDidJump;
|
||||
bool mFloatToSurface;
|
||||
bool mInert;
|
||||
bool mNeedLand;
|
||||
bool mWaterCollision;
|
||||
bool mWalkingOnWater;
|
||||
bool mSkipCollisionDetection;
|
||||
float mWaterlevel;
|
||||
float mSlowFall;
|
||||
|
@ -98,7 +101,7 @@ namespace MWPhysics
|
|||
float mFallHeight;
|
||||
osg::Vec3f mMovement;
|
||||
osg::Vec3f mPosition;
|
||||
ESM::Position mRefpos;
|
||||
osg::Vec2f mRotation;
|
||||
};
|
||||
|
||||
struct WorldFrameData
|
||||
|
|
Loading…
Reference in a new issue