An actor is a representation of a character, whether it's an NPC, a follower, or a party member! Actors are what gives visuals to characters, and defines their sprites, the origins of those sprites, and all sorts of stuff.

So, let's get started by making... Kris! Again!

Getting Started With Actors

local actor, super = Class(Actor, "kris")

function actor:init()

return actor

We get started with the same boilerplate as always. Now let's set some variables:

    -- Display name (optional) = "Kris"

    -- Width and height for this actor, used to determine its center
    self.width = 19
    self.height = 37

    -- Hitbox for this actor in the overworld (optional, uses width and height by default)
    self.hitbox = {0, 25, 19, 14}

    -- A table that defines where the Soul should be placed on this actor if they are a player.
    -- First value is x, second value is y.
    self.soul_offset = {10, 24}

    -- Color for this actor used in outline areas (optional, defaults to red)
    self.color = {0, 1, 1}

    -- Path to this actor's sprites (defaults to "")
    self.path = "party/kris/dark"
    -- This actor's default sprite or animation, relative to the path (defaults to "")
    self.default = "walk"

    -- Sound to play when this actor speaks (optional)
    self.voice = nil
    -- Path to this actor's portrait for dialogue (optional)
    self.portrait_path = nil
    -- Offset position for this actor's portrait (optional)
    self.portrait_offset = nil

    -- Whether this actor as a follower will blush when close to the player
    self.can_blush = false

Woah, woah, that's a lot. What's this about a soul? Blushing? Portraits? Voices? What's going on here?

Let's go through these one by one.

Soul Offset

In a battle, the Soul is the little heart that you control. It's the very culmination of your being. When that soul gets spawned, it appears on top of the player, and moves to the center of the arena. This offset is used to place the soul correctly.


If your character is going to be speaking, you'll want to give them a portrait. This is a sprite that appears next to the text box when they speak. The portrait offset is used to place the portrait correctly.


Again, if they're gonna be speaking, they'll need a voice, too!


Ralsei blushes if you get close enough to them. With can_blush, you can make your actor do the same!


Now that we've got our actor set up, let's give them some animations!

In the init function, let's add an animation table:

    -- Table of sprite animations
    self.animations = {
        ["slide"] = {"slide", 4/30, true},

This table is a list of animations that this actor can play. The key is the name of the animation, and the value is a table containing the name of the animation, the speed of the animation, and whether or not the animation should loop.


Does a certain animation not line up correctly? That's where offsets come in.

    -- Table of sprite offsets (indexed by sprite name)
    self.offsets = {
        ["battle/idle"] = {-5, -1},

This table is a list of offsets for each sprite. The key is the name of the sprite, and the value is a table containing the x and y offset of the sprite.

Battle Preparation

If your character is a party member, you'll have to worry about their battle sprites. Let's add some! Take a look at Kris's:

        -- Battle animations
        ["battle/idle"]         = {"battle/idle", 0.2, true},

        ["battle/attack"]       = {"battle/attack", 1/15, false},
        ["battle/act"]          = {"battle/act", 1/15, false},
        ["battle/spell"]        = {"battle/act", 1/15, false},
        ["battle/item"]         = {"battle/item", 1/12, false, next="battle/idle"},
        ["battle/spare"]        = {"battle/act", 1/15, false, next="battle/idle"},

        ["battle/attack_ready"] = {"battle/attackready", 0.2, true},
        ["battle/act_ready"]    = {"battle/actready", 0.2, true},
        ["battle/spell_ready"]  = {"battle/actready", 0.2, true},
        ["battle/item_ready"]   = {"battle/itemready", 0.2, true},
        ["battle/defend_ready"] = {"battle/defend", 1/15, false},

        ["battle/act_end"]      = {"battle/actend", 1/15, false, next="battle/idle"},

        ["battle/hurt"]         = {"battle/hurt", 1/15, false, temp=true, duration=0.5},
        ["battle/defeat"]       = {"battle/defeat", 1/15, false},

        ["battle/transition"]   = {"sword_jump_down", 0.2, true},
        ["battle/intro"]        = {"battle/attack", 1/15, true},
        ["battle/victory"]      = {"battle/victory", 1/10, false},

This, of course, being in self.animations. Let's also add some offsets:

        -- Battle offsets
        ["battle/idle"] = {-5, -1},

        ["battle/attack"] = {-8, -6},
        ["battle/attackready"] = {-8, -6},
        ["battle/act"] = {-6, -6},
        ["battle/actend"] = {-6, -6},
        ["battle/actready"] = {-6, -6},
        ["battle/item"] = {-6, -6},
        ["battle/itemready"] = {-6, -6},
        ["battle/defend"] = {-5, -3},

        ["battle/defeat"] = {-8, -5},
        ["battle/hurt"] = {-5, -6},

        ["battle/intro"] = {-8, -9},
        ["battle/victory"] = {-3, 0},

Perfect! We're battle-ready!