mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 20:15:33 +00:00
Keep track of whether an animation supplies movement
Also handle it when it doesn't.
This commit is contained in:
parent
0817d59f23
commit
24f1eba902
5 changed files with 37 additions and 16 deletions
|
@ -103,7 +103,7 @@ 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), mMovingAnim(false)
|
||||||
{
|
{
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
|
@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
mAnimation->setAccumulation(Ogre::Vector3(0.0f));
|
mAnimation->setAccumulation(Ogre::Vector3(0.0f));
|
||||||
}
|
}
|
||||||
if(mAnimation->hasAnimation(mCurrentGroup))
|
if(mAnimation->hasAnimation(mCurrentGroup))
|
||||||
mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
|
mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
|
@ -180,6 +180,9 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
||||||
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
|
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
|
||||||
|
|
||||||
|
// If this animation isn't moving us sideways, do it manually
|
||||||
|
if(!mMovingAnim)
|
||||||
|
movement.mPosition[0] += vec.x * (speed*duration);
|
||||||
// Apply any forward/backward movement manually
|
// Apply any forward/backward movement manually
|
||||||
movement.mPosition[1] += vec.y * (speed*duration);
|
movement.mPosition[1] += vec.y * (speed*duration);
|
||||||
}
|
}
|
||||||
|
@ -194,6 +197,9 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
|
|
||||||
// Apply any sideways movement manually
|
// Apply any sideways movement manually
|
||||||
movement.mPosition[0] += vec.x * (speed*duration);
|
movement.mPosition[0] += vec.x * (speed*duration);
|
||||||
|
// If this animation isn't moving us forward/backward, do it manually
|
||||||
|
if(!mMovingAnim)
|
||||||
|
movement.mPosition[1] += vec.y * (speed*duration);
|
||||||
}
|
}
|
||||||
else if(rot.z != 0.0f && !inwater && !sneak)
|
else if(rot.z != 0.0f && !inwater && !sneak)
|
||||||
{
|
{
|
||||||
|
@ -211,7 +217,7 @@ void CharacterController::update(float duration, Movement &movement)
|
||||||
mCurrentGroup = mAnimQueue.front().first;
|
mCurrentGroup = mAnimQueue.front().first;
|
||||||
size_t count = mAnimQueue.front().second;
|
size_t count = mAnimQueue.front().second;
|
||||||
mAnimQueue.pop_front();
|
mAnimQueue.pop_front();
|
||||||
mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count);
|
mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +250,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
|
||||||
mAnimQueue.clear();
|
mAnimQueue.clear();
|
||||||
mCurrentGroup = groupname;
|
mCurrentGroup = groupname;
|
||||||
mState = CharState_SpecialIdle;
|
mState = CharState_SpecialIdle;
|
||||||
mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
mMovingAnim = mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else if(mode == 0)
|
||||||
{
|
{
|
||||||
|
@ -272,10 +278,10 @@ void CharacterController::setState(CharacterState state, bool loop)
|
||||||
|
|
||||||
std::string anim;
|
std::string anim;
|
||||||
getStateInfo(mState, &anim);
|
getStateInfo(mState, &anim);
|
||||||
if(mAnimation->hasAnimation(anim))
|
if((mMovingAnim=mAnimation->hasAnimation(anim)) != false)
|
||||||
{
|
{
|
||||||
mCurrentGroup = anim;
|
mCurrentGroup = anim;
|
||||||
mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0);
|
mMovingAnim = mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,8 @@ class CharacterController
|
||||||
CharacterState mState;
|
CharacterState mState;
|
||||||
bool mSkipAnim;
|
bool mSkipAnim;
|
||||||
|
|
||||||
|
bool mMovingAnim;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
|
@ -317,7 +317,7 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue<Ogre::Real> *nonaccumctrl, const std::string &groupname)
|
float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue<Ogre::Real> *nonaccumctrl, const Ogre::Vector3 &accum, const std::string &groupname)
|
||||||
{
|
{
|
||||||
const std::string start = groupname+": start";
|
const std::string start = groupname+": start";
|
||||||
const std::string loopstart = groupname+": loop start";
|
const std::string loopstart = groupname+": loop start";
|
||||||
|
@ -340,8 +340,8 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node
|
||||||
|
|
||||||
if(stoptime > starttime)
|
if(stoptime > starttime)
|
||||||
{
|
{
|
||||||
Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime);
|
Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum;
|
||||||
Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime);
|
Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum;
|
||||||
|
|
||||||
return startpos.distance(endpos) / (stoptime-starttime);
|
return startpos.distance(endpos) / (stoptime-starttime);
|
||||||
}
|
}
|
||||||
|
@ -515,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops)
|
bool Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops)
|
||||||
{
|
{
|
||||||
// TODO: parameterize this
|
// TODO: parameterize this
|
||||||
size_t layeridx = 0;
|
size_t layeridx = 0;
|
||||||
|
@ -523,6 +523,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con
|
||||||
for(std::vector<ObjectInfo>::iterator iter(mObjects.begin());iter != mObjects.end();iter++)
|
for(std::vector<ObjectInfo>::iterator iter(mObjects.begin());iter != mObjects.end();iter++)
|
||||||
iter->mActiveLayers &= ~(1<<layeridx);
|
iter->mActiveLayers &= ~(1<<layeridx);
|
||||||
|
|
||||||
|
bool movinganim = false;
|
||||||
bool foundanim = false;
|
bool foundanim = false;
|
||||||
if(groupname.empty())
|
if(groupname.empty())
|
||||||
{
|
{
|
||||||
|
@ -578,18 +579,27 @@ void Animation::play(const std::string &groupname, const std::string &start, con
|
||||||
|
|
||||||
iter->mActiveLayers |= (1<<layeridx);
|
iter->mActiveLayers |= (1<<layeridx);
|
||||||
foundanim = true;
|
foundanim = true;
|
||||||
|
|
||||||
|
if(mAccumulate == Ogre::Vector3(0.0f))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!nonaccumctrl)
|
if(!nonaccumctrl)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname);
|
mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, mAccumulate, groupname);
|
||||||
if(mAnimVelocity > 0.0f) break;
|
if(mAnimVelocity > 1.0f)
|
||||||
|
{
|
||||||
|
movinganim = (nonaccumctrl==mNonAccumCtrl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(!foundanim)
|
if(!foundanim)
|
||||||
std::cerr<< "Failed to find animation "<<groupname <<std::endl;
|
std::cerr<< "Failed to find animation "<<groupname <<std::endl;
|
||||||
|
|
||||||
updateActiveControllers();
|
updateActiveControllers();
|
||||||
|
|
||||||
|
return movinganim;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ogre::Vector3 Animation::runAnimation(float duration)
|
Ogre::Vector3 Animation::runAnimation(float duration)
|
||||||
|
|
|
@ -78,6 +78,7 @@ protected:
|
||||||
|
|
||||||
static float calcAnimVelocity(const NifOgre::TextKeyMap &keys,
|
static float calcAnimVelocity(const NifOgre::TextKeyMap &keys,
|
||||||
NifOgre::NodeTargetValue<Ogre::Real> *nonaccumctrl,
|
NifOgre::NodeTargetValue<Ogre::Real> *nonaccumctrl,
|
||||||
|
const Ogre::Vector3 &accum,
|
||||||
const std::string &groupname);
|
const std::string &groupname);
|
||||||
|
|
||||||
/* Updates a skeleton instance so that all bones matching the source skeleton (based on
|
/* Updates a skeleton instance so that all bones matching the source skeleton (based on
|
||||||
|
@ -135,8 +136,10 @@ public:
|
||||||
* \param loops How many times to loop the animation. This will use the
|
* \param loops How many times to loop the animation. This will use the
|
||||||
* "loop start" and "loop stop" markers if they exist,
|
* "loop start" and "loop stop" markers if they exist,
|
||||||
* otherwise it will use "start" and "stop".
|
* otherwise it will use "start" and "stop".
|
||||||
|
* \return Boolean specifying whether the animation will return movement
|
||||||
|
* for the character at all.
|
||||||
*/
|
*/
|
||||||
void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops);
|
bool play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops);
|
||||||
|
|
||||||
virtual Ogre::Vector3 runAnimation(float timepassed);
|
virtual Ogre::Vector3 runAnimation(float timepassed);
|
||||||
|
|
||||||
|
|
|
@ -97,10 +97,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
|
||||||
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif");
|
||||||
|
|
||||||
addObjectList(node, smodel, true);
|
addObjectList(node, smodel, true);
|
||||||
if(!mNpc->isMale() && !isBeast)
|
if(mBodyPrefix.find("argonian") != std::string::npos)
|
||||||
addObjectList(node, "meshes\\base_anim_female.nif", true);
|
|
||||||
else if(mBodyPrefix.find("argonian") != std::string::npos)
|
|
||||||
addObjectList(node, "meshes\\argonian_swimkna.nif", true);
|
addObjectList(node, "meshes\\argonian_swimkna.nif", true);
|
||||||
|
else if(!mNpc->isMale() && !isBeast)
|
||||||
|
addObjectList(node, "meshes\\base_anim_female.nif", true);
|
||||||
if(mNpc->mModel.length() > 0)
|
if(mNpc->mModel.length() > 0)
|
||||||
addObjectList(node, "meshes\\"+mNpc->mModel, true);
|
addObjectList(node, "meshes\\"+mNpc->mModel, true);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue