Tuesday, April 4, 2023

Creating Fluid Sword Combo Animations in Unreal Engine 5.

Introduction

Hello dear reader! 

Today I would like to share with you some of my thoughts about authoring melee attack combos in games, their anatomy, different approaches to creating your animation assets for them, and implementing them in Unreal Engine. But before that, a short foreword explaining why I decided to explore this topic.

In 2003 Ubisoft released a superb game, one of my all-time favorites - Prince of Persia: Sands of Time. It was an absolute feast for my young gamer's senses. The story, gameplay, level design, VFX, animations, music... an ideal mix of high-quality ingredients.

I'm bringing up this game now because a couple of weeks ago I accidentally stumbled upon a video demonstrating the game's combat animations. And you know what? I was highly impressed with them once more, but this time from a whole new point of view. 

Shocking twenty years have passed since I finished this game last time. Today I'm a hardened veteran gamer and a game developer. And this is exactly why I reached a whole new level of appreciation for the superb quality of those combat animations. They were authored with staggering attention to detail and design. Check them out by yourselves. I am, personally, especially impressed with this basic attack combo. Those animated pauses between slashes are an embodiment of pure elegance itself. 

Demonstration of combat animations in Prince of Persia: Sands of Time.

Currently, I'm working on my own RPG game in UE5. For some time now I have been mulling over what type of combat system to implement. And after seeing this video I decided to use similar attack combos with animated pauses in my game. Now, that I'm mostly done with the implementation of this feature I want to put down a few words about this process.

Combo Anatomy

First of all, we are going to break down the anatomy of such a combo in terms of animations that are necessary to implement it. Let's assume that the combo consists of N attacks. The combo has to start from and end with an Idle animation. Between the combo attacks, the game waits for a player's input for a certain amount of time t_timeout. If the player makes no attack before t_timeout time is spent then we break out of the combo into the Idle animation. Each attack except the last one should have the same duration of t_attack so that the user can easily adjust to the combo's rhythm. The last attack is a special case of a Combo Closure Attack that can be, for example, slower but more powerful.

We can summarize all these details with a single Combo Animation Flow Diagram:

Combo Animation Flow Diagram.

Thus, to implement such a combo's animation perfectly and with full control we would need:

  • 1 Idle animation.
  • 1 Combo Closure Attack animation.
  • N - 1 Attack animations of t_attack duration each.
  • N - 1 Waiting animations of t_timeout duration each. These animations will seamlessly glue together Attack animations.
  • N - 1 Attack Cancel animation. These animations will seamlessly transition a character from the corresponding Waiting animation into the Idle animation when the waiting is timed out.

Showcase

I didn't make my own attack animations from scratch but used freely available animations from a great website Mixamo as a base for my combos.

I implemented two such combos for my game: one for a one-handed weapon and one for a two-handed weapon. And for each of these combos, I employed a slightly different approach. 

Slow and precise approach combo

For the first combo, I used 4 separate attack animations from the Mixamo. Each of these animations initially transitioned between states following a scheme Idle->Slash->Idle. The following week I had to do a really heavy animation editing in Blender to make these animations follow the scheme fitting my combo anatomy:

  • Attack 0: Idle->Slash1(0.7 sec)->Wait1(0.6 sec)->Idle.
  • Attack 1: Wait1->Slash2(0.7 sec)->Wait2(0.6 sec)->Idle.
  • Attack 2: Wait2->Slash3(0.7 sec)->Wait3(0.6 sec)->Idle.
  • Attack 3: Wait3->Slash4->Idle.

Finally I made an animation montage consisting of these 4 animations:


One-handed Weapon Combo Animation Montage.

BaseCharacterAnimation Blueprint Event Graph.

BaseCharacter.h


The main things to note here are "AttackEnd" and "ComboBreak" Skeleton Notifies. The AttackEnd Notify marks the start of the Waiting animation when a player might follow up with a new combo attack. The ComboBreak Notify causes the game to restart a combo from the very beginning when the next attack comes.

Fast and furious approach combo

For the second combo, I used an animation from Mixamo too. But this time I selected a single combo animation that follows a scheme Idle->Attack1->Attack2->Attack3->Idle. More than that, I did close to no preparatory animation editing. All the magic was done in the combo's animation montage:


Two-handed Weapon Combo Animation Montage.

Note that all animation segments in this montage reference the same single combo animation. The AttackEnd and ComboBreak Notifies work exactly the same way as in the first combo. But these animation segments are configured in a particular way to satisfy the combo's anatomy:

  • every segment ends at the animation time at which the following segment starts. Thus the combo's animation is seamless without any effort.
  • segments corresponding to attacks and waiting are of the same respective durations.
  • the source combo animation obviously does not have keyframes for transitioning back from each attack's Waiting states to the Idle state when the combo is broken. These transitions are made by UE automatically using Animation Blending. 
All I had to do to make an almost perfect combo montage from this single animation was to:
  1. select the correct points in time of the source animation at which to separate attack animations from waiting animations. I selected the frames between slashes where the legs' position was closest to the Idle state legs' position to make blending into the Idle state as seamless as possible.
  2. set up the segments' "Start Time" and "End Time" properties to these points in time. 
  3. scale the attack segments using the "Play Rate" property to the correct uniform attack durations. 
  4. similarly, scale the waiting segments. But to emphasize the effect of a character waiting for the player's input I made these segments from really short animation sections (~50 ms) and slowed them down ~8 times to uniform 0.4 sec.

And that is it! It took me exactly one evening to finish the second combo's montage. And the result is surprisingly good for such a short amount of time.

Conclusion

You can check out the WIP combos in an actual action for yourselves. In my opinion, each of these two approaches has its own pros and cons. 

Demonstration of implemented attack combos in my game.

The first combo with manually tailored animations looks really balanced and natural, it can be gracefully canceled into the Idle state after any attack. But it requires animation editing skills and time to fine-tune such animations.

The second combo, on the other hand, was really easy to implement. It saved me lots of time and effort. The result is of course not as perfect, not as graceful and natural as with a fully manual animation. But if you don't give it a really close look (because you are in the middle of a fast-paced sword exchange with several enemies) it looks pretty good. 

Automatic animation blending turned out to be a really great feature to speed up your game development and prototyping. This time I used premade animations as a base, but even if I had to manually create a new animation for a new combo, I would still prefer making one animation of the full combo following the Idle->AttackCombo->Idle scheme and upholding the roughly correct timings and between-attack poses that easily blend into the Idle pose, rather than doing 4 separate animations Idle->Attack->Idle and struggling to glue them together as a combo.

What thoughts do you have on this topic? Share your ideas, comments, experiences, struggles, and victories implementing attack combos in games down in the comment section.

No comments:

Post a Comment