Merge branch 'cherry-pick-6eaf0a38' into 'master'

Merge branch 'movement_refactoring' into 'master'

See merge request OpenMW/openmw!287
pull/593/head
psi29a 4 years ago
commit 26c38ecb46

@ -91,4 +91,13 @@ namespace MWClass
{
return true;
}
float Actor::getCurrentSpeed(const MWWorld::Ptr& ptr) const
{
const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr);
float moveSpeed = this->getMaxSpeed(ptr) * movementSettings.mSpeedFactor;
if (movementSettings.mIsStrafing)
moveSpeed *= 0.75f;
return moveSpeed;
}
}

@ -31,7 +31,7 @@ namespace MWClass
virtual void block(const MWWorld::Ptr &ptr) const;
virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const;
///< Return desired rotations, as euler angles.
///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero.
virtual float getEncumbrance(const MWWorld::Ptr& ptr) const;
///< Returns total weight of objects inside this object (including modifications from magic
@ -42,6 +42,9 @@ namespace MWClass
virtual bool isActor() const;
/// Return current movement speed.
virtual float getCurrentSpeed(const MWWorld::Ptr& ptr) const;
// not implemented
Actor(const Actor&);
Actor& operator= (const Actor&);

@ -500,7 +500,7 @@ namespace MWClass
registerClass (typeid (ESM::Creature).name(), instance);
}
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
float Creature::getMaxSpeed(const MWWorld::Ptr &ptr) const
{
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
@ -532,11 +532,6 @@ namespace MWClass
else
moveSpeed = getWalkSpeed(ptr);
const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr);
if (movementSettings.mIsStrafing)
moveSpeed *= 0.75f;
moveSpeed *= movementSettings.mSpeedFactor;
return moveSpeed;
}

@ -94,7 +94,7 @@ namespace MWClass
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
///< Return desired movement.
float getSpeed (const MWWorld::Ptr& ptr) const;
float getMaxSpeed (const MWWorld::Ptr& ptr) const;
static void registerSelf();

@ -936,7 +936,7 @@ namespace MWClass
return ref->mBase->mScript;
}
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
float Npc::getMaxSpeed(const MWWorld::Ptr& ptr) const
{
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead())
@ -979,11 +979,6 @@ namespace MWClass
if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing)
moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat();
const MWMechanics::Movement& movementSettings = ptr.getClass().getMovementSettings(ptr);
if (movementSettings.mIsStrafing)
moveSpeed *= 0.75f;
moveSpeed *= movementSettings.mSpeedFactor;
return moveSpeed;
}

@ -84,8 +84,8 @@ namespace MWClass
virtual std::string getScript (const MWWorld::ConstPtr& ptr) const;
///< Return name of the script attached to ptr
virtual float getSpeed (const MWWorld::Ptr& ptr) const;
///< Return movement speed.
virtual float getMaxSpeed (const MWWorld::Ptr& ptr) const;
///< Return maximal movement speed.
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)

@ -472,9 +472,6 @@ namespace MWMechanics
void Actors::updateMovementSpeed(const MWWorld::Ptr& actor)
{
float previousSpeedFactor = actor.getClass().getMovementSettings(actor).mSpeedFactor;
float newSpeedFactor = 1.f;
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
MWMechanics::AiSequence& seq = stats.getAiSequence();
@ -484,10 +481,13 @@ namespace MWMechanics
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
float distance = (targetPos - actorPos).length();
if (distance < DECELERATE_DISTANCE)
newSpeedFactor = std::max(0.7f, 0.1f * previousSpeedFactor * (distance/64.f + 2.f));
{
float speedCoef = std::max(0.7f, 0.1f * (distance/64.f + 2.f));
auto& movement = actor.getClass().getMovementSettings(actor);
movement.mPosition[0] *= speedCoef;
movement.mPosition[1] *= speedCoef;
}
}
actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor;
}
void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly)

@ -144,7 +144,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
mTimer = 0;
}
const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration
const float actorTolerance = 2 * actor.getClass().getMaxSpeed(actor) * duration
+ 1.2 * std::max(halfExtents.x(), halfExtents.y());
const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance);
@ -300,7 +300,7 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin
if (canActorMoveByZAxis(actor))
return true;
const float actorSpeed = actor.getClass().getSpeed(actor);
const float actorSpeed = actor.getClass().getMaxSpeed(actor);
const float maxAvoidDist = AI_REACTION_TIME * actorSpeed + actorSpeed / getAngularVelocity(actorSpeed) * 2; // *2 - for reliability
const float distToTarget = osg::Vec2f(endPoint.x(), endPoint.y()).length();
@ -360,7 +360,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position)
bool MWMechanics::AiPackage::isReachableRotatingOnTheRun(const MWWorld::Ptr& actor, const osg::Vec3f& dest)
{
// get actor's shortest radius for moving in circle
float speed = actor.getClass().getSpeed(actor);
float speed = actor.getClass().getMaxSpeed(actor);
speed += speed * 0.1f; // 10% real speed inaccuracy
float radius = speed / getAngularVelocity(speed);

@ -21,6 +21,7 @@
#include <iostream>
#include <components/misc/mathutil.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
@ -51,15 +52,6 @@
namespace
{
// Wraps a value to (-PI, PI]
void wrap(float& rad)
{
if (rad>0)
rad = std::fmod(rad+osg::PI, 2.0f*osg::PI)-osg::PI;
else
rad = std::fmod(rad-osg::PI, 2.0f*osg::PI)+osg::PI;
}
std::string getBestAttack (const ESM::Weapon* weapon)
{
int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2;
@ -1958,23 +1950,19 @@ void CharacterController::update(float duration, bool animationOnly)
osg::Vec3f rot = cls.getRotationVector(mPtr);
osg::Vec3f vec(movementSettings.asVec3());
vec.normalize();
float analogueMult = 1.0f;
if (isPlayer)
{
// TODO: Move this code to mwinput.
// Joystick analogue movement.
float xAxis = std::abs(movementSettings.mPosition[0]);
float yAxis = std::abs(movementSettings.mPosition[1]);
analogueMult = std::max(xAxis, yAxis);
movementSettings.mSpeedFactor = std::max(std::abs(vec.x()), std::abs(vec.y()));
// Due to the half way split between walking/running, we multiply speed by 2 while walking, unless a keyboard was used.
if(!isrunning && !sneak && !flying && analogueMult <= 0.5f)
analogueMult *= 2.f;
movementSettings.mSpeedFactor = analogueMult;
}
if(!isrunning && !sneak && !flying && movementSettings.mSpeedFactor <= 0.5f)
movementSettings.mSpeedFactor *= 2.f;
} else
movementSettings.mSpeedFactor = std::min(vec.length(), 1.f);
vec.normalize();
float effectiveRotation = rot.z();
static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game");
@ -2007,7 +1995,7 @@ void CharacterController::update(float duration, bool animationOnly)
else
mAnimation->setUpperBodyYawRadians(stats.getSideMovementAngle() / 4);
speed = cls.getSpeed(mPtr);
speed = cls.getCurrentSpeed(mPtr);
vec.x() *= speed;
vec.y() *= speed;
@ -2077,7 +2065,7 @@ void CharacterController::update(float duration, bool animationOnly)
}
}
fatigueLoss *= duration;
fatigueLoss *= analogueMult;
fatigueLoss *= movementSettings.mSpeedFactor;
DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
if (!godmode)
@ -2908,13 +2896,10 @@ void CharacterController::updateHeadTracking(float duration)
zAngleRadians = std::atan2(direction.x(), direction.y()) - std::atan2(actorDirection.x(), actorDirection.y());
xAngleRadians = -std::asin(direction.z());
wrap(zAngleRadians);
wrap(xAngleRadians);
xAngleRadians = std::min(xAngleRadians, osg::DegreesToRadians(40.f));
xAngleRadians = std::max(xAngleRadians, osg::DegreesToRadians(-40.f));
zAngleRadians = std::min(zAngleRadians, osg::DegreesToRadians(30.f));
zAngleRadians = std::max(zAngleRadians, osg::DegreesToRadians(-30.f));
const double xLimit = osg::DegreesToRadians(40.0);
const double zLimit = osg::DegreesToRadians(30.0);
zAngleRadians = osg::clampBetween(Misc::normalizeAngle(zAngleRadians), -xLimit, xLimit);
xAngleRadians = osg::clampBetween(Misc::normalizeAngle(xAngleRadians), -zLimit, zLimit);
}
float factor = duration*5;

@ -8,8 +8,14 @@ namespace MWMechanics
/// Desired movement for an actor
struct Movement
{
// Desired movement. Direction is relative to the current orientation.
// Length of the vector controls desired speed. 0 - stay, 0.5 - half-speed, 1.0 - max speed.
float mPosition[3];
// Desired rotation delta (euler angles).
float mRotation[3];
// Controlled by CharacterController, should not be changed from other places.
// These fields can not be private fields in CharacterController, because Actor::getCurrentSpeed uses it.
float mSpeedFactor;
bool mIsStrafing;

@ -122,7 +122,7 @@ namespace MWMechanics
if (mWalkState != WalkState::Evade)
{
const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getSpeed(actor) * duration;
const float distSameSpot = DIST_SAME_SPOT * actor.getClass().getCurrentSpeed(actor) * duration;
const float prevDistance = (destination - mPrev).length();
const float currentDistance = (destination - position).length();
const float movedDistance = prevDistance - currentDistance;

@ -32,7 +32,7 @@ bool smoothTurn(const MWWorld::Ptr& actor, float targetAngleRadians, int axis, f
if (absDiff < epsilonRadians)
return true;
float limit = getAngularVelocity(actor.getClass().getSpeed(actor)) * MWBase::Environment::get().getFrameDuration();
float limit = getAngularVelocity(actor.getClass().getMaxSpeed(actor)) * MWBase::Environment::get().getFrameDuration();
if (absDiff > limit)
diff = osg::sign(diff) * limit;

@ -2,6 +2,7 @@
#include <osg/Camera>
#include <components/misc/mathutil.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <components/settings/settings.hpp>
@ -200,7 +201,7 @@ namespace MWRender
updateFocalPointOffset(duration);
updatePosition();
float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr);
float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr);
speed /= (1.f + speed / 500.f);
float maxDelta = 300.f * duration;
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);
@ -249,7 +250,7 @@ namespace MWRender
{
if (!mStandingPreviewAllowed)
return;
float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr);
float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr);
bool combat = mTrackingPtr.getClass().isActor() &&
mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing;
bool standingStill = speed == 0 && !combat && !mFirstPersonView;
@ -396,12 +397,7 @@ namespace MWRender
void Camera::setYaw(float angle)
{
if (angle > osg::PI) {
angle -= osg::PI*2;
} else if (angle < -osg::PI) {
angle += osg::PI*2;
}
mYaw = angle;
mYaw = Misc::normalizeAngle(angle);
}
void Camera::setPitch(float angle)
@ -538,16 +534,8 @@ namespace MWRender
return;
}
mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mPitch;
mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mYaw;
if (mDeferredRotation.x() > osg::PI)
mDeferredRotation.x() -= 2 * osg::PI;
if (mDeferredRotation.x() < -osg::PI)
mDeferredRotation.x() += 2 * osg::PI;
if (mDeferredRotation.z() > osg::PI)
mDeferredRotation.z() -= 2 * osg::PI;
if (mDeferredRotation.z() < -osg::PI)
mDeferredRotation.z() += 2 * osg::PI;
mDeferredRotation.x() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[0] - mPitch);
mDeferredRotation.z() = Misc::normalizeAngle(-ptr.getRefData().getPosition().rot[2] - mYaw);
}
}

@ -159,7 +159,12 @@ namespace MWWorld
return "";
}
float Class::getSpeed (const Ptr& ptr) const
float Class::getMaxSpeed (const Ptr& ptr) const
{
return 0;
}
float Class::getCurrentSpeed (const Ptr& ptr) const
{
return 0;
}

@ -172,8 +172,15 @@ namespace MWWorld
///< Return name of the script attached to ptr (default implementation: return an empty
/// string).
virtual float getSpeed (const Ptr& ptr) const;
///< Return movement speed.
virtual float getWalkSpeed(const Ptr& ptr) const;
virtual float getRunSpeed(const Ptr& ptr) const;
virtual float getSwimSpeed(const Ptr& ptr) const;
/// Return maximal movement speed for the current state.
virtual float getMaxSpeed(const Ptr& ptr) const;
/// Return current movement speed.
virtual float getCurrentSpeed(const Ptr& ptr) const;
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement)
@ -182,7 +189,7 @@ namespace MWWorld
///< Return desired movement.
virtual osg::Vec3f getRotationVector (const Ptr& ptr) const;
///< Return desired rotations, as euler angles.
///< Return desired rotations, as euler angles. Sets getMovementSettings(ptr).mRotation to zero.
virtual std::pair<std::vector<int>, bool> getEquipmentSlots (const ConstPtr& ptr) const;
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
@ -364,12 +371,6 @@ namespace MWWorld
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
virtual void modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const;
virtual float getWalkSpeed(const Ptr& ptr) const;
virtual float getRunSpeed(const Ptr& ptr) const;
virtual float getSwimSpeed(const Ptr& ptr) const;
};
}

@ -0,0 +1,27 @@
#ifndef MISC_MATHUTIL_H
#define MISC_MATHUTIL_H
#include <osg/Math>
#include <osg/Vec2f>
namespace Misc
{
/// Normalizes given angle to the range [-PI, PI]. E.g. PI*3/2 -> -PI/2.
inline double normalizeAngle(double angle)
{
double fullTurns = angle / (2 * osg::PI) + 0.5;
return (fullTurns - floor(fullTurns) - 0.5) * (2 * osg::PI);
}
/// Rotates given 2d vector counterclockwise. Angle is in radians.
inline osg::Vec2f rotateVec2f(osg::Vec2f vec, float angle)
{
float s = std::sin(angle);
float c = std::cos(angle);
return osg::Vec2f(vec.x() * c + vec.y() * -s, vec.x() * s + vec.y() * c);
}
}
#endif
Loading…
Cancel
Save