pMove in a seperate loop with fixed timestep to prevent frame-dependent movement

actorid
scrawl 13 years ago
parent 4655ec94f0
commit 86b6184f43

@ -21,27 +21,24 @@ namespace MWWorld
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0), mFreeFly (true) mRender(_rend), mEngine(0), mFreeFly (true)
{ {
playerphysics = new playerMove; playerphysics = new playerMove;
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
playerphysics->mEngine = mEngine; playerphysics->mEngine = mEngine;
} }
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
{ {
delete mEngine; delete mEngine;
} }
OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine()
{ {
return mEngine; return mEngine;
} }
std::pair<std::string, float> PhysicsSystem::getFacedHandle (MWWorld::World& world) std::pair<std::string, float> PhysicsSystem::getFacedHandle (MWWorld::World& world)
{ {
std::string handle = ""; std::string handle = "";
@ -74,7 +71,7 @@ namespace MWWorld
if(hasWater){ if(hasWater){
playerphysics->waterHeight = waterHeight; playerphysics->waterHeight = waterHeight;
} }
} }
btVector3 PhysicsSystem::getRayPoint(float extent) btVector3 PhysicsSystem::getRayPoint(float extent)
@ -86,26 +83,23 @@ namespace MWWorld
btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y);
return result; return result;
} }
bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to) bool PhysicsSystem::castRay(const Vector3& from, const Vector3& to)
{ {
btVector3 _from, _to; btVector3 _from, _to;
_from = btVector3(from.x, from.y, from.z); _from = btVector3(from.x, from.y, from.z);
_to = btVector3(to.x, to.y, to.z); _to = btVector3(to.x, to.y, to.z);
std::pair<std::string, float> result = mEngine->rayTest(_from, _to); std::pair<std::string, float> result = mEngine->rayTest(_from, _to);
return !(result.first == ""); return !(result.first == "");
} }
void PhysicsSystem::doPhysics(float dt, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysics (float duration,
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
{ {
//set the DebugRenderingMode. To disable it,set it to 0 //set the DebugRenderingMode. To disable it,set it to 0
//eng->setDebugRenderingMode(1); //eng->setDebugRenderingMode(1);
//set the walkdirection to 0 (no movement) for every actor) //set the walkdirection to 0 (no movement) for every actor)
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
@ -117,8 +111,7 @@ namespace MWWorld
pm_ref.rightmove = 0; pm_ref.rightmove = 0;
pm_ref.forwardmove = 0; pm_ref.forwardmove = 0;
pm_ref.upmove = 0; pm_ref.upmove = 0;
//playerphysics->ps.move_type = PM_NOCLIP; //playerphysics->ps.move_type = PM_NOCLIP;
for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin()); for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin());
iter!=actors.end(); ++iter) iter!=actors.end(); ++iter)
@ -133,29 +126,24 @@ namespace MWWorld
Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); Ogre::Node* yawNode = sceneNode->getChildIterator().getNext();
Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); Ogre::Node* pitchNode = yawNode->getChildIterator().getNext();
Ogre::Quaternion yawQuat = yawNode->getOrientation(); Ogre::Quaternion yawQuat = yawNode->getOrientation();
Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); Ogre::Quaternion pitchQuat = pitchNode->getOrientation();
// unused
//Ogre::Quaternion both = yawQuat * pitchQuat;
// unused playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
//Ogre::Quaternion both = yawQuat * pitchQuat; playerphysics->ps.viewangles.z = 0;
playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
playerphysics->ps.viewangles.z = 0;
playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90; playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90;
if(mFreeFly) if(mFreeFly)
{ {
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x; pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z; pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y; pm_ref.upmove = dir1.y;
//std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n";
//playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees();
//std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n";
@ -163,46 +151,50 @@ namespace MWWorld
} }
else else
{ {
Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Quaternion quat = yawNode->getOrientation();
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
pm_ref.rightmove = -dir1.x; pm_ref.rightmove = -dir1.x;
pm_ref.forwardmove = dir1.z; pm_ref.forwardmove = dir1.z;
pm_ref.upmove = dir1.y; pm_ref.upmove = dir1.y;
dir = 0.025*(quat*dir1); dir = 0.025*(quat*dir1);
} }
//set the walk direction //set the walk direction
act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y));
} }
mEngine->stepSimulation(duration); mEngine->stepSimulation(dt);
Pmove(playerphysics); }
std::vector< std::pair<std::string, Ogre::Vector3> > PhysicsSystem::doPhysicsFixed (
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors)
{
Pmove(playerphysics);
std::vector< std::pair<std::string, Ogre::Vector3> > response; std::vector< std::pair<std::string, Ogre::Vector3> > response;
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
btVector3 newPos = it->second->getPosition(); btVector3 newPos = it->second->getPosition();
Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z());
if(it->first == "player"){ if(it->first == "player"){
coord = playerphysics->ps.origin; coord = playerphysics->ps.origin;
//std::cout << "ZCoord: " << coord.z << "\n"; //std::cout << "ZCoord: " << coord.z << "\n";
//std::cout << "Coord" << coord << "\n"; //std::cout << "Coord" << coord << "\n";
//coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y
} }
response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord)); response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord));
} }
return response; return response;
} }
@ -260,7 +252,14 @@ namespace MWWorld
{ {
// TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow
// start positions others than 0, 0, 0 // start positions others than 0, 0, 0
act->setPosition(btVector3(position.x,position.y,position.z)); if (handle == "player")
{
playerphysics->ps.origin = position;
}
else
{
act->setPosition(btVector3(position.x,position.y,position.z));
}
} }
} }
@ -316,7 +315,7 @@ namespace MWWorld
} }
void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
// unused // unused

@ -16,8 +16,11 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend); PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem (); ~PhysicsSystem ();
std::vector< std::pair<std::string, Ogre::Vector3> > doPhysics (float duration, void doPhysics(float duration, const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
const std::vector<std::pair<std::string, Ogre::Vector3> >& actors); ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
std::vector< std::pair<std::string, Ogre::Vector3> > doPhysicsFixed (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors);
///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed
void addObject (const std::string& handle, const std::string& mesh, void addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position); const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position);
@ -55,7 +58,7 @@ namespace MWWorld
void insertActorPhysics(const MWWorld::Ptr&, std::string model); void insertActorPhysics(const MWWorld::Ptr&, std::string model);
OEngine::Physic::PhysicEngine* getEngine(); OEngine::Physic::PhysicEngine* getEngine();
void setCurrentWater(bool hasWater, int waterHeight); void setCurrentWater(bool hasWater, int waterHeight);
private: private:
@ -64,7 +67,6 @@ namespace MWWorld
bool mFreeFly; bool mFreeFly;
playerMove* playerphysics; playerMove* playerphysics;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&);
}; };

@ -215,6 +215,7 @@ namespace MWWorld
setFallbackValues(fallbackMap); setFallbackValues(fallbackMap);
lastTick = mTimer.getMilliseconds();
} }
@ -559,8 +560,9 @@ namespace MWWorld
} }
} }
void World::moveObjectImp (Ptr ptr, float x, float y, float z) bool World::moveObjectImp (Ptr ptr, float x, float y, float z)
{ {
bool ret = false;
ptr.getRefData().getPosition().pos[0] = x; ptr.getRefData().getPosition().pos[0] = x;
ptr.getRefData().getPosition().pos[1] = y; ptr.getRefData().getPosition().pos[1] = y;
ptr.getRefData().getPosition().pos[2] = z; ptr.getRefData().getPosition().pos[2] = z;
@ -582,6 +584,7 @@ namespace MWWorld
if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY) if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY)
{ {
mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false); mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false);
ret = true;
} }
} }
@ -591,6 +594,8 @@ namespace MWWorld
/// \todo cell change for non-player ref /// \todo cell change for non-player ref
mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z)); mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z));
return ret;
} }
void World::moveObject (Ptr ptr, float x, float y, float z) void World::moveObject (Ptr ptr, float x, float y, float z)
@ -632,29 +637,45 @@ namespace MWWorld
void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors, void World::doPhysics (const std::vector<std::pair<std::string, Ogre::Vector3> >& actors,
float duration) float duration)
{ {
std::vector< std::pair<std::string, Ogre::Vector3> > vectors = mPhysics->doPhysics (duration, actors); mPhysics->doPhysics(duration, actors);
std::vector< std::pair<std::string, Ogre::Vector3> >::iterator player = vectors.end(); const int tick = 16; // 16 ms ^= 60 Hz
for (std::vector< std::pair<std::string, Ogre::Vector3> >::iterator it = vectors.begin(); // Game clock part of the loop, contains everything that has to be executed in a fixed timestep
it!= vectors.end(); ++it) long long dt = mTimer.getMilliseconds() - lastTick;
if (dt >= 100) dt = 100; // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps
while (dt >= tick)
{ {
if (it->first=="player") dt -= tick;
lastTick += tick;
std::vector< std::pair<std::string, Ogre::Vector3> > vectors = mPhysics->doPhysicsFixed (actors);
std::vector< std::pair<std::string, Ogre::Vector3> >::iterator player = vectors.end();
for (std::vector< std::pair<std::string, Ogre::Vector3> >::iterator it = vectors.begin();
it!= vectors.end(); ++it)
{ {
player = it; if (it->first=="player")
{
player = it;
}
else
{
MWWorld::Ptr ptr = getPtrViaHandle (it->first);
moveObjectImp (ptr, it->second.x, it->second.y, it->second.z);
}
} }
else
// Make sure player is moved last (otherwise the cell might change in the middle of an update
// loop)
if (player!=vectors.end())
{ {
MWWorld::Ptr ptr = getPtrViaHandle (it->first); if (moveObjectImp (getPtrViaHandle (player->first),
moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); player->second.x, player->second.y, player->second.z) == true)
return; // abort the current loop if the cell has changed
} }
} }
// Make sure player is moved last (otherwise the cell might change in the middle of an update
// loop)
if (player!=vectors.end())
moveObjectImp (getPtrViaHandle (player->first),
player->second.x, player->second.y, player->second.z);
} }
bool World::toggleCollisionMode() bool World::toggleCollisionMode()

@ -22,6 +22,8 @@
#include <openengine/bullet/physic.hpp> #include <openengine/bullet/physic.hpp>
#include <openengine/ogre/fader.hpp> #include <openengine/ogre/fader.hpp>
#include <OgreTimer.h>
namespace Ogre namespace Ogre
{ {
class Vector3; class Vector3;
@ -100,9 +102,13 @@ namespace MWWorld
int mNumFacing; int mNumFacing;
std::map<std::string,std::string> mFallback; std::map<std::string,std::string> mFallback;
unsigned long lastTick;
Ogre::Timer mTimer;
int getDaysPerMonth (int month) const; int getDaysPerMonth (int month) const;
void moveObjectImp (Ptr ptr, float x, float y, float z); bool moveObjectImp (Ptr ptr, float x, float y, float z);
///< @return true if the active cell (cell player is in) changed
public: public:

@ -393,7 +393,7 @@ namespace Physic
void PhysicEngine::stepSimulation(double deltaT) void PhysicEngine::stepSimulation(double deltaT)
{ {
dynamicsWorld->stepSimulation(deltaT,10); dynamicsWorld->stepSimulation(deltaT,10, 1/60.0);
if(isDebugCreated) if(isDebugCreated)
{ {
mDebugDrawer->step(); mDebugDrawer->step();

Loading…
Cancel
Save