From c79446818ef27a802d016e4e41e2e40d1970afe7 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Sat, 9 Dec 2023 16:48:04 +0100 Subject: [PATCH] Add a flag for jump when queueing movement, so inertia can be added accurately. --- apps/openmw/mwbase/world.hpp | 15 +++++++++---- apps/openmw/mwmechanics/character.cpp | 7 ++++--- apps/openmw/mwphysics/mtphysics.cpp | 28 ++++++++++++++++++++++++- apps/openmw/mwphysics/physicssystem.cpp | 4 ++-- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwphysics/ptrholder.hpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 4 +++- 8 files changed, 53 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f67b9a0e05..8670202965 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -295,9 +295,13 @@ namespace MWBase /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// 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 /// 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; @@ -567,7 +571,8 @@ namespace MWBase virtual DetourNavigator::Navigator* getNavigator() const = 0; virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque& 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; @@ -576,10 +581,12 @@ namespace MWBase virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0; 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, - std::span ignore, std::vector* occupyingActors = nullptr) const = 0; + std::span ignore, std::vector* occupyingActors = nullptr) const + = 0; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3eb392daf1..2aece5f86f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2420,7 +2420,9 @@ namespace MWMechanics } if (!isMovementAnimationControlled() && !isScriptedAnimPlaying()) - world->queueMovement(mPtr, vec, duration); + { + world->queueMovement(mPtr, vec, duration, mInJump && mJumpState == JumpState_None); + } } movement = vec; @@ -2446,7 +2448,6 @@ namespace MWMechanics } } - bool doMovementAccumulation = isMovementAnimationControlled(); osg::Vec3f movementFromAnimation = mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration); @@ -2494,7 +2495,7 @@ namespace MWMechanics } // Update movement - world->queueMovement(mPtr, movement, duration); + world->queueMovement(mPtr, movement, duration, mInJump && mJumpState == JumpState_None); } mSkipAnim = false; diff --git a/apps/openmw/mwphysics/mtphysics.cpp b/apps/openmw/mwphysics/mtphysics.cpp index deef837992..cc0c38a471 100644 --- a/apps/openmw/mwphysics/mtphysics.cpp +++ b/apps/openmw/mwphysics/mtphysics.cpp @@ -210,6 +210,13 @@ namespace auto it = actor.movement().begin(); 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 stop = std::min(it->simulationTimeStop, endTime); movement += it->velocity * (stop - start); @@ -222,6 +229,23 @@ namespace return movement; } + std::optional takeInertia(MWPhysics::PtrHolder& actor, float startTime) const + { + std::optional 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 { if (mSteps <= 0 || mDelta < 0.00001f) @@ -237,8 +261,10 @@ namespace // movement solver osg::Vec3f velocity = 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); } }; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 3c451497e1..6f57c7db01 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -624,12 +624,12 @@ namespace MWPhysics 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(); ActorMap::iterator found = mActors.find(ptr.mRef); if (found != mActors.end()) - found->second->queueMovement(velocity, start, start + duration); + found->second->queueMovement(velocity, start, start + duration, jump); } void PhysicsSystem::clearQueuedMovement() diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 3babdef9aa..7729f274f1 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -245,7 +245,7 @@ namespace MWPhysics /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// 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. void clearQueuedMovement(); diff --git a/apps/openmw/mwphysics/ptrholder.hpp b/apps/openmw/mwphysics/ptrholder.hpp index 5884372e42..d7a6f887bb 100644 --- a/apps/openmw/mwphysics/ptrholder.hpp +++ b/apps/openmw/mwphysics/ptrholder.hpp @@ -19,6 +19,7 @@ namespace MWPhysics osg::Vec3f velocity = osg::Vec3f(); float simulationTimeStart = 0.f; // The time at which this movement begun float simulationTimeStop = 0.f; // The time at which this movement finished + bool jump = false; }; class PtrHolder @@ -41,9 +42,9 @@ namespace MWPhysics btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); } 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() { return mMovement; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9db72d1604..b6b7de24b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1448,9 +1448,9 @@ namespace MWWorld 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) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 486e240fdc..aa5f9d56f0 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -383,9 +383,11 @@ namespace MWWorld 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 /// 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;