Apply movement by queueing it to do later

This commit is contained in:
Chris Robinson 2013-08-17 22:34:38 -07:00
parent 96bab88da6
commit 9d56e2d86d
9 changed files with 52 additions and 68 deletions

View file

@ -250,8 +250,9 @@ namespace MWBase
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0;
///< Convert position to cell numbers ///< Convert position to cell numbers
virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0; virtual void queueMovement(const MWWorld::Ptr &ptr, const Ogre::Vector3 &velocity) = 0;
///< Run physics simulation and modify \a world accordingly. ///< Queues movement for \a ptr (in local space), to be applied in the next call to
/// doPhysics.
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0;
///< cast a Ray and return true if there is an object in the ray path. ///< cast a Ray and return true if there is an object in the ray path.

View file

@ -300,17 +300,8 @@ namespace MWMechanics
if(!paused) if(!paused)
{ {
mMovement.reserve(mActors.size());
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{ iter->second->update(duration);
Movement movement;
iter->second->update(duration, movement);
mMovement.push_back(std::make_pair(iter->first, movement));
}
MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration);
mMovement.clear();
} }
} }

View file

@ -28,8 +28,6 @@ namespace MWMechanics
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap; typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap mActors; PtrControllerMap mActors;
MWWorld::PtrMovementList mMovement;
std::map<std::string, int> mDeathCount; std::map<std::string, int> mDeathCount;
float mDuration; float mDuration;

View file

@ -663,9 +663,11 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
return forcestateupdate; return forcestateupdate;
} }
void CharacterController::update(float duration, Movement &movement) void CharacterController::update(float duration)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
Ogre::Vector3 movement(0.0f);
if(!cls.isActor()) if(!cls.isActor())
{ {
@ -684,8 +686,6 @@ void CharacterController::update(float duration, Movement &movement)
} }
else if(!cls.getCreatureStats(mPtr).isDead()) else if(!cls.getCreatureStats(mPtr).isDead())
{ {
MWBase::World *world = MWBase::Environment::get().getWorld();
bool onground = world->isOnGround(mPtr); bool onground = world->isOnGround(mPtr);
bool inwater = world->isSwimming(mPtr); bool inwater = world->isSwimming(mPtr);
bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run);
@ -796,45 +796,41 @@ void CharacterController::update(float duration, Movement &movement)
} }
} }
vec *= duration;
movement.mPosition[0] += vec.x;
movement.mPosition[1] += vec.y;
movement.mPosition[2] += vec.z;
rot *= duration;
movement.mRotation[0] += rot.x;
movement.mRotation[1] += rot.y;
movement.mRotation[2] += rot.z;
if(cls.isNpc()) if(cls.isNpc())
forcestateupdate = updateNpcState(onground, inwater, isrunning, sneak); forcestateupdate = updateNpcState(onground, inwater, isrunning, sneak);
refreshCurrentAnims(idlestate, movestate, forcestateupdate); refreshCurrentAnims(idlestate, movestate, forcestateupdate);
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
world->queueMovement(mPtr, vec);
movement = vec;
} }
else if(cls.getCreatureStats(mPtr).isDead()) else if(cls.getCreatureStats(mPtr).isDead())
{ {
MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false); MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false);
world->queueMovement(mPtr, Ogre::Vector3(0.0f));
} }
if(mAnimation && !mSkipAnim) if(mAnimation && !mSkipAnim)
{ {
Ogre::Vector3 moved = mAnimation->runAnimation(duration); Ogre::Vector3 moved = mAnimation->runAnimation(duration) / duration;
// Ensure we're moving in generally the right direction // Ensure we're moving in generally the right direction
if(mMovementSpeed > 0.f) if(mMovementSpeed > 0.f)
{ {
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || if((movement.x < 0.0f && movement.x < moved.x*2.0f) ||
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) (movement.x > 0.0f && movement.x > moved.x*2.0f))
moved.x = movement.mPosition[0]; moved.x = movement.x;
if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) || if((movement.y < 0.0f && movement.y < moved.y*2.0f) ||
(movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f)) (movement.y > 0.0f && movement.y > moved.y*2.0f))
moved.y = movement.mPosition[1]; moved.y = movement.y;
if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) || if((movement.z < 0.0f && movement.z < moved.z*2.0f) ||
(movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f)) (movement.z > 0.0f && movement.z > moved.z*2.0f))
moved.z = movement.mPosition[2]; moved.z = movement.z;
} }
if(moved.squaredLength() > 1.0f)
movement.mPosition[0] = moved.x; world->queueMovement(mPtr, moved);
movement.mPosition[1] = moved.y;
movement.mPosition[2] = moved.z;
} }
mSkipAnim = false; mSkipAnim = false;
} }

View file

@ -164,7 +164,7 @@ public:
void updatePtr(const MWWorld::Ptr &ptr); void updatePtr(const MWWorld::Ptr &ptr);
void update(float duration, Movement &movement); void update(float duration);
void playGroup(const std::string &groupname, int mode, int count); void playGroup(const std::string &groupname, int mode, int count);
void skipAnim(); void skipAnim();

View file

@ -65,10 +65,7 @@ void Objects::update(float duration, bool paused)
if(!paused) if(!paused)
{ {
for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter)
{ iter->second->update(duration);
Movement movement;
iter->second->update(duration, movement);
}
} }
} }

View file

@ -124,7 +124,7 @@ namespace MWWorld
return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
movement; movement * time;
} }
btCollisionObject *colobj = physicActor->getCollisionBody(); btCollisionObject *colobj = physicActor->getCollisionBody();
@ -140,7 +140,7 @@ namespace MWWorld
velocity = (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* velocity = (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
movement / time; movement;
} }
else else
{ {
@ -150,7 +150,7 @@ namespace MWWorld
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope) if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
onground = true; onground = true;
} }
velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * movement;
velocity.z += physicActor->getVerticalForce(); velocity.z += physicActor->getVerticalForce();
} }

View file

@ -1083,7 +1083,12 @@ namespace MWWorld
--cellY; --cellY;
} }
void World::doPhysics(const PtrMovementList &actors, float duration) void World::queueMovement(const Ptr &ptr, const Vector3 &velocity)
{
mPhysics->queueObjectMovement(ptr, velocity);
}
void World::doPhysics(float duration)
{ {
/* No duration? Shouldn't be any movement, then. */ /* No duration? Shouldn't be any movement, then. */
if(duration <= 0.0f) if(duration <= 0.0f)
@ -1091,8 +1096,9 @@ namespace MWWorld
processDoors(duration); processDoors(duration);
PtrMovementList::const_iterator player(actors.end()); const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) PtrVelocityList::const_iterator player(results.end());
for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();iter++)
{ {
if(iter->first.getRefData().getHandle() == "player") if(iter->first.getRefData().getHandle() == "player")
{ {
@ -1100,23 +1106,12 @@ namespace MWWorld
player = iter; player = iter;
continue; continue;
} }
moveObjectImp(iter->first, iter->second.x, iter->second.y, iter->second.z);
rotateObjectImp(iter->first, Ogre::Vector3(iter->second.mRotation), true);
Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration,
!isSwimming(iter->first) && !isFlying(iter->first));
moveObjectImp(iter->first, vec.x, vec.y, vec.z);
} }
if(player != actors.end()) if(player != results.end())
{ moveObjectImp(player->first, player->second.x, player->second.y, player->second.z);
rotateObjectImp(player->first, Ogre::Vector3(player->second.mRotation), true);
Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration, mPhysEngine->stepSimulation(duration);
!isSwimming(player->first) && !isFlying(player->first));
moveObjectImp(player->first, vec.x, vec.y, vec.z);
}
mPhysEngine->stepSimulation (duration);
} }
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2) bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2)
@ -1261,6 +1256,8 @@ namespace MWWorld
mWorldScene->update (duration, paused); mWorldScene->update (duration, paused);
doPhysics (duration);
performUpdateSceneQueries (); performUpdateSceneQueries ();
updateWindowManager (); updateWindowManager ();

View file

@ -106,6 +106,9 @@ namespace MWWorld
void processDoors(float duration); void processDoors(float duration);
///< Run physics simulation and modify \a world accordingly. ///< Run physics simulation and modify \a world accordingly.
void doPhysics(float duration);
///< Run physics simulation and modify \a world accordingly.
void ensureNeededRecords(); void ensureNeededRecords();
int mPlayIntro; int mPlayIntro;
@ -276,8 +279,9 @@ namespace MWWorld
virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const;
///< Convert position to cell numbers ///< Convert position to cell numbers
virtual void doPhysics(const PtrMovementList &actors, float duration); virtual void queueMovement(const Ptr &ptr, const Ogre::Vector3 &velocity);
///< Run physics simulation and modify \a world accordingly. ///< Queues movement for \a ptr (in local space), to be applied in the next call to
/// doPhysics.
virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2); virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2);
///< cast a Ray and return true if there is an object in the ray path. ///< cast a Ray and return true if there is an object in the ray path.