Designing base animations

In this lesson, we will add simple animations to the battlers. We will make them move forward and back, but also add an animation to represent taking damage. If you lack a sprite for visualization animations, you can find one in the Godot project that comes with the course.

Here, I’m assuming you know how to use Godot’s animation editor. I am not going to explain how it works in detail work here. You can learn how the editor works using the following free resources:

The scene’s setup

Then are two problems to address when setting up your game for character animation:

Let’s set up the scene to get started. We need a little rig to give our animations some flexibility. Create a new scene with a Position2D as its root node. Name it BattlerAnim.

Below you can see the setup. There is a second Position2D node named Pivot that we will control using the AnimationPlayer. That way, even if you want to move the root node using GDScript code, you can do so.

I’ve attached a new script named BattlerAnim.gd to the root node.

We have a second AnimationPlayer named AnimationPlayerDamage here so we can layer two animations.

During development, I had only one animation player initially, which led to a bug. The poison status effect could stack to the point the battler would keep playing the damage animation and never finish its turn.

There is also a Tween node that we’ll use to move the root note forward and back. We need the tween here because the battler can face two different directions, left or right, and in either case, we want to animate it moving forward.

Designing animations

It’s time to add some simple animations. To visualize your work, you can select the Pivot node and drag and drop a sprite into the scene.

Select the AnimationPlayer node and create a setup animation which we’ll use to reset the Pivot node to its default state. With the Pivot selected, key its Modulate, Position, and Visible properties. I’ve also set the animation to Autoplay on Load by clicking the sign-like icon to the right of the animation drop-down menu.

The attack animation should move the battler forward (towards the left, by convention) and back to its start position. Below, you can also see a Functions track that calls the method emit_signal() and emits the triggered signal.

We’ll use the signal to consume a hit on our AttackAction objects. This setup allows you to design attacks and spells that hit multiple times and with precise timings.

To call functions in animations as in the image above, you want to create a Call Method Track:

When you insert a keyframe on such a track, a window opens and lets you select a function to call. To set the function’s arguments, click on the key in the animation editor and in the Inspector, expand Args.

The die animation tints the node red and makes it blink by animating its Modulate property. To do so, you want to alternate keyframes between a red and a white tone. The last keyframe is still red, but with the alpha channel dragged to zero, which makes the sprite fade out.

The scale track maintains the node’s scale to (1, 1) until the 0.35 seconds mark. Then, I stretched the character by scaling it vertically, and then squash it down.

I also used the animation to toggle the node’s visibility. This is a safeguard: I mostly do that to avoid bad surprises at run-time.

Next, let’s select the AnimationPlayerDamage node and add a take_damage animation to it.

This animation is similar to die, except it only animates the node’s Modulate property, and at the end of the animation, we remove any tint from the node.

Notice the keys’ timings below: the character initially blinks fast and the effect slows down after a few split seconds.

Creating derived battler scenes

Until now, we had temporary Battler instances as a child of our ActiveTurnQueue, in the CombatDemo scene. We’re going to create two derived scenes for the playable character and the enemy.

While we could code Battler.gd to customize every battler instance a lot in the Inspector, as your game grows, the list of required properties to do so will grow too and become hard to manage.

You will likely need some battlers to be unique in some ways, and to do so you’ll need specialized scenes that favor composition over inheritance. It’s the most flexible way to work in Godot, at little cost.

You could use the scene inheritance feature in Godot. I recommend to avoid it: if you change the parent scene’s structure, you can lose data in inherited scenes without warning. There are other known issues with changes from the parent scene not propagating to inherited ones.

That’s why, instead, I recommend creating new scenes, which is what we’ll do here.

In CombatDemo, remove the two Battler instances. We’ll replace them with two new scenes. For each scene:

  1. Duplicate Battler.tscn in the FileSystem tab, name the new file after your battler, and open the new scene.
  2. Instantiate BattlerAnim.tscn as a child of the scene’s root. We use this instance to give our battler a skin.
  3. Right-click on BattlerAnim and turn on Editable Children.
  4. Add a Sprite as a child of the Pivot node. To do so, I select the Pivot and drag and drop a PNG file from the FileSystem onto the viewport. You can use the textures bear.png and bugcat.png.

Your battler scenes should look like this.

I created two scenes, Bear.tscn and BugCat.tscn. In the CombatDemo, instantiate each of them as a child of the ActiveTurnQueue.

In this demo, the battlers aren’t what they would be in a larger game project. Here, we’re using the Editable Children feature for testing purposes. Instead, in a complete game, you may want to export an extra property on the BattlerAnim class to assign it an animated skin. But while prototyping, Editable Children does the job.

In the next lesson, we will code the BattlerAnim and start playing animations.