mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 14:59:54 +00:00
Merge branch 'skating-olympics' into 'master'
De-jank stationary animations Closes #3330 See merge request OpenMW/openmw!3631
This commit is contained in:
commit
78a8f9d692
12 changed files with 142 additions and 32 deletions
|
@ -2,6 +2,7 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #2623: Snowy Granius doesn't prioritize conjuration spells
|
Bug #2623: Snowy Granius doesn't prioritize conjuration spells
|
||||||
|
Bug #3330: Backward displacement of the character when attacking in 3rd person
|
||||||
Bug #3438: NPCs can't hit bull netch with melee weapons
|
Bug #3438: NPCs can't hit bull netch with melee weapons
|
||||||
Bug #3842: Body part skeletons override the main skeleton
|
Bug #3842: Body part skeletons override the main skeleton
|
||||||
Bug #4127: Weapon animation looks choppy
|
Bug #4127: Weapon animation looks choppy
|
||||||
|
|
|
@ -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) = 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;
|
||||||
|
|
||||||
|
|
|
@ -2421,7 +2421,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isMovementAnimationControlled() && !isScriptedAnimPlaying())
|
if (!isMovementAnimationControlled() && !isScriptedAnimPlaying())
|
||||||
world->queueMovement(mPtr, vec);
|
{
|
||||||
|
world->queueMovement(mPtr, vec, duration, mInJump && mJumpState == JumpState_None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
movement = vec;
|
movement = vec;
|
||||||
|
@ -2494,7 +2496,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update movement
|
// Update movement
|
||||||
world->queueMovement(mPtr, movement);
|
world->queueMovement(mPtr, movement, duration, mInJump && mJumpState == JumpState_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSkipAnim = false;
|
mSkipAnim = false;
|
||||||
|
|
|
@ -170,6 +170,8 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have the effective movement vector, apply wind forces to it
|
// Now that we have the effective movement vector, apply wind forces to it
|
||||||
|
// TODO: This will cause instability in idle animations and other in-place animations. Should include a flag for
|
||||||
|
// this when queueing up movement
|
||||||
if (worldData.mIsInStorm && velocity.length() > 0)
|
if (worldData.mIsInStorm && velocity.length() > 0)
|
||||||
{
|
{
|
||||||
osg::Vec3f stormDirection = worldData.mStormDirection;
|
osg::Vec3f stormDirection = worldData.mStormDirection;
|
||||||
|
@ -200,7 +202,8 @@ namespace MWPhysics
|
||||||
|
|
||||||
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.0001f; ++iterations)
|
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.0001f; ++iterations)
|
||||||
{
|
{
|
||||||
osg::Vec3f nextpos = newPosition + velocity * remainingTime;
|
osg::Vec3f diff = velocity * remainingTime;
|
||||||
|
osg::Vec3f nextpos = newPosition + diff;
|
||||||
bool underwater = newPosition.z() < swimlevel;
|
bool underwater = newPosition.z() < swimlevel;
|
||||||
|
|
||||||
// If not able to fly, don't allow to swim up into the air
|
// If not able to fly, don't allow to swim up into the air
|
||||||
|
@ -212,7 +215,11 @@ namespace MWPhysics
|
||||||
continue; // velocity updated, calculate nextpos again
|
continue; // velocity updated, calculate nextpos again
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((newPosition - nextpos).length2() > 0.0001)
|
// Note, we use an epsilon of 1e-6 instead of std::numeric_limits<float>::epsilon() to avoid doing extremely
|
||||||
|
// small steps. But if we make it any larger we'll start rejecting subtle movements from e.g. idle
|
||||||
|
// animations. Note that, although both these comparisons to 1e-6 are logically the same, they test separate
|
||||||
|
// floating point accuracy cases.
|
||||||
|
if (diff.length2() > 1e-6 && (newPosition - nextpos).length2() > 1e-6)
|
||||||
{
|
{
|
||||||
// trace to where character would go if there were no obstructions
|
// trace to where character would go if there were no obstructions
|
||||||
tracer.doTrace(actor.mCollisionObject, newPosition, nextpos, collisionWorld, actor.mIsOnGround);
|
tracer.doTrace(actor.mCollisionObject, newPosition, nextpos, collisionWorld, actor.mIsOnGround);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "../mwrender/bulletdebugdraw.hpp"
|
#include "../mwrender/bulletdebugdraw.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/datetimemanager.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
#include "physicssystem.hpp"
|
#include "physicssystem.hpp"
|
||||||
#include "projectile.hpp"
|
#include "projectile.hpp"
|
||||||
|
#include "ptrholder.hpp"
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
|
@ -195,6 +197,67 @@ namespace
|
||||||
void operator()(MWPhysics::ProjectileSimulation& /*sim*/) const {}
|
void operator()(MWPhysics::ProjectileSimulation& /*sim*/) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct InitMovement
|
||||||
|
{
|
||||||
|
int mSteps = 0;
|
||||||
|
float mDelta = 0.f;
|
||||||
|
float mSimulationTime = 0.f;
|
||||||
|
|
||||||
|
// Returns how the actor or projectile wants to move between startTime and endTime
|
||||||
|
osg::Vec3f takeMovement(MWPhysics::PtrHolder& actor, float startTime, float endTime) const
|
||||||
|
{
|
||||||
|
osg::Vec3f movement = osg::Vec3f();
|
||||||
|
actor.eraseMovementIf([&](MWPhysics::Movement& v) {
|
||||||
|
if (v.mJump)
|
||||||
|
return false;
|
||||||
|
float start = std::max(v.mSimulationTimeStart, startTime);
|
||||||
|
float stop = std::min(v.mSimulationTimeStop, endTime);
|
||||||
|
movement += v.mVelocity * (stop - start);
|
||||||
|
if (std::abs(stop - v.mSimulationTimeStop) < 0.0001f)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<osg::Vec3f> takeInertia(MWPhysics::PtrHolder& actor, float startTime) const
|
||||||
|
{
|
||||||
|
std::optional<osg::Vec3f> inertia = std::nullopt;
|
||||||
|
actor.eraseMovementIf([&](MWPhysics::Movement& v) {
|
||||||
|
if (v.mJump && v.mSimulationTimeStart >= startTime)
|
||||||
|
{
|
||||||
|
inertia = v.mVelocity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return inertia;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(auto& sim) const
|
||||||
|
{
|
||||||
|
if (mSteps <= 0 || mDelta < 0.00001f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto locked = sim.lock();
|
||||||
|
if (!locked.has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& [ptrHolder, frameDataRef] = *locked;
|
||||||
|
|
||||||
|
// Because takeMovement() returns movement instead of velocity, convert it back to velocity for the
|
||||||
|
// 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 += inertia.value_or(velocity);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct PreStep
|
struct PreStep
|
||||||
{
|
{
|
||||||
btCollisionWorld* mCollisionWorld;
|
btCollisionWorld* mCollisionWorld;
|
||||||
|
@ -501,18 +564,18 @@ namespace MWPhysics
|
||||||
return std::make_tuple(numSteps, actualDelta);
|
return std::make_tuple(numSteps, actualDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::applyQueuedMovements(float& timeAccum, std::vector<Simulation>& simulations,
|
void PhysicsTaskScheduler::applyQueuedMovements(float& timeAccum, float simulationTime,
|
||||||
osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
std::vector<Simulation>& simulations, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||||
{
|
{
|
||||||
assert(mSimulations != &simulations);
|
assert(mSimulations != &simulations);
|
||||||
|
|
||||||
waitForWorkers();
|
waitForWorkers();
|
||||||
prepareWork(timeAccum, simulations, frameStart, frameNumber, stats);
|
prepareWork(timeAccum, simulationTime, simulations, frameStart, frameNumber, stats);
|
||||||
if (mWorkersSync != nullptr)
|
if (mWorkersSync != nullptr)
|
||||||
mWorkersSync->wakeUpWorkers();
|
mWorkersSync->wakeUpWorkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsTaskScheduler::prepareWork(float& timeAccum, std::vector<Simulation>& simulations,
|
void PhysicsTaskScheduler::prepareWork(float& timeAccum, float simulationTime, std::vector<Simulation>& simulations,
|
||||||
osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||||
{
|
{
|
||||||
// This function run in the main thread.
|
// This function run in the main thread.
|
||||||
|
@ -522,6 +585,9 @@ namespace MWPhysics
|
||||||
|
|
||||||
double timeStart = mTimer->tick();
|
double timeStart = mTimer->tick();
|
||||||
|
|
||||||
|
// The simulation time when the movement solving begins.
|
||||||
|
float simulationTimeStart = simulationTime - timeAccum;
|
||||||
|
|
||||||
// start by finishing previous background computation
|
// start by finishing previous background computation
|
||||||
if (mNumThreads != 0)
|
if (mNumThreads != 0)
|
||||||
{
|
{
|
||||||
|
@ -536,10 +602,15 @@ namespace MWPhysics
|
||||||
timeAccum -= numSteps * newDelta;
|
timeAccum -= numSteps * newDelta;
|
||||||
|
|
||||||
// init
|
// init
|
||||||
const Visitors::InitPosition vis{ mCollisionWorld };
|
const Visitors::InitPosition initPositionVisitor{ mCollisionWorld };
|
||||||
for (auto& sim : simulations)
|
for (auto& sim : simulations)
|
||||||
{
|
{
|
||||||
std::visit(vis, sim);
|
std::visit(initPositionVisitor, sim);
|
||||||
|
}
|
||||||
|
const Visitors::InitMovement initMovementVisitor{ numSteps, newDelta, simulationTimeStart };
|
||||||
|
for (auto& sim : simulations)
|
||||||
|
{
|
||||||
|
std::visit(initMovementVisitor, sim);
|
||||||
}
|
}
|
||||||
mPrevStepCount = numSteps;
|
mPrevStepCount = numSteps;
|
||||||
mRemainingSteps = numSteps;
|
mRemainingSteps = numSteps;
|
||||||
|
@ -552,10 +623,10 @@ namespace MWPhysics
|
||||||
mNextJob.store(0, std::memory_order_release);
|
mNextJob.store(0, std::memory_order_release);
|
||||||
|
|
||||||
if (mAdvanceSimulation)
|
if (mAdvanceSimulation)
|
||||||
|
{
|
||||||
mWorldFrameData = std::make_unique<WorldFrameData>();
|
mWorldFrameData = std::make_unique<WorldFrameData>();
|
||||||
|
|
||||||
if (mAdvanceSimulation)
|
|
||||||
mBudgetCursor += 1;
|
mBudgetCursor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (mNumThreads == 0)
|
if (mNumThreads == 0)
|
||||||
{
|
{
|
||||||
|
@ -864,6 +935,7 @@ namespace MWPhysics
|
||||||
std::remove_if(mLOSCache.begin(), mLOSCache.end(), [](const LOSRequest& req) { return req.mStale; }),
|
std::remove_if(mLOSCache.begin(), mLOSCache.end(), [](const LOSRequest& req) { return req.mStale; }),
|
||||||
mLOSCache.end());
|
mLOSCache.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
mTimeEnd = mTimer->tick();
|
mTimeEnd = mTimer->tick();
|
||||||
if (mWorkersSync != nullptr)
|
if (mWorkersSync != nullptr)
|
||||||
mWorkersSync->workIsDone();
|
mWorkersSync->workIsDone();
|
||||||
|
|
|
@ -46,8 +46,8 @@ namespace MWPhysics
|
||||||
/// @param timeAccum accumulated time from previous run to interpolate movements
|
/// @param timeAccum accumulated time from previous run to interpolate movements
|
||||||
/// @param actorsData per actor data needed to compute new positions
|
/// @param actorsData per actor data needed to compute new positions
|
||||||
/// @return new position of each actor
|
/// @return new position of each actor
|
||||||
void applyQueuedMovements(float& timeAccum, std::vector<Simulation>& simulations, osg::Timer_t frameStart,
|
void applyQueuedMovements(float& timeAccum, float simulationTime, std::vector<Simulation>& simulations,
|
||||||
unsigned int frameNumber, osg::Stats& stats);
|
osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
||||||
|
|
||||||
void resetSimulation(const ActorMap& actors);
|
void resetSimulation(const ActorMap& actors);
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ namespace MWPhysics
|
||||||
void afterPostSim();
|
void afterPostSim();
|
||||||
void syncWithMainThread();
|
void syncWithMainThread();
|
||||||
void waitForWorkers();
|
void waitForWorkers();
|
||||||
void prepareWork(float& timeAccum, std::vector<Simulation>& simulations, osg::Timer_t frameStart,
|
void prepareWork(float& timeAccum, float simulationTime, std::vector<Simulation>& simulations,
|
||||||
unsigned int frameNumber, osg::Stats& stats);
|
osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats);
|
||||||
|
|
||||||
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
std::unique_ptr<WorldFrameData> mWorldFrameData;
|
||||||
std::vector<Simulation>* mSimulations = nullptr;
|
std::vector<Simulation>* mSimulations = nullptr;
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "../mwrender/bulletdebugdraw.hpp"
|
#include "../mwrender/bulletdebugdraw.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/datetimemanager.hpp"
|
||||||
|
|
||||||
#include "actor.hpp"
|
#include "actor.hpp"
|
||||||
#include "collisiontype.hpp"
|
#include "collisiontype.hpp"
|
||||||
|
@ -623,18 +624,20 @@ namespace MWPhysics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity)
|
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);
|
ActorMap::iterator found = mActors.find(ptr.mRef);
|
||||||
if (found != mActors.end())
|
if (found != mActors.end())
|
||||||
found->second->setVelocity(velocity);
|
found->second->queueMovement(velocity, start, start + duration, jump);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::clearQueuedMovement()
|
void PhysicsSystem::clearQueuedMovement()
|
||||||
{
|
{
|
||||||
for (const auto& [_, actor] : mActors)
|
for (const auto& [_, actor] : mActors)
|
||||||
{
|
{
|
||||||
actor->setVelocity(osg::Vec3f());
|
actor->clearMovement();
|
||||||
actor->setInertialForce(osg::Vec3f());
|
actor->setInertialForce(osg::Vec3f());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -722,8 +725,10 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
std::vector<Simulation>& simulations = mSimulations[mSimulationsCounter++ % mSimulations.size()];
|
std::vector<Simulation>& simulations = mSimulations[mSimulationsCounter++ % mSimulations.size()];
|
||||||
prepareSimulation(mTimeAccum >= mPhysicsDt, simulations);
|
prepareSimulation(mTimeAccum >= mPhysicsDt, simulations);
|
||||||
|
float simulationTime = MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime() + dt;
|
||||||
// modifies mTimeAccum
|
// modifies mTimeAccum
|
||||||
mTaskScheduler->applyQueuedMovements(mTimeAccum, simulations, frameStart, frameNumber, stats);
|
mTaskScheduler->applyQueuedMovements(
|
||||||
|
mTimeAccum, simulationTime, simulations, frameStart, frameNumber, stats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,7 +912,7 @@ namespace MWPhysics
|
||||||
->mValue.getFloat()))
|
->mValue.getFloat()))
|
||||||
, mSlowFall(slowFall)
|
, mSlowFall(slowFall)
|
||||||
, mRotation()
|
, mRotation()
|
||||||
, mMovement(actor.velocity())
|
, mMovement()
|
||||||
, mWaterlevel(waterlevel)
|
, mWaterlevel(waterlevel)
|
||||||
, mHalfExtentsZ(actor.getHalfExtents().z())
|
, mHalfExtentsZ(actor.getHalfExtents().z())
|
||||||
, mOldHeight(0)
|
, mOldHeight(0)
|
||||||
|
@ -922,7 +927,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
ProjectileFrameData::ProjectileFrameData(Projectile& projectile)
|
ProjectileFrameData::ProjectileFrameData(Projectile& projectile)
|
||||||
: mPosition(projectile.getPosition())
|
: mPosition(projectile.getPosition())
|
||||||
, mMovement(projectile.velocity())
|
, mMovement()
|
||||||
, mCaster(projectile.getCasterCollisionObject())
|
, mCaster(projectile.getCasterCollisionObject())
|
||||||
, mCollisionObject(projectile.getCollisionObject())
|
, mCollisionObject(projectile.getCollisionObject())
|
||||||
, mProjectile(&projectile)
|
, mProjectile(&projectile)
|
||||||
|
|
|
@ -245,7 +245,8 @@ 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);
|
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();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_MWPHYSICS_PTRHOLDER_H
|
#ifndef OPENMW_MWPHYSICS_PTRHOLDER_H
|
||||||
#define OPENMW_MWPHYSICS_PTRHOLDER_H
|
#define OPENMW_MWPHYSICS_PTRHOLDER_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -13,6 +14,14 @@
|
||||||
|
|
||||||
namespace MWPhysics
|
namespace MWPhysics
|
||||||
{
|
{
|
||||||
|
struct Movement
|
||||||
|
{
|
||||||
|
osg::Vec3f mVelocity = osg::Vec3f();
|
||||||
|
float mSimulationTimeStart = 0.f; // The time at which this movement begun
|
||||||
|
float mSimulationTimeStop = 0.f; // The time at which this movement finished
|
||||||
|
bool mJump = false;
|
||||||
|
};
|
||||||
|
|
||||||
class PtrHolder
|
class PtrHolder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -32,9 +41,13 @@ namespace MWPhysics
|
||||||
|
|
||||||
btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); }
|
btCollisionObject* getCollisionObject() const { return mCollisionObject.get(); }
|
||||||
|
|
||||||
void setVelocity(osg::Vec3f velocity) { mVelocity = velocity; }
|
void clearMovement() { mMovement = {}; }
|
||||||
|
void queueMovement(osg::Vec3f velocity, float simulationTimeStart, float simulationTimeStop, bool jump = false)
|
||||||
|
{
|
||||||
|
mMovement.push_back(Movement{ velocity, simulationTimeStart, simulationTimeStop, jump });
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f velocity() { return std::exchange(mVelocity, osg::Vec3f()); }
|
void eraseMovementIf(const auto& predicate) { std::erase_if(mMovement, predicate); }
|
||||||
|
|
||||||
void setSimulationPosition(const osg::Vec3f& position) { mSimulationPosition = position; }
|
void setSimulationPosition(const osg::Vec3f& position) { mSimulationPosition = position; }
|
||||||
|
|
||||||
|
@ -53,7 +66,7 @@ namespace MWPhysics
|
||||||
protected:
|
protected:
|
||||||
MWWorld::Ptr mPtr;
|
MWWorld::Ptr mPtr;
|
||||||
std::unique_ptr<btCollisionObject> mCollisionObject;
|
std::unique_ptr<btCollisionObject> mCollisionObject;
|
||||||
osg::Vec3f mVelocity;
|
std::list<Movement> mMovement;
|
||||||
osg::Vec3f mSimulationPosition;
|
osg::Vec3f mSimulationPosition;
|
||||||
osg::Vec3d mPosition;
|
osg::Vec3d mPosition;
|
||||||
osg::Vec3d mPreviousPosition;
|
osg::Vec3d mPreviousPosition;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <components/settings/values.hpp>
|
#include <components/settings/values.hpp>
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/datetimemanager.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
#include "../mwworld/manualref.hpp"
|
#include "../mwworld/manualref.hpp"
|
||||||
|
@ -457,7 +458,8 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
osg::Vec3f direction = orient * osg::Vec3f(0, 1, 0);
|
osg::Vec3f direction = orient * osg::Vec3f(0, 1, 0);
|
||||||
direction.normalize();
|
direction.normalize();
|
||||||
projectile->setVelocity(direction * speed);
|
float start = MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime();
|
||||||
|
projectile->queueMovement(direction * speed, start, start + duration);
|
||||||
|
|
||||||
update(magicBoltState, duration);
|
update(magicBoltState, duration);
|
||||||
|
|
||||||
|
@ -485,7 +487,8 @@ namespace MWWorld
|
||||||
projectileState.mVelocity
|
projectileState.mVelocity
|
||||||
-= osg::Vec3f(0, 0, Constants::GravityConst * Constants::UnitsPerMeter * 0.1f) * duration;
|
-= osg::Vec3f(0, 0, Constants::GravityConst * Constants::UnitsPerMeter * 0.1f) * duration;
|
||||||
|
|
||||||
projectile->setVelocity(projectileState.mVelocity);
|
float start = MWBase::Environment::get().getWorld()->getTimeManager()->getSimulationTime();
|
||||||
|
projectile->queueMovement(projectileState.mVelocity, start, start + duration);
|
||||||
|
|
||||||
// rotation does not work well for throwing projectiles - their roll angle will depend on shooting
|
// rotation does not work well for throwing projectiles - their roll angle will depend on shooting
|
||||||
// direction.
|
// direction.
|
||||||
|
|
|
@ -1448,9 +1448,9 @@ namespace MWWorld
|
||||||
return placed;
|
return placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity)
|
void World::queueMovement(const Ptr& ptr, const osg::Vec3f& velocity, float duration, bool jump)
|
||||||
{
|
{
|
||||||
mPhysics->queueObjectMovement(ptr, velocity);
|
mPhysics->queueObjectMovement(ptr, velocity, duration, jump);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::updateAnimatedCollisionShape(const Ptr& ptr)
|
void World::updateAnimatedCollisionShape(const Ptr& ptr)
|
||||||
|
|
|
@ -383,9 +383,11 @@ namespace MWWorld
|
||||||
|
|
||||||
float getMaxActivationDistance() const override;
|
float getMaxActivationDistance() const override;
|
||||||
|
|
||||||
void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) 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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue