1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-27 05:40:25 +00:00

Add a flag for jump when queueing movement, so inertia can be added accurately.

This commit is contained in:
Mads Buvik Sandvei 2023-12-09 16:48:04 +01:00
parent 32d391f548
commit c79446818e
8 changed files with 53 additions and 16 deletions

View file

@ -295,9 +295,13 @@ namespace MWBase
/// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is
/// obstructed). /// obstructed).
virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration) = 0; virtual void queueMovement(
const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump = false)
= 0;
///< Queues movement for \a ptr (in local space), to be applied in the next call to ///< Queues movement for \a ptr (in local space), to be applied in the next call to
/// doPhysics. /// doPhysics.
/// \param duration The duration this speed shall be held, starting at current simulation time
/// \param jump Whether the movement shall be run over time, or immediately added as inertia instead
virtual void updateAnimatedCollisionShape(const MWWorld::Ptr& ptr) = 0; virtual void updateAnimatedCollisionShape(const MWWorld::Ptr& ptr) = 0;
@ -567,7 +571,8 @@ namespace MWBase
virtual DetourNavigator::Navigator* getNavigator() const = 0; virtual DetourNavigator::Navigator* getNavigator() const = 0;
virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path, virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const = 0; const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const
= 0;
virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0; virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0;
@ -576,10 +581,12 @@ namespace MWBase
virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0; virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0;
virtual bool hasCollisionWithDoor( virtual bool hasCollisionWithDoor(
const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const
= 0;
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
std::span<const MWWorld::ConstPtr> ignore, std::vector<MWWorld::Ptr>* occupyingActors = nullptr) const = 0; std::span<const MWWorld::ConstPtr> ignore, std::vector<MWWorld::Ptr>* occupyingActors = nullptr) const
= 0;
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;

View file

@ -2420,7 +2420,9 @@ namespace MWMechanics
} }
if (!isMovementAnimationControlled() && !isScriptedAnimPlaying()) if (!isMovementAnimationControlled() && !isScriptedAnimPlaying())
world->queueMovement(mPtr, vec, duration); {
world->queueMovement(mPtr, vec, duration, mInJump && mJumpState == JumpState_None);
}
} }
movement = vec; movement = vec;
@ -2446,7 +2448,6 @@ namespace MWMechanics
} }
} }
bool doMovementAccumulation = isMovementAnimationControlled();
osg::Vec3f movementFromAnimation osg::Vec3f movementFromAnimation
= mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration); = mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration);
@ -2494,7 +2495,7 @@ namespace MWMechanics
} }
// Update movement // Update movement
world->queueMovement(mPtr, movement, duration); world->queueMovement(mPtr, movement, duration, mInJump && mJumpState == JumpState_None);
} }
mSkipAnim = false; mSkipAnim = false;

View file

@ -210,6 +210,13 @@ namespace
auto it = actor.movement().begin(); auto it = actor.movement().begin();
while (it != actor.movement().end()) while (it != actor.movement().end())
{ {
if (it->jump)
{
// Adjusting inertia is instant and should not be performed over time like other movement is.
it++;
continue;
}
float start = std::max(it->simulationTimeStart, startTime); float start = std::max(it->simulationTimeStart, startTime);
float stop = std::min(it->simulationTimeStop, endTime); float stop = std::min(it->simulationTimeStop, endTime);
movement += it->velocity * (stop - start); movement += it->velocity * (stop - start);
@ -222,6 +229,23 @@ namespace
return movement; return movement;
} }
std::optional<osg::Vec3f> takeInertia(MWPhysics::PtrHolder& actor, float startTime) const
{
std::optional<osg::Vec3f> inertia = std::nullopt;
auto it = actor.movement().begin();
while (it != actor.movement().end())
{
if (it->jump && it->simulationTimeStart >= startTime)
{
inertia = it->velocity;
it = actor.movement().erase(it);
}
else
it++;
}
return inertia;
}
void operator()(auto& sim) const void operator()(auto& sim) const
{ {
if (mSteps <= 0 || mDelta < 0.00001f) if (mSteps <= 0 || mDelta < 0.00001f)
@ -237,8 +261,10 @@ namespace
// movement solver // movement solver
osg::Vec3f velocity osg::Vec3f velocity
= takeMovement(*ptrHolder, mSimulationTime, mSimulationTime + mDelta * mSteps) / (mSteps * mDelta); = takeMovement(*ptrHolder, mSimulationTime, mSimulationTime + mDelta * mSteps) / (mSteps * mDelta);
// takeInertia() returns a velocity and should be taken over the velocity calculated above to initiate a jump
auto inertia = takeInertia(*ptrHolder, mSimulationTime);
frameDataRef.get().mMovement += velocity; frameDataRef.get().mMovement += inertia.value_or(velocity);
} }
}; };

View file

@ -624,12 +624,12 @@ namespace MWPhysics
return false; return false;
} }
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration) void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump)
{ {
float start = MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime(); float start = MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime();
ActorMap::iterator found = mActors.find(ptr.mRef); ActorMap::iterator found = mActors.find(ptr.mRef);
if (found != mActors.end()) if (found != mActors.end())
found->second->queueMovement(velocity, start, start + duration); found->second->queueMovement(velocity, start, start + duration, jump);
} }
void PhysicsSystem::clearQueuedMovement() void PhysicsSystem::clearQueuedMovement()

View file

@ -245,7 +245,7 @@ namespace MWPhysics
/// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
/// be overwritten. Valid until the next call to stepSimulation /// be overwritten. Valid until the next call to stepSimulation
void queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration); void queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump = false);
/// Clear the queued movements list without applying. /// Clear the queued movements list without applying.
void clearQueuedMovement(); void clearQueuedMovement();

View file

@ -19,6 +19,7 @@ namespace MWPhysics
osg::Vec3f velocity = osg::Vec3f(); osg::Vec3f velocity = osg::Vec3f();
float simulationTimeStart = 0.f; // The time at which this movement begun float simulationTimeStart = 0.f; // The time at which this movement begun
float simulationTimeStop = 0.f; // The time at which this movement finished float simulationTimeStop = 0.f; // The time at which this movement finished
bool jump = false;
}; };
class PtrHolder class PtrHolder
@ -41,9 +42,9 @@ namespace MWPhysics
btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); } btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); }
void clearMovement() { mMovement = {}; } void clearMovement() { mMovement = {}; }
void queueMovement(osg::Vec3f velocity, float simulationTimeStart, float simulationTimeStop) void queueMovement(osg::Vec3f velocity, float simulationTimeStart, float simulationTimeStop, bool jump = false)
{ {
mMovement.push_back(Movement{ velocity, simulationTimeStart, simulationTimeStop }); mMovement.push_back(Movement{ velocity, simulationTimeStart, simulationTimeStop, jump });
} }
std::deque<Movement>& movement() { return mMovement; } std::deque<Movement>& movement() { return mMovement; }

View file

@ -1448,9 +1448,9 @@ namespace MWWorld
return placed; return placed;
} }
void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity, float duration) void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump)
{ {
mPhysics->queueObjectMovement(ptr, velocity, duration); mPhysics->queueObjectMovement(ptr, velocity, duration, jump);
} }
void World::updateAnimatedCollisionShape(const Ptr& ptr) void World::updateAnimatedCollisionShape(const Ptr& ptr)

View file

@ -383,9 +383,11 @@ namespace MWWorld
float getMaxActivationDistance() const override; float getMaxActivationDistance() const override;
void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity, float duration) override; void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump = false) override;
///< Queues movement for \a ptr (in local space), to be applied in the next call to ///< Queues movement for \a ptr (in local space), to be applied in the next call to
/// doPhysics. /// doPhysics.
/// \param duration The duration this speed shall be held, starting at current simulation time
/// \param jump Whether the movement shall be run over time, or immediately added as inertia instead
void updateAnimatedCollisionShape(const Ptr& ptr) override; void updateAnimatedCollisionShape(const Ptr& ptr) override;