Skip to content

Tutorials · Crypt Knight · Chapter 7

Animating the knight

40 minutes Uses: Sprite, AnimatedSprite, grounded, velocity, play_clip

By the end

  • art/hero.png and art/hero.anim: the knight’s three strips packed into one sheet, and its clips: idle, run, jump and fall
  • Each clip’s speed and whether it loops, and a pivot on every frame of the two clips whose art floats
  • The knight as an Animated Sprite on the same node as its body, drawn at each frame’s own size
  • A script that shows idle, run, jump or fall from what the body is doing, and mirrors the art to face the way the knight last moved
On this page

One sheet for the three strips

The knight’s art is three pictures: gothic-hero-idle.png, gothic-hero-run.png and gothic-hero-jump.png, each a strip of frames. An Animated Sprite plays clips of one picture, and these three are drawn at three sizes, so they cannot be one grid. Make Animation… packs pictures into one sheet and writes the animation that holds them. The next steps cut that sheet into the knight’s own clips.

  1. In Assets, open art, right-click gothic-hero-idle.png, and choose Make Animation…. The window opens with gothic-hero-idle.png ticked, Name gothic-hero-idle, Frames a second 12 and Loop ticked.
  2. Tick gothic-hero-jump.png and gothic-hero-run.png too. The pictures play in name order, which here is the order they are listed in.
  3. Set Name to hero, leave Frames a second and Loop as they are, and press Create. It writes art/hero.png, a sheet of the three strips side by side, 2048 by 128, and art/hero.anim, one clip called hero that plays them.
The Make Animation window over the editor, listing the pictures in art with gothic-hero-idle.png, gothic-hero-jump.png and gothic-hero-run.png ticked, Name still the picture’s own, gothic-hero-idle, Frames a second 12, and Loop ticked

The hero clip is the three strips as three whole frames, which nothing will play: it is how the sheet was made. Make Animation… makes and never updates: pressed again on the same name, it refuses. To change the sheet, delete hero.png and hero.anim and make them again.

The knight draws the sheet

The knight is still a crimson box. It becomes a Sprite, which draws a picture, with an Animated Sprite beside it, which says which clip of the sheet to draw.

  1. Select knight. Remove its Shape with the bin icon at the right of the ShapeComponent header.
  2. Press Add component and choose SpriteComponent, then Add component again and choose AnimatedSpriteComponent.
  3. Drag art/hero.png from Assets onto the Sprite’s Texture, set Size to 38 and 48, Anchor to 0.5 and 1, and Sort Layer to 5, as the box’s was.
  4. In the Animated Sprite, drag art/hero.anim onto Animations, keep Clip on idle, Speed 1 and Playing ticked, and tick Frame Size.
  5. Keep the knight selected, so the Animation panel at the bottom of the window shows hero.anim, and press Ctrl+S.
The knight selected, its Inspector narrowed to its Sprite and its Animated Sprite: Texture hero.png, Size 38 by 48, Anchor 0.5 and 1 and Sort Layer 5, then Animations hero.anim, Clip idle, Speed 1, Playing and Frame Size ticked; in the Viewport the knight’s art sits in its Sprite frame, with the smaller green body box and its two top grabs inside
Texture
The picture the frames are cut from: the sheet. The Animated Sprite’s clip chooses which part of it to draw.
Clip
The clip to play. A name the animation does not have draws the whole sheet at once, so until the next section cuts the clips, the knight is the whole sheet squeezed into 38 by 48. That is expected.
Frame Size
Draws each frame at its own size in pixels, and places it so its pivot sits on the node. Without it, every frame is stretched to the Sprite’s Size. The knight’s frames are 38, 61 and 66 wide, and stretching them to one size would squash all but one.

Cut the strips into clips

The Sprite sheet tab cuts a picture into a grid of cells, and turns cells into frames. The hero sheet is not one grid: each strip has its own cell size, and starts at its own distance from the left. So the sheet is cut four times, one clip each, setting the grid to the strip first. The three strips sit side by side at these places, which is what the Margin is for: the jump strip at x 0, the run strip at 307 and the idle strip at 1101.

The Sprite sheet tab open on hero.png, 2048 by 128: its Grid with 32-pixel cells, the sheet drawn across the tab with the knight’s frames in a row, the Clips and Regions sections under the Grid, and the Animation panel below listing the clips hero, idle, run, jump and fall
  1. With knight still selected, double-click art/hero.png in Assets. The Sprite sheet tab opens on it.
  2. Idle. Under Grid, set Cell to 38 and 48, and Margin to 1101 and 0. The grid is drawn over the sheet, and its first column is the idle strip’s first frame. Drag across the first four cells of the top row, from cell 0, 0 to cell 3, 0: the bar under the sheet shows the cell under the cursor, and Selected 4 x 1.
  3. Under Clips, press From selection. A clip appears in the list. Name it idle, set its rate to 8 fps, and its loop to Loop, and press Generate 1. The Animation panel lists idle (4). Press Clear to empty the list.
  4. Run. Set Cell to 66 and 48, and Margin to 307 and 0. Drag from cell 0, 0 to cell 11, 0: Selected 12 x 1. Press From selection; name it run, 14 fps, Loop; press Generate 1 and Clear.
  5. Jump. Set Cell to 61 and 77, and Margin to 0 and 0. Drag from cell 0, 0 to cell 2, 0: Selected 3 x 1. Press From selection; name it jump, 12 fps, Once; press Generate 1 and Clear.
  6. Fall. Keep that grid. Drag from cell 3, 0 to cell 4, 0: Selected 2 x 1. Press From selection; name it fall, 8 fps, Once; press Generate 1 and Clear.
  7. In the Animation panel, press Save. It writes the four clips into art/hero.anim.
Loop and Once
What a clip does at its end. idle and run loop: they are a breath and a stride, which repeat for as long as the knight does the same thing. jump and fall play once and hold their last frame: a jump does not start again in mid-air, and the fall, where it leaves off, hangs on its last pose until the knight lands.
fps
Frames a second. A slow idle, 8, is a breath. A quick run, 14, is twelve frames in under a second. fall is as slow as idle.
Clips from the sheet
The jump strip is five frames: the first three, rising, are jump, and the last two, falling, are fall. One picture, two clips.

A pivot for every frame that floats

A frame’s pivot is the point of it that sits on the knight’s node, which is its feet: 0.5 across is the middle, and the other number says how far down the frame the soles are, from 0 at the top to 1 at the bottom. A new frame has 0.5 and 1, the middle of its bottom edge, which is right for the idle and run frames: they are 48 tall, and the knight’s soles are on their bottom row.

The jump and fall frames are 77 tall, to have room for the cape and the leap, and the knight is drawn in them at different heights: his soles are not on the bottom row. A pivot at the bottom would hold the frame by empty space, and the knight would float above the ground, or sink into it, as the pose changes. So each of their five frames gets a pivot at its own soles, the row they end on, over 77.

ClipFrameSoles end at rowPivot y
jump0760.987
jump1670.870
jump2480.623
fall0420.545
fall1600.779
  1. In the Animation panel, click jump in the list of clips. The playhead is on its first frame.
  2. Under Frames, the strip for Frame 0 has a pivot x and a y box. Double-click the y box, type 0.987, and press Enter. Scroll the panel down if the strip is out of sight.
  3. Press the Next frame button in the transport row, which reads Frame 2 / 3, and set y to 0.870. Press it again, and set y to 0.623.
  4. Click fall. Set y to 0.545 on its first frame, press Next frame, and set it to 0.779 on the second.
  5. Press Save, and Ctrl+S.
The Animation panel for the knight: the clips hero, idle, run, jump and fall, with jump chosen, Once, 12 fps, Frame 2 of 3 under the playhead, and in its strip Frame 1, dur 0.08333, pivot x 0.50 and y 0.8701

The script picks the clip

The knight’s script already knows what the knight is doing: it runs, it jumps, it falls. Now it says so to the Animated Sprite, and it turns the art to face the way the knight last moved. Replace everything in knight.rgs with the script below, and press Ctrl+S.

rgs knight.rgs
/// The knight: runs where `move` points, jumps on `jump`, jumps lower when
/// `jump` is let go early, drops through a ledge when `down` is held as it
/// jumps, faces the way it last moved, and shows the clip for what it is doing.
component Knight {
    /// How fast the knight runs.
    #[suffix("u/s")]
    speed: f32 = 110.0,
    /// The way the knight faces: -1 for left, 1 for right.
    facing: f32 = 1.0,
    /// The clip on show, so a clip starts only when it changes.
    shown: String = "",

    fn loop() {
        let x = direction("move").x;
        set_number("CharacterBodyComponent", "velocity.x", x * speed);
        let drop = pressed("jump") && held("down");
        set_flag("CharacterBodyComponent", "drop_through", drop);
        if pressed("jump") && !drop {
            jump();
        }
        if !held("jump") {
            cut_jump();
        }
        if x != 0.0 {
            facing = x;
        }
        set_flag("SpriteComponent", "flip.x", facing < 0.0);
        let want = "fall";
        if grounded() {
            want = "idle";
            if x != 0.0 {
                want = "run";
            }
        } else if velocity().y < 0.0 {
            want = "jump";
        }
        if want != shown {
            play_clip(want);
            shown = want;
        }
    }
}
facing and shown
Two more fields. facing is -1 for left and 1 for right, and keeps its value from step to step, so the knight goes on facing left after it stops. shown is the clip on show, so a clip is started only when it changes.
let x and facing = x
x is the sideways input, read once and used three times. A local is a name for a value; it lives for the one step. facing takes x only while x is not 0, which is how it remembers the last way the knight moved.
set_flag with flip.x
Writes the Sprite’s Flip X on or off. The art is drawn facing right, so a negative facing mirrors it. A Sprite’s Flip mirrors an Animated Sprite’s frames too, and, with Frame Size on, the pivot with them, so the feet stay where they were.
grounded and velocity
grounded() is whether the body stood on something at the start of this step. velocity() is its velocity, as a vector; the world’s y grows downward, so velocity().y < 0.0 means rising and a positive one falling.
let want
The clip the knight should be showing, chosen from what it is doing: idle or run on the ground, by whether it is moving; jump while rising; fall otherwise. It starts as fall, and the if chain changes it.
play_clip
Starts a clip from its first frame, and sets the sprite playing. Called on every step it would start the clip over every sixtieth of a second, and jump would never leave its first frame. So the script calls it only when want is not what is shown.

Check it works

The knight in the air a moment after a jump, in his rising pose with his cape streaming behind him, over the town
The knight in the air after the top of a jump, in his falling pose, with his cape flared up above him
The knight against the left wall, facing left: the same art, mirrored