Actors

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()
    super.init(self)
end

return actor

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

    -- Display name (optional)
    self.name = "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.

Portraits

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.

Voices

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

Blushing

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

Animations


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.

Offsets


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!