Moving without foot sliding
When your NPC moves it may move at different speeds, especially if you are using some sort of steering. This presents the problem of what speed should you play your walk/run animations. My solution is to analyse the animation and see how far the foot travels from start frame to end frame and when animating play the correct amount of frame(s) for the distance.
Here’s the code:-
#include "anim.h" void animItem::calcAnimDist( TEntity e, TEntity bone ) { TVec3 startPos; TVec3 newPos; TVec3 prevPos; TVec3 rot; float totalZ = 0; float totalX= 0; if (!bone) return; rot = EntityRotation(e,1); RotateEntity(e,Vec3(0),1); startPos = EntityPosition(bone,1); for(int i=startFrame; i<endFrame; i++) { prevPos = EntityPosition(bone,1); Animate( e, i ); newPos = EntityPosition(bone,1); totalZ += abs(newPos.Z - prevPos.Z); totalX += abs(newPos.X - prevPos.X); } RotateEntity(e,rot,1); distanceZ = totalZ*2; distanceX = totalX*2; perFrameZ = totalZ / frameCount; perFrameX = totalX / frameCount; maxSpeed = perFrameZ / 1.8; minSpeed = perFrameZ / 3.6; }
Here’s it’s header file, it has loads more stuff in that I will touch on in later blog entries.
#ifndef ANIM_H #define ANIM_H #include <string> #include <map> #include <vector> #include <algorithm> #include "engine.h" #include "actor/include/animbody.h" using namespace std; typedef enum animDirection { ANIM_OTHER }; class keyFrame { int parentFrame; int childFrame; }; typedef enum animType { ANIM_NONE = 0, ANIM_IDLE = 1, ANIM_WALK = 2, ANIM_RUN = 4, ANIM_CROUCH = 8, ANIM_TURN = 16, ANIM_STRAFE = 32, ANIM_RIFLE = 64, ANIM_PISTOL = 128, ANIM_DEATH = 256, ANIM_FORWARD = 512, ANIM_BACKWARD = 1024, ANIM_PAIN = 2048, ANIM_LEFT = 4096, ANIM_RIGHT = 8192, ANIM_JUMP = 16384 }; typedef enum animStatus { ANIM_DEFAULT, ANIM_STARTING, ANIM_PLAYING, ANIM_STOPPING, ANIM_STOPPED }; class animItem { protected: float distanceZ; float distanceX; float rotationAngle; map<std::string,keyFrame> keyFrames; public: animType animType; std::string name; int sequence; int startFrame; int endFrame; int frameCount; float perFrameX; float perFrameZ; bool speedDepdent; float maxSpeed; float minSpeed; animDirection direction; animStatus m_status; animItem() {}; animItem( string pName, int pStart, int pEnd, animDirection pDirection = ANIM_OTHER ); ~animItem() {}; inline int getFrameCount() { return frameCount; } //void calcAnimDist( TEntity e, string boneName ); void calcAnimDist( TEntity e, TEntity bone ); }; typedef enum animPlayType { PLAY_REPEAT, PLAY_ONCE, PLAY_ONCE_RESET }; class playingAnim { protected: public: animItem* myAnimItem; float currentFrame; // Zero based float speed; animStatus status; animPlayType animType; TEntity entity; float transitionTime; float startTime; float stopTime; int blendTime; playingAnim() {}; playingAnim( animItem* pAnim, float pTransitionTime = 0, float pSpeed = 0, animPlayType pAnimType = PLAY_REPEAT): currentFrame(0), blendTime(0), stopTime(0), startTime(0) { myAnimItem = pAnim; speed = pSpeed; animType = pAnimType; transitionTime = pTransitionTime; status = ANIM_STARTING; } inline void setStartTime( float pTime ) { startTime = pTime; } inline void setStopTime( float pTime ) { stopTime = pTime; } inline void setEntity( TEntity ent ) { entity = ent; } inline void setCurrentFrame( float pFrame ) { currentFrame = pFrame; } inline float getStopTime() { return stopTime; } inline float getStartTime() { return startTime; } inline float getTransitionTime() { return transitionTime; } inline animStatus getStatus() { return status; } inline animPlayType getAnimType() { return animType; } }; class entityAnimation { protected: map<string,animItem*> items; map<string,playingAnim*> animQueue; playingAnim* activeItem; TEntity entity; public: entityAnimation( TEntity pEnt ); //~entityAnimation(); animItem* addItem( string pName, int pStart, int pEnd ); playingAnim* start( string pName, float pTranTime = 0, float animSpeed = 1, animPlayType pAnimType = PLAY_REPEAT, string entityName = ""); void stop( playingAnim* anim, float transition); void stopAll( float time); void update( float dist = 0); bool isPlayingAnimName( string pName ); bool animationActive( string pName); bool animationStopped( string pName ); inline float startBlend( playingAnim* play ); inline float stopBlend( playingAnim* play ); }; class locomotion: public entityAnimation { public: animType currentAnimType; bool crouching; bool holdingPistol; bool holdingRifle; bool movingForward; bodyParts* m_bodyParts; bodyControl* m_bodyControl; float swapTime; void update( float dist = 0); animItem* locomotion::findItemForSpeed( float dist ); animItem* locomotion::findItemForType( animType pAnimType ); bool readAnimFile( string pFile ); void setCrouching( bool pCrouch = true ); void setHoldingPistol( bool pPistol = true ); void setHoldingRifle( bool pRifle = true ); void setMovingForward( bool pForward = true ); locomotion( TEntity e); void render( TCamera cam); }; #endif
8 Comments
Recommended Comments