mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-22 10:53:54 +00:00
Move the movement solver code to mwworld's physics system
This commit is contained in:
parent
0a4568bd11
commit
2c39760bd5
9 changed files with 184 additions and 229 deletions
|
@ -64,7 +64,7 @@ add_openmw_dir (mwclass
|
||||||
add_openmw_dir (mwmechanics
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators
|
||||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
||||||
aiescort aiactivate movementsolver
|
aiescort aiactivate
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
|
|
@ -265,6 +265,7 @@ namespace MWMechanics
|
||||||
Ogre::Vector3 movement = iter->second.update(duration);
|
Ogre::Vector3 movement = iter->second.update(duration);
|
||||||
mMovement.push_back(std::make_pair(iter->first, movement));
|
mMovement.push_back(std::make_pair(iter->first, movement));
|
||||||
}
|
}
|
||||||
|
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
|
||||||
|
|
||||||
mMovement.clear();
|
mMovement.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,6 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "movementsolver.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -79,7 +77,6 @@ static void getStateInfo(CharacterState state, std::string *group)
|
||||||
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop)
|
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop)
|
||||||
: mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false)
|
: mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false)
|
||||||
{
|
{
|
||||||
mMovementSolver = new MovementSolver();
|
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -98,7 +95,6 @@ CharacterController::CharacterController(const CharacterController &rhs)
|
||||||
, mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState)
|
, mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState)
|
||||||
, mSkipAnim(rhs.mSkipAnim)
|
, mSkipAnim(rhs.mSkipAnim)
|
||||||
{
|
{
|
||||||
mMovementSolver = new MovementSolver();
|
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
/* We've been copied. Update the animation with the new controller. */
|
/* We've been copied. Update the animation with the new controller. */
|
||||||
|
@ -107,7 +103,6 @@ CharacterController::CharacterController(const CharacterController &rhs)
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
{
|
{
|
||||||
delete mMovementSolver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -181,21 +176,14 @@ Ogre::Vector3 CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
mSkipAnim = false;
|
mSkipAnim = false;
|
||||||
|
|
||||||
if(duration > 0.0f)
|
const ESM::Position &refpos = mPtr.getRefData().getPosition();
|
||||||
{
|
// Rotates first around z, then y, then x
|
||||||
const ESM::Position &refpos = mPtr.getRefData().getPosition();
|
movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)*
|
||||||
|
Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
|
||||||
|
Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) *
|
||||||
|
movement;
|
||||||
|
|
||||||
// Rotates first around z, then y, then x
|
return movement;
|
||||||
movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)*
|
|
||||||
Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
|
|
||||||
Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) *
|
|
||||||
movement;
|
|
||||||
|
|
||||||
Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration);
|
|
||||||
MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ogre::Vector3(0.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,6 @@ namespace MWRender
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
class MovementSolver;
|
|
||||||
|
|
||||||
enum CharacterState {
|
enum CharacterState {
|
||||||
CharState_Idle,
|
CharState_Idle,
|
||||||
CharState_Idle2,
|
CharState_Idle2,
|
||||||
|
@ -51,8 +49,6 @@ class CharacterController
|
||||||
CharacterState mState;
|
CharacterState mState;
|
||||||
bool mSkipAnim;
|
bool mSkipAnim;
|
||||||
|
|
||||||
MovementSolver *mMovementSolver;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Called by the animation whenever a new text key is reached. */
|
/* Called by the animation whenever a new text key is reached. */
|
||||||
void markerEvent(float time, const std::string &evt);
|
void markerEvent(float time, const std::string &evt);
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
#include "movementsolver.hpp"
|
|
||||||
|
|
||||||
#include "libs/openengine/bullet/trace.h"
|
|
||||||
#include "libs/openengine/bullet/physic.hpp"
|
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
|
||||||
#include "../mwbase/environment.hpp"
|
|
||||||
#include "../mwbase/world.hpp"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
|
|
||||||
namespace MWMechanics
|
|
||||||
{
|
|
||||||
|
|
||||||
static const float sMaxSlope = 45.0f;
|
|
||||||
|
|
||||||
MovementSolver::MovementSolver()
|
|
||||||
: mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MovementSolver::~MovementSolver()
|
|
||||||
{
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce)
|
|
||||||
{
|
|
||||||
//Math stuff. Basically just project the velocity vector onto the plane represented by the normal.
|
|
||||||
//More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity.
|
|
||||||
float backoff;
|
|
||||||
|
|
||||||
backoff = in.dotProduct(normal);
|
|
||||||
if(backoff < 0.0f)
|
|
||||||
backoff *= overbounce;
|
|
||||||
else
|
|
||||||
backoff /= overbounce;
|
|
||||||
|
|
||||||
out = in - (normal*backoff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction)
|
|
||||||
{
|
|
||||||
Ogre::Vector3 normalizedDirection(direction);
|
|
||||||
normalizedDirection.normalise();
|
|
||||||
|
|
||||||
// no divide by normalizedDirection.length necessary because it's normalized
|
|
||||||
velocity = normalizedDirection * velocity.dotProduct(normalizedDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior)
|
|
||||||
{
|
|
||||||
traceResults trace; // no initialization needed
|
|
||||||
|
|
||||||
newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE),
|
|
||||||
position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime,
|
|
||||||
halfExtents, verticalRotation, isInterior, mEngine);
|
|
||||||
if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine);
|
|
||||||
if(getSlope(trace.planenormal) < sMaxSlope)
|
|
||||||
{
|
|
||||||
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
|
||||||
position = trace.endpos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float MovementSolver::getSlope(const Ogre::Vector3 &normal)
|
|
||||||
{
|
|
||||||
return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time)
|
|
||||||
{
|
|
||||||
Ogre::Vector3 position(ptr.getRefData().getPosition().pos);
|
|
||||||
|
|
||||||
/* Anything to collide with? */
|
|
||||||
OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle());
|
|
||||||
if(!physicActor || !physicActor->getCollisionMode())
|
|
||||||
return position + movement;
|
|
||||||
|
|
||||||
traceResults trace; //no initialization needed
|
|
||||||
int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
|
||||||
|
|
||||||
float verticalVelocity = physicActor->getVerticalForce();
|
|
||||||
Ogre::Vector3 horizontalVelocity = movement/time;
|
|
||||||
Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps
|
|
||||||
Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity);
|
|
||||||
|
|
||||||
float remainingTime = time;
|
|
||||||
bool isInterior = !ptr.getCell()->isExterior();
|
|
||||||
float verticalRotation = physicActor->getRotation().getYaw().valueDegrees();
|
|
||||||
Ogre::Vector3 halfExtents = physicActor->getHalfExtents();
|
|
||||||
|
|
||||||
Ogre::Vector3 lastNormal(0.0f);
|
|
||||||
Ogre::Vector3 currentNormal(0.0f);
|
|
||||||
Ogre::Vector3 up(0.0f, 0.0f, 1.0f);
|
|
||||||
Ogre::Vector3 newPosition = position;
|
|
||||||
|
|
||||||
newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine);
|
|
||||||
if(trace.fraction < 1.0f)
|
|
||||||
{
|
|
||||||
if(getSlope(trace.planenormal) > sMaxSlope)
|
|
||||||
{
|
|
||||||
// if we're on a really steep slope, don't listen to user input
|
|
||||||
clippedVelocity.x = clippedVelocity.y = 0.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if we're within 10 units of the ground, force velocity to track the ground
|
|
||||||
clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
// trace to where character would go if there were no obstructions
|
|
||||||
newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine);
|
|
||||||
newPosition = trace.endpos;
|
|
||||||
currentNormal = trace.planenormal;
|
|
||||||
remainingTime = remainingTime * (1.0f-trace.fraction);
|
|
||||||
|
|
||||||
// check for obstructions
|
|
||||||
if(trace.fraction != 1.0f)
|
|
||||||
{
|
|
||||||
//std::cout<<"angle: "<<getSlope(trace.planenormal)<<"\n";
|
|
||||||
if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal)
|
|
||||||
{
|
|
||||||
if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine))
|
|
||||||
std::cout<< "stepped" <<std::endl;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up);
|
|
||||||
resultantDirection.normalise();
|
|
||||||
clippedVelocity = velocity;
|
|
||||||
projectVelocity(clippedVelocity, resultantDirection);
|
|
||||||
|
|
||||||
// just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain.
|
|
||||||
clippedVelocity += currentNormal*clippedVelocity.length()/50.0f;
|
|
||||||
std::cout<< "clipped velocity: "<<clippedVelocity <<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
clipVelocity(clippedVelocity, currentNormal, clippedVelocity, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastNormal = currentNormal;
|
|
||||||
|
|
||||||
iterations++;
|
|
||||||
} while(iterations < maxIterations && remainingTime != 0.0f);
|
|
||||||
|
|
||||||
verticalVelocity = clippedVelocity.z;
|
|
||||||
verticalVelocity -= time*400;
|
|
||||||
physicActor->setVerticalForce(verticalVelocity);
|
|
||||||
|
|
||||||
return newPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
#ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H
|
|
||||||
#define GAME_MWMECHANICS_MOVEMENTSOLVER_H
|
|
||||||
|
|
||||||
#include <OgreVector3.h>
|
|
||||||
|
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class Ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace OEngine
|
|
||||||
{
|
|
||||||
namespace Physic
|
|
||||||
{
|
|
||||||
class PhysicEngine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWMechanics
|
|
||||||
{
|
|
||||||
class MovementSolver
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MovementSolver();
|
|
||||||
virtual ~MovementSolver();
|
|
||||||
|
|
||||||
Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior);
|
|
||||||
|
|
||||||
void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce);
|
|
||||||
void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction);
|
|
||||||
|
|
||||||
float getSlope(const Ogre::Vector3 &normal);
|
|
||||||
|
|
||||||
OEngine::Physic::PhysicEngine *mEngine;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */
|
|
|
@ -21,6 +21,153 @@ using namespace Ogre;
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static const float sMaxSlope = 45.0f;
|
||||||
|
|
||||||
|
class MovementSolver
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime,
|
||||||
|
float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior,
|
||||||
|
OEngine::Physic::PhysicEngine *engine)
|
||||||
|
{
|
||||||
|
traceResults trace; // no initialization needed
|
||||||
|
|
||||||
|
newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE),
|
||||||
|
position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime,
|
||||||
|
halfExtents, verticalRotation, isInterior, engine);
|
||||||
|
if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine);
|
||||||
|
if(getSlope(trace.planenormal) < sMaxSlope)
|
||||||
|
{
|
||||||
|
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
|
||||||
|
position = trace.endpos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out,
|
||||||
|
const float overbounce)
|
||||||
|
{
|
||||||
|
//Math stuff. Basically just project the velocity vector onto the plane represented by the normal.
|
||||||
|
//More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity.
|
||||||
|
float backoff;
|
||||||
|
|
||||||
|
backoff = in.dotProduct(normal);
|
||||||
|
if(backoff < 0.0f)
|
||||||
|
backoff *= overbounce;
|
||||||
|
else
|
||||||
|
backoff /= overbounce;
|
||||||
|
|
||||||
|
out = in - (normal*backoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction)
|
||||||
|
{
|
||||||
|
Ogre::Vector3 normalizedDirection(direction);
|
||||||
|
normalizedDirection.normalise();
|
||||||
|
|
||||||
|
// no divide by normalizedDirection.length necessary because it's normalized
|
||||||
|
velocity = normalizedDirection * velocity.dotProduct(normalizedDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float getSlope(const Ogre::Vector3 &normal)
|
||||||
|
{
|
||||||
|
return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time,
|
||||||
|
OEngine::Physic::PhysicEngine *engine)
|
||||||
|
{
|
||||||
|
Ogre::Vector3 position(ptr.getRefData().getPosition().pos);
|
||||||
|
|
||||||
|
/* Anything to collide with? */
|
||||||
|
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
|
||||||
|
if(!physicActor || !physicActor->getCollisionMode())
|
||||||
|
return position + movement;
|
||||||
|
|
||||||
|
traceResults trace; //no initialization needed
|
||||||
|
int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
|
||||||
|
|
||||||
|
float verticalVelocity = physicActor->getVerticalForce();
|
||||||
|
Ogre::Vector3 horizontalVelocity = movement/time;
|
||||||
|
Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps
|
||||||
|
Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity);
|
||||||
|
|
||||||
|
float remainingTime = time;
|
||||||
|
bool isInterior = !ptr.getCell()->isExterior();
|
||||||
|
float verticalRotation = physicActor->getRotation().getYaw().valueDegrees();
|
||||||
|
Ogre::Vector3 halfExtents = physicActor->getHalfExtents();
|
||||||
|
|
||||||
|
Ogre::Vector3 lastNormal(0.0f);
|
||||||
|
Ogre::Vector3 currentNormal(0.0f);
|
||||||
|
Ogre::Vector3 up(0.0f, 0.0f, 1.0f);
|
||||||
|
Ogre::Vector3 newPosition = position;
|
||||||
|
|
||||||
|
newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine);
|
||||||
|
if(trace.fraction < 1.0f)
|
||||||
|
{
|
||||||
|
if(getSlope(trace.planenormal) > sMaxSlope)
|
||||||
|
{
|
||||||
|
// if we're on a really steep slope, don't listen to user input
|
||||||
|
clippedVelocity.x = clippedVelocity.y = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we're within 10 units of the ground, force velocity to track the ground
|
||||||
|
clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// trace to where character would go if there were no obstructions
|
||||||
|
newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine);
|
||||||
|
newPosition = trace.endpos;
|
||||||
|
currentNormal = trace.planenormal;
|
||||||
|
remainingTime = remainingTime * (1.0f-trace.fraction);
|
||||||
|
|
||||||
|
// check for obstructions
|
||||||
|
if(trace.fraction != 1.0f)
|
||||||
|
{
|
||||||
|
//std::cout<<"angle: "<<getSlope(trace.planenormal)<<"\n";
|
||||||
|
if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal)
|
||||||
|
{
|
||||||
|
if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine))
|
||||||
|
std::cout<< "stepped" <<std::endl;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up);
|
||||||
|
resultantDirection.normalise();
|
||||||
|
clippedVelocity = velocity;
|
||||||
|
projectVelocity(clippedVelocity, resultantDirection);
|
||||||
|
|
||||||
|
// just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain.
|
||||||
|
clippedVelocity += currentNormal*clippedVelocity.length()/50.0f;
|
||||||
|
std::cout<< "clipped velocity: "<<clippedVelocity <<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clipVelocity(clippedVelocity, currentNormal, clippedVelocity, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastNormal = currentNormal;
|
||||||
|
|
||||||
|
iterations++;
|
||||||
|
} while(iterations < maxIterations && remainingTime != 0.0f);
|
||||||
|
|
||||||
|
verticalVelocity = clippedVelocity.z;
|
||||||
|
verticalVelocity -= time*400;
|
||||||
|
physicActor->setVerticalForce(verticalVelocity);
|
||||||
|
|
||||||
|
return newPosition;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
|
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
|
||||||
mRender(_rend), mEngine(0), mFreeFly (true)
|
mRender(_rend), mEngine(0), mFreeFly (true)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +332,11 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time)
|
||||||
|
{
|
||||||
|
return MovementSolver::move(ptr, movement, time, mEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PhysicsSystem::addHeightField (float* heights,
|
void PhysicsSystem::addHeightField (float* heights,
|
||||||
int x, int y, float yoffset,
|
int x, int y, float yoffset,
|
||||||
|
|
|
@ -35,6 +35,8 @@ namespace MWWorld
|
||||||
|
|
||||||
bool toggleCollisionMode();
|
bool toggleCollisionMode();
|
||||||
|
|
||||||
|
Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time);
|
||||||
|
|
||||||
std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance);
|
std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance);
|
||||||
std::vector < std::pair <float, std::string> > getFacedHandles (float queryDistance);
|
std::vector < std::pair <float, std::string> > getFacedHandles (float queryDistance);
|
||||||
std::vector < std::pair <float, std::string> > getFacedHandles (float mouseX, float mouseY, float queryDistance);
|
std::vector < std::pair <float, std::string> > getFacedHandles (float mouseX, float mouseY, float queryDistance);
|
||||||
|
|
|
@ -836,6 +836,27 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::doPhysics(const PtrMovementList &actors, float duration)
|
void World::doPhysics(const PtrMovementList &actors, float duration)
|
||||||
{
|
{
|
||||||
|
/* No duration? Shouldn't be any movement, then. */
|
||||||
|
if(duration <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PtrMovementList::const_iterator player(actors.end());
|
||||||
|
for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++)
|
||||||
|
{
|
||||||
|
if(iter->first.getRefData().getHandle() == "player")
|
||||||
|
{
|
||||||
|
/* Handle player last, in case a cell transition occurs */
|
||||||
|
player = iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration);
|
||||||
|
moveObjectImp(iter->first, vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
if(player != actors.end())
|
||||||
|
{
|
||||||
|
Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration);
|
||||||
|
moveObjectImp(player->first, vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::toggleCollisionMode()
|
bool World::toggleCollisionMode()
|
||||||
|
|
Loading…
Reference in a new issue