10
\$\begingroup\$

So I've come across an issue in the game I'm working on, but it seems to be a pretty fundamental thing that probably comes up in a lot of games.

My game requires that some gameplay function occurs at a very specific point in time during a character animation. And so, as the title says, I'm wondering what are some good techniques and fundamental strategies for syncing gameplay-related events/functions/actions to specific points in a character's animation.

Here are some simple examples of what I'm talking about in various types of games:

  • Your character reloads their gun in a shooter. Your character plays his/her 'reload' animation, but it's important that the function that sets the currentAmmo variable is only called at the exact moment after the magazine is swapped and the gun is cocked. This might be some point in the middle of the reload animation.

  • In a turn-based RPG your characters stand in a line facing a line of enemies. When commanded to attack, one of your characters runs/jumps up to one of the enemies and slashes their giant sword before running/jumping back to their standing place. You want to make sure that the enemy is damaged at the exact moment that the slashing animation is played - some point between running up and running back.

  • In a stealth game, your character can sneak up and interact with computers and buttons in the world. Maybe there is a button that turns off the power supply to the lights of the outpost that you're infiltrating. When the action button is pressed, your character reaches out and pushes the button and then returns to their idle stance. You want the lights to turn off at the exact point in the 'push_button' animation when the button is pushed in.

Admittedly, my particular case is most like the second example, in which I have created an animation where my turn-based character lunges forward during an attack and I want the damage to be applied at the exact moment that the animation seems to be making contact. Because my game using a turn-based system (imagine something like Final Fantasy or Fire Emblem) I want the damage/healing/magic/etc. to be applied at the correct time during each character animation even though I'm not actually using collision/hitboxes.

I should mention that I'm making my game in a popular game engine, and that right now I'm handling this by using their animation events or notifies to achieve something close to the desired results - my character performs a certain command and triggers a command-specific animation (i.e.: 'attack_command') and the animation assets for each one of my commands must include an animation event/notify 'callback' into my characters ExecuteCommand function. In other words - the character tells the attack animation to play, and then the attack animation emits an event/notify callback into the character at the exact moment during the animation when the damage should be dealt.

Honestly, this works for now, but it just feels wrong - like I'm missing some part of the bigger picture here! Part of the reason that this method feels wrong is that it couples the game logic with the animation assets; if my animation asset forgets to include an ExecuteCommand() event/callback, the command wont execute properly and extra code is needed to check if a command animation finished without executing the command. It's messy and it means that my gameplay has a strange dependency on its assets. Of course I want the damage to occur at a specific point during my attack animation, but I feel really weird about calling gameplay code inside animation assets..

So what am I overlooking here? What are some good general techniques for handling these types of situations in which you want certain important gameplay actions to occur at specific times during animations?

Edit: To clarify, this isn't an engine-specific question nor am I looking for engine-specific designs/techniques. I'm interested in general animation/gameplay synchronization techniques that one might use in your game projects regardless of technologies used.

\$\endgroup\$
  • 1
    \$\begingroup\$ I'm confused. You say you want gameplay to depend on animation timings, but then say you don't want your gameplay to depend on your assets, and animations are a type of asset. How do you expect those wishes to be compatible? \$\endgroup\$ – Anko Sep 8 '15 at 23:06
  • \$\begingroup\$ I want some gameplay elements to be synchronized with animation. However, synchronization between two things doesn't always imply a dependency, right? I'm interested in some techniques that people use to synchronize their animations with their gameplay. I said what I've tried and what I'm currently doing to achieve this - and so my question is, is there a different/better/alternative technique that one might use or is this (animation events/notifies/callbacks baked into the assets) the standard way? Is this what you use in your projects? \$\endgroup\$ – MrKatSwordfish Sep 8 '15 at 23:26
5
\$\begingroup\$

For synchronisation, you need to decide who (your code, animations, or neither) is the timing authority—the "beat" that everyone else "dances" to.

Different arrangements suit different games:

  • Animations are the timing authority (your current setup)

    The game code may trigger animations. When animations reach certain points, they raise events (e.g. reloading done) that the game code may react to (e.g. reset available ammo).

    If the precise timing of animations (independently of game state) is an important part of your game, or you specifically want your animators to control timing, consider this approach.

    Animation tools Blender (3D) and Spine (2D) allow the animator to define events that game code can subscribe to.

  • Code is the timing authority

    Inverse of the above: Events happening in the game world (e.g. the player choosing to reload their weapon) cause animations to be run and to be passed parameters (e.g. time until reload should be finished). Each animation uses the supplied parameters to modify how it looks (e.g. running the animation at an appropriate speed such that the "reloaded part" happens when specified).

    Animations might also be listening for game events (e.g. player cancels reload or player crouches while reloading) and modify their look accordingly.

    If your animations can afford to be flexible about timing, your game relies heavily on procedurally generated content, or you specifically want your programmers to control timing, consider this approach.

    Overgrowth's character animations are largely structured this way: David Rosen explains it in his GDC 14 talk (see specifically the Movement and Movement Continued segments).

  • Implicit timing (external authority)

    In rhythm games or other situations where timing is controlled from an external source (in rhythm games, the music track's beat), it may make sense to model things as such. The game code and animations can both read a global timestamp and game state, then behave accordingly without communicating.

    If your game state and animations are largely dependant on an external timing authority, consider this approach.

You might of course want to use different approaches for different systems in your game. (For example, rhythm games frequently use the beat of the song as an external authority, but animations still listen to player interaction events to cancel or change the look of held notes.)

\$\endgroup\$
0
\$\begingroup\$

I've read somewhere that almost all computation problems can be solved with an additional abstraction layer, and I don't see your case being different.

For this requirement I generally see a layer to control the State of the character. This way the character will have a current Animation and a current State. Each one with its own responsibility.

The animation is responsible only for the visual, and the state handles the game specific logic for that action.

In my fighting game, the state is a object that inherits from BaseState class and has an Update() method. Each character has a collection of states, but only one can be assigned at a time. And the Update() method of the current state is called once per frame.

It's inside the Update() of the state where I do all that logic: set the velocity of character at a specific frame, increment/decrement health etc.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.