Jump to content

animation functions?


cassius
 Share

Recommended Posts

At the moment I have a single seperate animation function for each character and I was wondering how other people tackle this.Would it be feasible or advisable to have a single anim function for ALL characters?

amd quad core 4 ghz / geforce 660 ti 2gb / win 10

Blender,gimp,silo2,ac3d,,audacity,Hexagon / using c++

Link to comment
Share on other sites

With animations for characters I always make an "animator" class.

 

This is generally how I do it. Like it or not it works for me wink.png

 

The animator class lives within any character class in a "Has a" relationship. The animator class is given a pointer or reference to the mesh to be animated and stores each animation in an animation struct as shown below:

struct Animation {
  float start;
  float end;
  float speed;
  int SEQ;                    //sequence
  std::string type;         //name of the animation
  bool loop;
  float currentFrame;
  float blendVal;
};

 

These structs are then stored in a std::map<std::string, struct Animation> STL map where the std::string is the name of the animation and the struct is... well the struct.

 

The class has a number of functions to register animations, play animations, stop animations etc. and all that the character class has to do is 1. update the animator each frame and 2. initialize new animations based on what is happening.

 

Anyway... This animator class I'm showing here is kinda suited to DDD but you could easily use it without, you'll just have to register each animation separately in hard code.

 

Below is the class declaration. I'll let y'all figure out how to make the implementation.

 

class Animator {
public:
  Animator::Animator(LE::TEntity *pModel);
  Animator::~Animator();
  void Update();
  void RegisterAnimation(std::string type, float start, float end, float speed, int SEQ);
  void PlayAnimation(std::string type, bool loop);
  void StopAnimation();
  void BlendAnimation(std::string type, float blendRate, bool loop);
  void PlayEmote(int);

private:
  void LoopAnimation(struct Animation*);
  LE::TEntity *pModel;
  float blendRate;
  std::vector<int> AnimDelete;
  std::map<std::string, struct Animation> AnimBank;
  std::vector<struct Animation> EmoteBank;
  std::vector<struct Animation*> AnimActive;
  struct Animation *anim;
};

 

- Update() - plays any animation that is active including animations that still have a blend value greater than 0. If the animation structs loop variable is true it will loop expired animations otherwise it will erase them from the AnimActive list. If the blend value of an active animation reaches 0 it will also be removed from the AnimActive list. If there are registered emotes and the "idle" animation is active this function will roll a dice for playing an emote.

 

- RegisterAnimation() - creates a new animation struct based on the given data and inserts it at the end of AnimBank.

 

- PlayAnimation() - plays the requested animation either looped or not... This will remove all other active animations prior to the call whether blended or full on.

 

- StopAnimation() - Clears AnimActive which effectively stops all animation

 

- BlendAnimation() - Adds a new animation to AnimActive with a low blend value. The blend value of this animation will continue to rise until it reaches 1.0f and all others in AnimActive are 0 and then removed. If BlendAnimation is called before the last BlendAnimation() anim finishes then the last one will be blended out from where ever it was.

 

- PlayEmote() - plays a single emote at random.

 

- LoopAnimation() - Edits the data in the Animation struct passed to it so that it will loop and not end. It is called only if an animation reaches its end and the loop boolean parameter is true.

 

NOTE: This class was made specifically with my game in mind... Therefore, while idle, it will randomly play random emote animations (if registered). Therefore, some of the functions like PlayEmote(int) may not make sense to you. However, the way it works in my code is, if the animation called "idle" is playing then it rolls a dice (1 in 7 chance) and if it hits 7 it plays a random emote animation labeled "emote" from the EmoteBank (std::vector<struct Animation> all emotes are labelled "emote" while all other animations must be unique.

STS - Scarlet Thread Studios

AKA: Engineer Ken

 

Fact: Game Development is hard... very bloody hard.. If you are not prepared to accept that.. Please give up now!

Link to comment
Share on other sites

Scarlet thread : Interseting, but a bit complex for me. I will paste that code into my "examples" folder for later study.

At the moment I have a simple struct called actor which contains everything pertaining to characters including framebegin and frameend and health etc.

amd quad core 4 ghz / geforce 660 ti 2gb / win 10

Blender,gimp,silo2,ac3d,,audacity,Hexagon / using c++

Link to comment
Share on other sites

cassius with C you'll want to store an array of a structure that holds the animations of that character because it'll have more than 1 animation to it. Then you can have normal functions like:

 

UpdateAnimations(characterStruct char);

 

Where you process the animations of the character you pass into it. The thing you'll want to do is actually loop through every active animation each cycle. You do this because of blending. You'll most likely only have at most 2 active at a time (unless you are trying to do split animations) and mostly only 1 active. I say this because when you are blending between 2 animations they'll both be active and you'll call Animate() on both but they'll have different blend values. One will be blending in the other out. So you'll need a blend value for each animation and an active flag for each animation.

Link to comment
Share on other sites

Blending is another thing I don't fully understand.

Blending means you can play 2 different animations simultaneously. Yes, they will be mixed. And you'll get something between them. But with "blending" parameter you can express one animation more then the second. So you can change "blending" from 0 to 1 through the time and your character will change one animation to the second seamlessly.

Link to comment
Share on other sites

The only thing I think you need to know about blending is that 1 will play the animation in full strength and 0 won't show the animation being played at all (even if you call Animate()). When you change animations from say idle to walk you don't want to fully just switch from idle to walk because it'll be choppy and look bad, instead you want to smoothly blend from idle to walk. The way you do this is by slowly decreasing the blend of idle from 1 to 0, and increasing the blend value of walk from 0 to 1. You need to call Animate() on both in the same frame to get this effect.

 

This is why each animation needs it's own blend variable. It could also store it's own blend speed if you want to increase/decrease the blending of each animation at different rates.

 

I'm not sure if you are using Josh's examples of animation but normally I, and some others I know, increase the frames ourselves with a timer.

 

Just some pseudo type ideas

void PlayAnimation(ActorAnimations anim, string animName)
{
// check to see if animName is already active and if so bail out of this function because we don't want to activate it twice
// find the current active animation in anim and set it's blendMode value to BLEND_OUT, this active value should be true already
// set it's currentFrame to startFrame, possibly some other init's
// find the animName animation in anim and set it's blendMode value to BLEND_IN, and active to true
selectedAnimation.lastTime = AppTime();
}

void UpdateAnimation(ActorAnimations anim)
{
// loop through all animations of this actor
foreach(a in anim)
{
 // when we switch animations both will be active, until the blend out one is finished, then we'll set it's active to false
 if(a.active)
 {
  if(a.blendMode == BLEND_OUT)
  {
// use a timer to increase a.blend value over multiple frames until it's >= 1
if(a.blend >= 1) a.blendMode = BLEND_NOTHING;
  }
  if(a.blendMode == BLEND_OUT)
  {
// use a timer to decrease a.blend value over multiple frames until it's <= 0
// once we are fully blended out, deactivate this animation
if(a.blend <= 0) a.active = false;
// just resetting this variable, not 100% needed, but cleaner
if(a.blend <= 0) a.blendMode = BLEND_NOTHING;
  }
  // animate
  if(AppTime() - a.lastTime > a.animationSpeed)
  {
a.lastTime = AppTime();
a.frame++;
if(a.frame > a.lastFrame)
 if(a.loop)
  a.frame = a.startFrame;
 else
  // maybe fire a callback function or something so we can handle 1 time animations and what to change to after it's finished
  }
  // something like this, can't remember param order
  Animate(a.model, a.frame, a.blend);
 }
}
}


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...