Welcome to Iris Engine’s documentation!

Iris Engine is a visual novel engine that will help you tell interactive stories.

Its scripting language, Lua, is really easy to learn, so you will be able to express your ideas even if you don’t know anything about programming. Here is an example of a conversation between two characters:

-- First, give a name to your characters
h = Character.new("Haru")
s = Character.new("Sakura")

-- And let them speak
h "Hi there!"
s "This is all you need to do to display dialogue on the screen."
h "Easy, right?"

Warning

Iris Engine is still in development and some important features have not been implemented yet. Using it for production is not recommended.

Getting Started

Your first game with Iris Engine
A step-by-step tutorial that will guide you through the creation of a simple game in Iris Engine from start to finish. You should start here.
Examples and templates
Use these as a base for your game so that you can start creating right away.
Working with visuals
Learn how Iris Engine handles backgrounds, sprites and character sprites.
API reference
Here you will find detailed information about all the functions and classes available to you.
The config file
Detailed information about all the settings you can change to make your game work the way you want.

Getting Started

The best way to learn how to create a game with Iris Engine is to follow the steps in Your first game with Iris Engine.

If you have already done that, take a look at the templates, which will help you get up and running quickly.

Your first game with Iris Engine

The purpose of this tutorial is to demonstrate how you can make a simple visual novel using Iris Engine from start to finish.

Warning

Iris Engine is still in development and some important features have not been implemented yet. Using it for production is not recommended.

Preparations

The first thing you’ll need to do is download the latest version of Iris Engine.

_images/download_engine.png

Then, create a folder for your game and unzip the contents of Iris-Engine.zip to that folder.

You should see a file called Iris Engine.exe, it will be the executable of your game. You can rename it if you want.

If you try to run the game right now you’ll get an error. That’s because you need a template for your game. In this tutorial we are going to make a 720p visual novel, so go ahead and download the 720p Visual Novel Template.

Unzip the contents of 720p-VN-Template.zip to the folder of your game, so that config.lua is in the same folder as the executable of your game.

If you try to run the game now, you should see something like this:

_images/fg_firstRun.png

Now open config.lua in any text editor. I personally recommend using Sublime Text, Visual Studio Code, or Notepad++. You should find the following line near the beginning of the file:

name = "720p Template",

Replace the text in quotes with the name of your game as you want it to appear in the title of the window. For example, if the name of your game is “Tutorial Game”, you should edit the line to look like this:

name = "Tutorial Game",
Dialogue and narration

Let’s start with the actual game. Open assets/scripts/_start.lua in your text editor. This file contains the first script your game will run. There is already some code there from the template but we don’t want it in our game, so delete it.

First, we are going to start by writing a bit of narration:

say "I'm on my way home from class."
say "There are more students than usual today."
say "I guess that makes sense, midterms are coming closer and all club activities have been suspended."

To try this out, copy the code above into the script you just opened, save the changes to the file and double click on the executable of your game to launch it.

As you can see, narration is written using the say word followed by the text of the narration in quotes.

Let’s try now to make a conversation between two characters. The first thing you’ll need to do is define them. Add the following code to the beginning of the script:

h = Character.new("Haru")
s = Character.new("Sakura")

These two lines define characters. The text in quotes is the name the player will see, while the text before the = symbol is the internal name of the character in the code of the script, in this case h for Haru and s for Sakura.

Now that the characters are defined, we can use h and s in the same way as say to write dialogue, like so:

h = Character.new("Haru")
s = Character.new("Sakura")

say "I'm on my way home from class."
say "There are more students than usual today."
say "I guess that makes sense, midterms are coming closer and all club activities have been suspended."

s "Hi there, Haru! Are you going home now?"
h "Yes I am. I want to study for the midterms."
s "Well, about that... I wanted to ask you something."
h "What is it?"
s "Please, help me with maths!"

The main difference between using say and the characters we defined is that the latter shows the name of the character that is speaking.

_images/fg_dialogue.png
Images

Now that we know how to write the text of our game let’s add some images, this is a visual novel after all. I’ve prepared some images so that you can follow along, click here to download them. Just unzip the contents to your game folder.

Let’s try adding a background to the game. Take a look at the content of assets/images/backgrounds. Here are the images you can use as backgrounds for your game. We are going to use street day.png. Add the following line just after the definition of the characters:

scene("street day.png")

The scene function clears the screen and displays a background image, in this case street day.png. This is especially useful in cases where every character leaves the scene or when the action of the story moves to another place, as it will automatically hide all other images in the screen.

Now that we have a background, let’s add a sprite for Sakura.

Tip

In video games, 2D images of characters, items and other things are called sprites.

First, take a look at the content of assets/images/characters. In Iris Engine, character sprites are composed of a base, which is an image of the character without a face, and a set of images with the facial expressions the character can make.

_images/baseVSexpressions.png

The reason for this is that it allows us to reuse the same expressions with different base images, but that’s out of the scope of this tutorial. For now, pay atenttion to the name of the files.

In order to show a character sprite, we need to define it first in a similar way as we did with characters in the previous section. Add the following code just after the definition of the characters:

sakura = CharacterSprite.new("sakura1.png")

Here, we define a character sprite that uses sakura1.png as the base image and give it an internal name, in this case sakura, so that we can refer to it later in the script.

Note

Before we continue, let’s talk a bit about terminology. Here, sakura is what we call a variable. h and s are also variables.

Variables are a powerful tool that allows us to give names to things so that we can use them later in the script.

Now that the sprite is defined, we can use sakura:show("expression") to display it with that facial expression:

h = Character.new("Haru")
s = Character.new("Sakura")

sakura = CharacterSprite.new("sakura1.png")

scene("street day.png")

say "I'm on my way home from class."
say "There are more students than usual today."
say "I guess that makes sense, midterms are coming closer and all club activities have been suspended."

sakura:show("smiling")

s "Hi there, Haru! Are you going home now?"
h "Yes I am. I want to study for the midterms."

sakura:show("serious")

s "Well, about that... I wanted to ask you something."
h "What is it?"

sakura:show("normal")

s "Please, help me with maths."

The text in quotes is the name of the facial expression we want the character to make. If the base image is sakura1.png and the name of the expression is smiling, then the engine will display the image sakura1 smiling.png as the facial expression.

You can hide a character sprite using hide. For example, you can hide Sakura with sakura:hide(). This is useful when a character leaves but the scene stays the same.

Choices

Many visual novels allow the player to make decisions that influence the outcome of the story. In this tutorial, we are going to let the player decide if they want to help Sakura study maths or not.

The first thing we need to do is define what will happen when the player chooses each option. In order to do that, we are going to do something very similar to what we did with characters and character sprites. For each option, we are going to define a block of code with the outcome of that decision, and we are going to give a name to that block so that we can use it later.

These blocks of code are called functions, and they are defined like this:

help = function()
    h "Okay, I will help you."
    sakura:show("happy")
    s "Really? Thanks!"
    h "No problem, it will help me review the subject."
end

dontHelp = function()
    sakura:show("nervious")
    h "Sorry, but that's my worst subject, I don't think I will be able to help."
    sakura:show("serious")
    s "Okay, no problem."
    s "I guess I will ask someone else."
end

Here we define two functions, one called help and the other called dontHelp. A function starts with function() and ends with end, everything in the middle is part of the function.

If you try to launch the game now you’ll see that nothing has changed. This is because we’ve defined the functions but we haven’t used them yet. Let’s fix that.

In order to present a choice to the player we need to define a question in the same way we’ve been defining things before.

q = Question.new({
    "Help her", help,
    "Don't help her", dontHelp
})

To create a question we need to give it a list with the options the player can choose. The text in quotes is the text of the option the player will see, and the text without quotes is the name of the function that contains the code of the outcome of that option.

Now that everything is defined, we can present the choice to the player with q:ask(). Here is the script so far:

h = Character.new("Haru")
s = Character.new("Sakura")

sakura = CharacterSprite.new("sakura1.png")

scene("street day.png")

say "I'm on my way home from class."
say "There are more students than usual today."
say "I guess that makes sense, midterms are coming closer and all club activities have been suspended."

sakura:show("smiling")

s "Hi there, Haru! Are you going home now?"
h "Yes I am. I want to study for the midterms."

sakura:show("serious")

s "Well, about that... I wanted to ask you something."
h "What is it?"

sakura:show("normal")

s "Please, help me with maths."

help = function()
    h "Okay, I will help you."
    sakura:show("happy")
    s "Really? Thanks!"
    h "No problem, it will help me review the subject."
end

dontHelp = function()
    sakura:show("nervious")
    h "Sorry, but that's my worst subject, I don't think I will be able to help."
    sakura:show("serious")
    s "Okay, no problem."
    s "I guess I will ask someone else."
end

q = Question.new({
    "Help her", help,
    "Don't help her", dontHelp
})

q:ask()
Flags

Sometimes you will need to remember a choice the player has made so that it can affect the story after a common section of the script. Let’s see an example.

We are going to extend the story of our game by adding a common section after q:ask():

hideText()
scene("black.png")

say "A week later..."

hideText()
scene("street day.png")

h "Great! I was able to pass all of the tests!"

There is a new function here, hideText. It does what the name suggests, it hides the box where the text of the game appears with an animation. I added it just for aesthetic purposes, it makes scene transitions look nicer.

Now, after this common section we want Sakura to thank Haru for helping her with maths only if the player chose to help her.

Up to this point, we’ve only used variables to give a name to the things we defined, but variables can store any kind of value. This time, we are going to create a variable called playerHelpedSakura and we are going to set its value to false, meaning that the player did not help sakura. Add this line to the beginning of the script:

playerHelpedSakura = false

After that, we are going to change its value to true, which means that the player did help sakura, in the help function we wrote before:

help = function()
    h "Okay, I will help you."
    sakura:show("happy")
    s "Really? Thanks!"
    h "No problem, it will help me review the subject."

    playerHelpedSakura = true
end

We can check the value of playerHelpedSakura after the common section using an if statement:

if playerHelpedSakura then
    sakura:show("happy")
    s "Me too!"
    sakura:show("smiling")
    s "Thank you for your help!"
    h "You're welcome!"
end

The block of script between then and end will only be run if the condition is true. We can also add a block of code that will only be run if the condition is false using else:

if playerHelpedSakura then
    sakura:show("happy")
    s "Me too!"
    sakura:show("smiling")
    s "Thank you for your help!"
    h "You're welcome!"
else
    h "I feel bad about refusing to help Sakura with maths."
    h "I hope she didn't fail the test because of that."
end
Ending the game

We’ve written a masterpiece with a deep, complex story, branching paths and stunning visuals, but right now, when the script ends the game just stops. Let’s fix that. Add this at the end of the script:

hideText()
scene("black.png")
sleep(1)
openScript("_start.lua")

Here, we hide the text and then fade to black. After that, we use a new function, sleep, to pause the game for 1 second while the screen is in black. Next, we use openScript to run the script _start.lua.

For now, as we’ve written the script of our game in _start.lua this will cause the game to restart, but we are going to change that in a moment.

Adding a main menu

Let’s add a main menu to the game. We want this menu to be the first thing the player sees when they launch the game, so we want to write the code for it in _start.lua. However that file already contains the script of our game, so go to the assets/scripts folder and rename _start.lua to game.lua. After that, create a new file called _start.lua and open it in your text editor.

Take a look at assets/images/gui/button.png. This image will be the background of the menu buttons. Actually, there are four backgrounds in that image, one for each possible button state. From left to right:

  • Up: when the player is not interacting with the button
  • Hover: when the mouse is over the button
  • Down: when the button is being pressed
  • Disabled: when the button is disabled and the player can’t interact with it

In order to create a menu, we first need to define the buttons in a similar way as we did with character sprites:

start = Button.new("button.png", 1, "Start")
exit = Button.new("button.png", 1, "Exit")

These two lines define buttons. Both of them use button.png as the background image, and their text will be “Start” and “Exit” respectively.

You might be wondering what that 1 means. It’s the layer of the button. While visual novels are 2D games, we still need to know which objects should be drawn on top of others. The background is at layer 0, character sprites are at layer 50, and these two buttons will be at layer 1.

Now that the buttons are defined we need to set their position with setPosition:

start:setPosition(489, 450)
exit:setPosition(489, 550)

We can display them on the screen using show:

scene("menu.png")

start:show()
exit:show()

Remember that using scene to change the background of the scene clears the screen, so we need to change the background before using show to display the buttons.

If you try to run the game now you will be able to interact with the menu. However, pressing the buttons does nothing. This is because we still need to define what happens when the player clicks on them. In order to do that, we are going to do something very similar to what we did when we wanted to present a choice to the player. We are going to define a function for each button:

start.onClick = function()
    scene("black.png")
    openScript("game.lua")
end

exit.onClick = function()
    scene("black.png")
    exitGame()
end

All buttons have a property called onClick. A property is a variable that belongs to an object. When we define a function and store it in the onClick property of a button, we are telling the game to run that function when the player clicks on that button.

Here, the first function will be run when the player clicks on the start button. This function will make the screen fade to black and then run the script game.lua. The second function will be run when the player clicks on the exit button and wil make the scene fade to black and then close the game with exitGame.

Here is the script so far:

start = Button.new("button.png", 1, "Start")
exit = Button.new("button.png", 1, "Exit")

start.onClick = function()
    scene("black.png")
    openScript("game.lua")
end

exit.onClick = function()
    scene("black.png")
    exitGame()
end

start:setPosition(489, 450)
exit:setPosition(489, 550)

scene("menu.png")
start:show()
exit:show()

If you run the game now everything should be working.

Releasing your game

Releasing your game is easy, you just need to distribute the files in your game folder to your players. You could zip them and give the zip to them or you could use a third party tool to create an installer. Remember that your players will need to have Visual C++ Redistributable 2015 in order to run the game.

It is possible to compile the scripts, which should improve performance slightly and add a layer of obfuscation. However, at this moment Iris Engine doesn’t provide the necessary tools to do that, so you will need to use a third party Lua compiler.

What’s next?

In this tutorial we’ve only scratched the surface. Here is a list of links you will find useful:

Language reference
A more in-depth view of the scripting language. Here you will learn how to write the scripts of your games.
Working with visuals
In this section you will learn how to create the visual part of your visual novel. Learn about sprites, transitions and animations.
API reference index
Here you will find detailed information about all the functions and classes at your disposal.
Examples and templates
Learn through examples. Here you can find full games made with Iris Engine you can use as a learning resource.
Full script

Here is the full script of the game.

_start.lua
start = Button.new("button.png", 1, "Start")
exit = Button.new("button.png", 1, "Exit")

start.onClick = function()
    scene("black.png")
    openScript("game.lua")
end

exit.onClick = function()
    scene("black.png")
    exitGame()
end

start:setPosition(489, 450)
exit:setPosition(489, 550)

scene("menu.png")
start:show()
exit:show()
game.lua
h = Character.new("Haru")
s = Character.new("Sakura")

playerHelpedSakura = false

sakura = CharacterSprite.new("sakura1.png")

scene("street day.png")

say "I'm on my way home from class."
say "There are more students than usual today."
say "I guess that makes sense, midterms are coming closer and all club activities have been suspended."

sakura:show("smiling")

s "Hi there, Haru! Are you going home now?"
h "Yes I am. I want to study for the midterms."

sakura:show("serious")

s "Well, about that... I wanted to ask you something."
h "What is it?"

sakura:show("normal")

s "Please, help me with maths."

help = function()
    h "Okay, I will help you."

    sakura:show("happy")

    s "Really? Thanks!"
    h "No problem, it will help me review the subject."

    playerHelpedSakura = true
end

dontHelp = function()
    sakura:show("nervious")

    h "Sorry, but that's my worst subject, I don't think I will be able to help."

    sakura:show("serious")

    s "Okay, no problem."
    s "I guess I will ask someone else."
end

q = Question.new({
    "Help her", help,
    "Don't help her", dontHelp
})

q:ask()

hideText()
scene("black.png")

say "A week later..."

hideText()
scene("street day.png")

h "Great! I was able to pass all of the tests!"

if playerHelpedSakura then
    sakura:show("happy")

    s "Me too!"

    sakura:show("smiling")

    s "Thank you for your help!"
    h "You're welcome!"
else
    h "I feel bad about refusing to help Sakura with maths."
    h "I hope she didn't fail the test because of that."
end

hideText()
scene("black.png")
sleep(1)
openScript("_start.lua")

Examples and templates

Templates

Trying to create config files and basic assets for your game completely from scratch can be hard, especially if it’s your first time doing so. These templates can help you getting started by providing a base you can customize to your needs.

Each template targets a common game resolution and comes with:

  • A config file with all the settings you need
  • An example folder structure for your project
  • A font you can use to render the text in your game
  • Necessary images to display the text window and choices menu
  • Some example transition images
  • An example icon
  • Some GUI sounds

You can download templates from the GitHub repo.

_images/downloads.png
Examples

Here are some complete games you can use as a learning resource:

Iris Engine showcase
A simple game showcasing all the basic features of the engine. It also includes a basic Pong minigame.
Exploration game (coming soon)
A more complex game with Ace Attorney-like exploration segments showing what is possible if you are familiar with the Lua programming language.

Language reference

Here you will learn how to write scripts for your games.

Iris Engine uses Lua as its scripting language, so if you are already familiar with it you can jump straight to the API Reference.

Warning

Iris Engine expects all scripts to be saved in UTF-8. Not doing so will cause problems with non-ASCII characters.

Language basics

The script of an Iris Engine game is usually written in several lua files. These files can be edited in any text editor, such as Sublime Text, Visual Studio Code, or Notepad++.

You can specify which script will be run first in the config file.

Comments

Comments are parts of the script that are ignored by the game. They will help you organize your scripts.

Comments start with a double hyphen (--) and run until the end of the line. A comment can also span multiple lines if it starts with --[[ and ends with ]]. Here is an example:

-- This line is a comment and will be ignored by the game
say "This part will be executed." -- This is a comment, too

--[[
This is a multiline comment.
All of this text will be ignored by the game.
]]

However, a comment may not be part of a string:

say "Hi. --This is not a comment and will be part of the narration."
Variables

Variables are a way of storing information for future use, and you will be using them a lot. You don’t have to worry about the details right now, as you will quickly learn how to use them as you go.

Variables can be created by assigning any value to a name using the = operator:

-- Create a variable called welcome that contains the text "Hi there!"
welcome = "Hi there!"

-- This will display the content of the variable as narration
say (welcome)

All variables are global by default. That means you can use and modify the value of the variable from any script in your game. You can limit the scope of a variable to a single script or block by using the local keyword.

-- This variable will only be known in the context it was defined
local welcome = "Hi there!"

If a variable is declared as local, other scripts will behave as if it didn’t exist, so they will be able to define another variable with the same name without modifying the original.

When a local and a global variable have the same name, the local one will take precedence.

Dialogue and narration

In visual novels, text may consist of narration, which does not have a speaker, and dialogue, which is labeled with the name of the character that is saying it.

The say function

In Iris Engine, narration is written using the say function. Here is an example of its usage:

say "This is narration."
say "You only need to write the 'say' keyword followed by the text in quotes."
say "Easy, right?"

After each call to the say function, the game will display the text on the screen and wait until the player clicks to dismiss it.

If your text contains quotation marks, you will need to precede them with a backslash (\) to prevent them from closing the string:

say "I saw a sign saying \"Mind the doors\"."

Alternatively, you can use single quotes to surround your text:

say 'I saw a sign saying "Mind the doors"'
String concatenation

Sometimes you will need to include the value of a variable in your narration. This can be achieved with the .. operator. Here is an example:

-- Variable
timesDefeated = 10

-- Say with string concatenation
say ("I was defeated " .. timesDefeated .. " times playing Rock–Paper–Scissors.")

This will be displayed as:

I was defeated 10 times playing Rock-Paper-Scissors.

Note

When calling the say function with anything that is not a literal string, such as a variable, a number, or the result of an operation like string concatenation, you will need to surround the argument in parentheses:

say (10)
say ("There are " .. 10 .. " things.")
welcome = "Hello!"
say (welcome)
Line breaks and long text

You can enforce a line break by inserting \n in the middle of a string. For example:

say "This line contains\na line break."

This will be displayed as:

This line contains
a line break.

If the text to display is too long to fit in the text window, the game will split it automatically as if you had written it using multiple calls to the say function.

Defining characters

In order to write dialogue, that is, text that is labeled with the name of the character that is saying it, you will need to create a Character object and store it in a variable. After that, you will be able to use that variable the same way as the say function. Here is an example:

-- Create Character objects for Haru and Sakura
h = Character.new("Haru")
s = Character.new("Sakura")

-- Display dialogue using the variables we defined above
h "Hi, my name is Haru."
s "And I am Sakura."

The name of a character can be modified at any point by assigning a new value to its name property:

-- Characters
h = Character.new("Haru")
s = Character.new("???")

-- Dialogue
s "Good morning!"   --> The name will be displayed as "???"
h "Hi. What's your name?"

s.name = "Sakura"

s ("My name is " .. s.name .. ". Nice to meet you.")

Choices, flags and control flow

Functions

Before we can talk about choices, we must first introduce the concept of functions.

Functions are like little snippets of code that we save in a variable so that we can execute them anytime we want. There are two equivalent ways to create functions:

-- We can create a function the same way we create variables
sayHello = function()
    say "Hello!"
    say "I'm narrating from a function."
end

-- Or we can use this other syntax, which will produce the same result
function anotherFunction()
    say "This is another function."
    say "It's called 'anotherFunction'."
end

If you try to run this script, you will see it doesn’t do anything. That is because we created the functions but we never executed them. In order to execute a function we need to call it using its name followed by (). Here is an example where we call two times one of the functions we just created:

say "I am going to say hello."
sayHello()
say "You didn't hear me? No problem, I will repeat it."
sayHello()

Note

There is a lot more you can do with functions, this is only a short and simplified introduction to the concept so that we can explain the next topic.

Choices

Many visual novels ask the player to make choices that influence the outcome of the story. In Iris Engine, this is done using Question objects.

In order to present a choice to the player, you will need to create a Question object and store it in a variable. Let’s see an example:

-- First, we define a function for each option
function drink()
    say "I'm thirsty too. I should have a drink."
end

function iceCream()
    say "Ice cream is probably the best option."
end

-- Then we create a Question object by giving it a list of options and
-- the corresponding functions to call when the player selects them
q = Question.new({
    "Have a drink", drink,
    "Have an ice cream", iceCream
})

-- We can ask the player by calling q:ask()
say "It's so hot here. What should I do?"
q:ask()

Note

The Question.new function takes a list of things as an argument. When this is the case, the parentheses are optional, so you can also write q = Question.new{ ... }. This will save you some typing.

Note

Note that when calling a function that works with an object, you will need to use the colon (:) operator instead of the dot (.) operator.

That is why at the end we use q:ask() instead of q.ask().

You can also define the functions and create the Question object at the same time like so:

-- This time, we will define the functions while creating the question
q = Question.new{
    "Have a drink", function()
        say "I'm thirsty too. I should have a drink."
    end,

    "Have an ice cream", function()
        say "Ice cream is probably the best option."
    end
}

-- Now we can ask the player to make the choice
say "It's so hot here. What should I do?"
q:ask()
Setting and checking flags

Sometimes you will need to remember a choice the player has made so that it can affect the story after a common section that will be the same regardless of what was chosen. This is usually done using flags.

In Iris Engine, flags are just global variables. For example, we can modify one of the functions of the previous example so that it sets a flag:

function iceCream()
    say "Ice cream is probably the best option."

    -- Here we set the flag to 'true'
    ateIceCream = true
end

We can then check the ateIceCream flag using an if statement:

if ateIceCream then
    -- This will be executed if ateIceCream was set to 'true'
    say "The ice cream I had yesterday was delicious."
else
    -- This will be executed if ateIceCream was set to 'false'
    say "That ice cream looked delicious."
    say "I should go get one."
end

Note

If the value of a variable has not been set to anything, it will be evaluated as if it were set to false.

Variables don’t have to be either true or false, they can store any kind of data. For example, let’s say your game includes a Rock–Paper–Scissors minigame and you store the number of times the player was defeated in a variable called timesDefeated. You can display a different dialogue depending on that number with something like this:

if timesDefeated == 0 then
    -- The player was defeated 0 times
    say "I'm the best Rock-Paper-Scissors player in the world."
elseif timesDefeated < 3 then
    -- The player has been defeated 1 or 2 times
    say "I didn't win every match, but overall it wasn't that bad."
else
    -- The player has been defeated 3 or more times
    say "Maybe I should quit this game."
end
Questions without functions

It is also possible to create a Question object without using functions. In fact, you can associate any kind of value to each option. After the call to the ask method, the answer property of your Question will contain the value associated to the choice selected by the player. This can be useful in some cases. For example, let’s implement a coin flipping minigame:

say "I have to choose heads or tails."

-- We will associate a number to each option
q = Question.new{
    "Heads", 0, -- A value of 0 will mean heads
    "Tails", 1  -- A value of 1 will mean tails
}

-- Ask the player to choose
q:ask()

-- Compare the answer with a randomly generated number between 0 and 1
if q.answer == math.random(0, 1) then
    say "¡I won!"
else
    say "¡No! ¡I lost!"
end
Labels and the goto statement

Labels allow you to assign a name to a specific point in a script. You can then use the goto statement to transfer the execution of the script to that point.

::first::
    say "This will be executed first."

::second::
    say "And this will follow next."

::third::
    say "Now we will jump to the second label and create an infinite loop."
    goto second

Unlike with function calls, there is no way to return to where you’ve jumped from.

Warning

The goto statement has the following restrictions:

  • Goto statements can’t be used to jump in or out of functions.
  • Goto statements can’t jump after the declaration of a local variable.

That means this will produce an error:

goto after -- Invalid jump
local a = 0
::after::

For more info, read this article from the Lua wiki.

API reference

Here you will find detailed information about all the functions and classes available to you and how to use them.

API reference index

Here you will find detailed information about all the functions, classes and enumerations you can use in your scripts.

Functions
The say function
Syntax:say(string text)
Returns:nil

This function is used to write narration, which consists of text that doesn’t have a speaker.

The given text will be displayed in the text window with a typewriter effect. After that, the execution of the script will be paused until the player clicks to dismiss it.

If the text contains a \n character, a line break will be inserted.

If the text to display is too long to fit in the text window, it will be splitted automatically as if you had written it using multiple calls to the say function.

Parameters
Type Name Description
string text The text to display as narration
Remarks

If the argument is a single literal string, the parentheses can be omitted, making a call to the function look like this: say "Text.". This will save you a lot of typing.

If the text window is hidden, it will be made visible with the transition specified in the config file.

Examples
-- Using the 'say' function with literal strings
say "This is narration."
say "As this is a single literal string, the parentheses can be omitted."
say "Easy, right?"

-- Using the 'say' function with variables and expressions
a = 10
b = "Hello!"
say("The value of a is " .. a .. ".")
say(b)
The append function
Syntax:append(string text)
Returns:nil

Adds new text to the text window without clearing what was already being displayed. After that, the execution of the script will be paused until the player clicks to dismiss it.

This function works with both dialogue and narration.

Parameters
Type Name Description
string text The text to append
Remarks

If the argument is a single literal string, the parentheses can be omitted, making a call to the function look like this: append "Text.". This will save you a lot of typing.

Examples
-- Using the 'append' function with narration
say "This is bad."
say "I shouldn't be here"
append ", should I?"
The hideText function
Syntax:hideText()
Returns:nil

This function is used to hide the text window with the transition specified in the config file. This will always be a blocking transition.

It is usually called before the transition to a new scene.

Remarks

The text window will remain hidden until new dialogue is displayed by using the say function or a Character object.

Examples
say "It's getting late."

-- Hide the text window
hideText()

-- Change the scene
scene("sky sunset.png")

-- Show the text window again
say "I should hurry."
The setTextAlign function
Syntax:setTextAlign(Position alignment)
Returns:nil

This function is used to specify the horizontal alignment of text in the text window.

Parameters
Type Name Description
Position alignment A value from the position enum indicating the horizontal alignment of the text
Remarks

Calling this function will set the horizontal aligment immediately, so you might get unwanted results if you don’t change the text being displayed after doing so. To avoid this, call this function just before displaying new text or while the text window is hidden.

Examples
setTextAlign(Position.center)
say "\nApril 27, 11:37 AM\nDistrict Court - Defendant Lobby No. 5"
hideText()
setTextAlign(Position.left)
The setBackground function
Syntax:setBackground(string image [, TransitionObject transition])
Returns:nil

This function is used to change the background image of the current scene.

Unlike the scene function, this has no effect on the rest of the objects of the scene, which will remain visible.

Parameters
Type Name Description
string image Path to the image to use as the new background; see remarks for details
TransitionObject transition Transition to use; se remarks for details
Remarks

The path of the image parameter must be relative to the backgrounds path specified in the config file.

If no transition is given, this one will be used by default:

{type=Transition.dissolve, time=0.5, block=false}

This function supports the following transition types:

  • Transition.none
  • Transition.dissolve
Examples
-- Start with a sunset
scene("street sunset.png")

say "It's getting late."

-- Slowly change the background to a night scene over the course of 400 seconds
setBackground("street night.png", {type=Transition.dissolve, time=400, block=false})

-- Continue with the script while the background changes
say "I should hurry."
The scene function
Syntax:
scene(string image, number time = 0.5)
scene(string image, TransitionObject transition)
Returns:nil

This function hides all the objects in the scene and then changes the background to the specified image.

Parameters
Type Name Description
string image Path to the image to use as the new background; see remarks for details
number time The duration in seconds of the default transition; see remarks for details
TransitionObject transition Transition to use; see remarks for details
Remarks

The path of the image parameter must be relative to the backgrounds path specified in the config file.

If no Transition object is given, this one will be used by default:

{type=Transition.dissolve, time=0.5, block=true}

If the second argument of the function is a number, a dissolve transition will be used. The number will determine the duration in seconds of the dissolve.

This function supports the following transition types:

  • Transition.none
  • Transition.dissolve
  • Transition.imageDissolve

Note

Scene transitions will always be blocking.

Examples
-- This will use a dissolve transition with a duration of 0.5 seconds
scene("sky.png")

-- This will use a dissolve transition with a duration of 1 second
scene("sky.png", 1)

-- This will use an imageDissolve transition with a duration of 1 second
scene("sky.png", {type=Transition.imageDissolve, image="left.png", time=1})
The disableSkip function
Syntax:disableSkip()
Returns:nil

After calling this function, holding the Ctrl key will not skip the dialogue. In addition, the player will not be able to skip blocking transitions.

Examples
disableSkip()

say "The player will not be able to skip this text with the 'Ctrl' key."

enableSkip()
The enableSkip function
Syntax:enableSkip()
Returns:nil

After calling this function, holding the Ctrl key will quickly advance the dialogue. In addition, the player will be able to skip blocking transitions by pressing left mouse button, the Enter key or by rotating the mouse wheel.

Skipping is enabled by default.

Examples
disableSkip()

say "The player will not be able to skip this text with the 'Ctrl' key."

enableSkip()
The disableMouseInput function
Syntax:disableMouseInput([number zindex])
Returns:nil

After calling this function, buttons and clickable maps will not accept mouse input. This means that the associated onMouseEnter, onMouseExit and onClick events will not be triggered even if the conditions are met.

Parameters
Type Name Description
number zindex Only objects below this z-index will not accept mouse input; see remarks for details
Remarks

Regardless of whether or not the mouse input is enabled, the player will be able to click to dismiss the text displayed on the text window.

Mouse input will be disabled automatically during scene transitions.

If a z-index is provided, this function will only have an effect in objects that are below that z-index. This is useful if you want to create a modal window, where the rest of the screen remains visible but the player can only interact with the content of said window.

Examples
disableMouseInput()

say "Buttons and clickable maps will not accept mouse input."

enableMouseInput()
The enableMouseInput function
Syntax:enableMouseInput()
Returns:nil

After calling this function, buttons and clickable maps will accept mouse input. This means that the associated onMouseEnter, onMouseExit and onClick events will be triggered when the conditions are met.

Mouse input is enabled by default.

Remarks

Regardless of whether or not the mouse input is enabled, the player will be able to click to dismiss the text displayed on the text window.

Mouse input will be disabled automatically during scene transitions.

Examples
disableMouseInput()

say "Buttons and clickable maps will not accept mouse input."

enableMouseInput()
The getMousePosition function
Syntax:getMousePosition()
Returns:number x, number y

Returns the position of the mouse.

Return values
Type Name Description
number x Distance in pixels from the left side of the screen to the mouse pointer
number y Distance in pixels from the top of the screen to the mouse pointer
Examples
-- Get the position of the mouse
x, y = getMousePosition()
The setCursor function
Syntax:setCursor(Cursor cursor)
Returns:nil

This function is used to change the mouse cursor.

Parameters
Type Name Description
Cursor cursor The new Cursor; see remarks for details
Remarks

Passing nil as the argument will change the cursor to the default system cursor.

Examples
-- Create a mouse cursor
pointer = Cursor.new("red arrow.png", 0, 0)

-- Change the mouse cursor to the one we just created
setCursor(pointer)

...

-- Restore the default system cursor
setCursor(nil)
The setOnRightClick function
Syntax:setOnRightClick(function event)
Returns:nil

Specifies a function to call whenever the player presses the right mouse button.

This can be useful when making custom menus. For example, you could use this function to close the menu when the player presses the right mouse button.

Parameters
Type Name Description
function event The function to call; see remarks for details
Remarks

Passing nil as the argument will disable this event, so pressing the right mouse button after that will do nothing. Call this function again to re-enable it.

Examples
-- You can use this function to close a custom menu
-- when the player presses the right mouse button
setOnRightClick(function()
    -- Hide the custom menu
    button1:hide()
    button2:hide()
    button3:hide()

    -- Disable onRightClick event
    setOnRightClick(nil)
end)
The playMusic function
Syntax:playMusic(string music)
Returns:nil

Starts playing the specified sound file. The music will loop until you start playing another file or call a function that stops it.

Parameters
Type Name Description
string music Path to the sound file to play; see remarks for details
Remarks

The path of the music parameter must be relative to the music path specified in the config file.

Examples
-- Start playing BGM01.ogg
playMusic("BGM01.ogg")

...

-- Stop the music with a fade
fadeOutMusic(1)
The fadeInMusic function
Syntax:fadeInMusic(string music, number seconds)
Returns:nil

Starts playing the specified sound file with a fade effect. The music will loop until you start playing another file or call a function that stops it.

The fade-in effect only applies to the first loop.

Parameters
Type Name Description
string music Path to the sound file to play; see remarks for details
number seconds Seconds for the fade-in effect to complete
Remarks

The path of the music parameter must be relative to the music path specified in the config file.

Examples
-- Start playing BGM01.ogg with a fade-in effect of 3 seconds
fadeInMusic("BGM01.ogg", 3)

...

-- Stop the music with a fade
fadeOutMusic(1)
The stopMusic function
Syntax:stopMusic()
Returns:nil

Abruptly stops playback of music.

Examples
-- Start playing BGM01.ogg with a fade-in effect of 3 seconds
fadeInMusic("BGM01.ogg", 3)

...

-- Stop the music
stopMusic()
The fadeOutMusic function
Syntax:fadeOutMusic(number seconds)
Returns:nil

Gradually fade out the music over the specified seconds.

Parameters
Type Name Description
number seconds Seconds for the fade-out effect to complete
Examples
-- Start playing BGM01.ogg with a fade-in effect of 3 seconds
fadeInMusic("BGM01.ogg", 3)

...

-- Stop the music with a fade-out effect of 1 second
fadeOutMusic(1)
The playSound function
Syntax:playSound(string sound)
Returns:nil

Plays the specified sound file once. There can be multiple sounds playing at the same time.

Parameters
Type Name Description
string sound Path to the sound file to play; see remarks for details
Remarks

The path of the sound parameter must be relative to the sounds path specified in the config file.

Examples
-- Play splash.ogg and surprise.ogg at the same time
playSound("splash.ogg")
playSound("surprise.ogg")
The stopSound function
Syntax:stopSound(string sound)
Returns:nil

Stops all sounds that were loaded using the specified path.

If the playSound function is called multiple times with the same argument, the same sound can be played more than once at the same time. The stopSound function will stop all of them.

Parameters
Type Name Description
string sound Path to the sound file to stop; see remarks for details
Remarks

The path of the sound parameter must be relative to the sounds path specified in the config file.

Examples
-- Play sound
playSound("people talking.ogg")

say "There is a lot of noise here."

-- Stop the sound
stopSound("people talking.ogg")

-- This dialogue will be shown at the same time the sound stops
say "Silence, please."
The yield function
Syntax:yield()
Returns:nil

Suspends the execution of the script until the next frame, producing the same result as a call to sleep(0).

This is useful as Iris Engine can’t redraw the screen and execute a Lua script at the same time, so having a loop in your script that doesn’t call any blocking functions will make the game appear to be frozen.

With the yield function you can tell the engine to update the state of the objects and redraw the screen, allowing you to extend the game loop with your own custom code. This is most useful for custom minigames and such.

It can also be used to hide the framerate drops that occur when loading new images by forcing the game to wait one frame before starting any animations.

Examples
-- Create a sprite
ball = Sprite.new("ball.png", 1)
ball:show()

while true do
    -- Place the sprite in a random position
    ball:setPosition(math.random(10, 50), math.random(10, 50))

    -- Let the engine render the screen
    yield()
end
The sleep function
Syntax:sleep(number seconds)
Returns:nil

Pauses the execution of the script for the specified number of seconds. This is useful to create dramatic pauses, show an image that will stay on screen for a certain amount of time, etc.

This pause will behave as a blocking transition, so the player can skip it by clicking the mouse. This can be disabled with the disableSkip function.

Parameters
Type Name Description
number seconds Number of seconds to wait; see remarks for details
Remarks

The sleep function will pause the execution of the script for at least the given number of seconds. Depending on external circumnstances such as framerate or load, the actual elapsed time might be longer.

The minimum ammount of time this function can wait is the time it takes to render a frame, so calling sleep(0) will pause the execution of the script until the next frame.

Examples
-- Fade to black, wait 1 second and show the next background
scene("black.png")
sleep(1)
scene("sky.png")
The getDeltaSeconds function
Syntax:getDeltaSeconds()
Returns:number elapsedSeconds

Returns the number of seconds elapsed since the last execution of Lua code.

This can be used in combination with the yield function to extend the game loop with your own custom code, allowing you to create minigames where the speed of the game does not depend on the frame rate.

You can also use this function to know how much time the player spent reading a certain line or making a certain decision.

Return values
Type Name Description
number elapsedSeconds The time elapsed since the last execution of lua code; see remarks for details
Remarks

The value returned is the number of seconds elapsed from the beginning of the last Lua execution to the beginning of the current Lua execution.

Examples
-- Create a question
q = Question.new{
    "Have a drink", 0,
    "Have an ice cream", 1
}

-- Ask the player what to do
say "What should I do?"
q:ask()

-- Get the time elapsed since q:ask() was called
-- This works because q:ask is a blocking function (see glossary for details)
elapsedTime = getDeltaSeconds()
say ("You have spent " .. elapsedTime .. " seconds making that decision.")
The openScript function
Syntax:openScript(string file)
Returns:This function does not return

This function will open and run the specified script. This script may be in source form or precompiled.

The openScript function is similar to a goto statement in that the execution will never return to the point where it was called from. This means that if there is any code below a call to this function, it will never get executed.

Note

All visible objects in the scene except for the background will be hidden. This might change in a future release.

Warning

The path to the script may not contain any non-ASCII characters. This is not the case for images or sounds and will be fixed in a future release.

Parameters
Type Name Description
string file Path to the script; see remarks for details
Remarks

The path of the file parameter must be relative to the scripts path specified in the config file.

Examples
-- Open the script "chapter01.lua"
openScript("chapter01.lua")

-- This code will never be executed
say "The player will not read this."
The exitGame function
Syntax:exitGame()
Returns:This function does not return

Calling this function will immediately close the game.

Examples
-- Create a button to quit the game
local closeBtn = Button.new("closeBtn.png", 50)
closeBtn:setPosition(0, 552)

-- The function to call when the user presses the button
closeBtn.onClick = function()
    -- Fade to black and stop the music
    fadeOutMusic(2)
    scene("black.png", 2)

    -- Quit the game
    exitGame()
end

-- Show the button so that the player can press it
closeBtn:show()
The saveScreenshot function
Syntax:saveScreenshot(string path, number width, number height)
Returns:nil

Takes a screenshot of the game and saves it to a file.

Parameters
Type Name Description
string path Where to save the image; see remarks for details
number width The width in pixels of the image to save
number height The height in pixels of the image to save
Remarks

The screenshot will be stretched to fit the provided resolution.

The format of the image will be deduced from the extension of the provided filename. Supported formats are: png, bmp and tga.

Examples
-- Save a screenshot as "screenshot.png"
-- The resolution of the saved image will be 1280x720
saveScreenshot("screenshot.png", 1280, 720)
The precacheImage function
Syntax:precacheImage(string image)
Returns:nil

Iris Engine will load assets the first time they are needed. However, as loading takes time, this can cause framerate drops during gameplay. To avoid this, you can enable precaching in the config file, which will make the engine preload images automatically when any object that uses them is defined.

There are, however, some images that will never be preloaded automatically, such as character expressions. In cases where this is an issue, you can use the precacheImage function to manually preload any image.

Keep in mind that preloading doesn’t remove the framerate drop, it just makes it easier to hide. Use this function just before a call to sleep or yield and the player won’t be able to notice the drop.

Parameters
Type Name Description
string image Path to the image to preload
Remarks

If precaching is enabled, there is usually no need to use this function. It’s here in case you observe performance issues during playtesting.

Examples
-- Fade to black
scene("black.png")

-- Take advantage of the scene transition to preload some images
precacheImage("assets/images/characters/sakura2.png")
precacheImage("assets/images/characters/sakura2 smiling.png")

-- Wait 1 second before showing the next background
sleep(1)
scene("sky.png")

Narration

Function Description
say Display narration text
append Add text to the currently displayed line
hideText Hide the text window
setTextAlign Set text alignment

Visuals

Function Description
setBackground Change the background image
scene Transition to a new scene

User input

Function Description
disableSkip Disable Ctrl functionality and make blocking transtions unskippable
enableSkip Enable Ctrl functionality and make blocking transitions skippable
disableMouseInput Disable elements that accept mouse input such as buttons
enableMouseInput Enable elements that accept mouse input such as buttions
getMousePosition Get the position of the mouse
setCursor Change the cursor icon
setOnRightClick Specify a function to call when the player presses the right mouse button

Sound

Function Description
playMusic Start playing background music
fadeInMusic Start playing background music with a fade
stopMusic Stop playing background music
fadeOutMusic Stop playing background music with a fade
playSound Play a sound
stopSound Stop a sound

Game control

Function Description
yield Pause Lua execution until the next frame
sleep Pause Lua execution for the specified time
getDeltaSeconds Get the number of seconds elapsed since the last execution of Lua
openScript Transfer execution to the specified script
exitGame Close the game
saveScreenshot Save a screenshot of the game to a file

Caching

Function Description
precacheImage Precache the specified image
Classes
The Character class

In visual novels, text may consist of narration, which does not have a speaker, and dialogue, which is labeled with the name of the character that is saying it.

In Iris Engine, dialogue is written using Character objects. Once defined, these objects can be used in the same way as the say function. See Defining characters for a quick explanation on how to use them.

Properties
The name property

Gets or sets the text that will be displayed as the name of the character in the text window when this character speaks.

Examples
-- Characters
h = Character.new("Haru")
s = Character.new("???")

-- Dialogue
s "Good morning!"   --> The name will be displayed as "???"
h "Hi. What's your name?"

-- Set the name to "Sakura"
s.name = "Sakura"

s ("My name is " .. s.name .. ". Nice to meet you.")
--> The text displayed will be: "My name is Sakura. Nice to meet you."
Type Name Default value Description
string name Defined in constructor Gets or sets the name of the character
Member functions
Character constructor
Syntax:Character.new(string name)

Constructs a Character object with the specified name.

Parameters
Type Name Description
string name The name of the character used for dialogue
Examples
-- Create Character objects for Haru and Sakura
h = Character.new("Haru")
s = Character.new("Sakura")

-- Display dialogue using the variables we defined above
h "Hi, my name is Haru."
s "And I am Sakura."
The __call metamethod
Syntax:character(string text)
Returns:nil

The __call metamethod allows you to treat a Character object like a function. This allows you to use a Character object in the same way as the say function to write dialogue, which consists of text labeled with the name of the character that is saying it.

The given text will be displayed in the text window with a typewriter effect. After that, the execution of the script will be paused until the player clicks to dismiss it.

If the text contains a \n character, a line break will be inserted.

If the text to display is too long to fit in the text window, it will be splitted automatically as if you had written it using multiple calls to the metamethod.

Parameters
Type Name Description
string text The text to display as dialogue
Remarks

If the argument is a single literal string, the parentheses can be omitted, making a call to the method look like this: character "Text.". This will save you a lot of typing.

If the text window is hidden, it will be made visible with the transition specified in the config file.

Examples
-- Create Character objects for Haru and Sakura
h = Character.new("Haru")
s = Character.new("Sakura")

-- Display dialogue using the variables we defined above
h "Hi, my name is Haru."
s "And I am Sakura."

-- Using this metamethod with variables and expressions
a = 10
b = "Hello!"
h("The value of a is " .. a .. ".")
s(b)
Method Description
(constructor) Create a character
__call metamethod Display dialogue text
The Question class

Many visual novels ask the player to make choices that influence the outcome of the story. In Iris Engine, this can be done using Question objects. Let’s see an example:

-- First, we define a function for each option
function drink()
    say "I'm thirsty too. I should have a drink."
end

function iceCream()
    say "Ice cream is probably the best option."
end

-- Then we create a Question object by giving it a list of options and
-- the corresponding functions to call when the player selects them
q = Question.new{
    "Have a drink", drink,
    "Have an ice cream", iceCream
}

-- We can ask the player by calling q:ask()
say "It's so hot here. What should I do?"
q:ask()

In order to create a Question object, you will need to specify the list of options the player can choose. This is done using a table that contains exactly two entries for each option: a string with the text of the button, and a value to associate to that option. In the previous example that value was a function with the code to execute if the player selects that option, but this value can be anything, including numbers, booleans, objects, strings and so on.

The choice is presented to the player using the ask method. After the call to this method has returned, the answer property of the object will contain the value associated with the option that the player selected. If this value was a function, that function will be called automatically.

Properties
The answer property

After a call to the ask method, gets the value associated to the option selected by the player.

Warning

The value of this property before a call to the ask method is undefined.

Examples
say "I have to choose heads or tails."

-- We will associate a number to each option
q = Question.new{
    "Heads", 0, -- A value of 0 will mean heads
    "Tails", 1  -- A value of 1 will mean tails
}

-- Ask the player to choose
q:ask()

-- Check the answer
result = q.asnwer  -- Will be '0' if the player selected "Heads"
                   -- or '1' if the player selected "Tails"
The removeAfterSelection property

Gets or sets whether or not options should be removed from the Question object in subsequent calls to the ask method after the player selects them.

This can be used, for example, in games where the player is required to ask a set of questions to a character and is able to decide in which order to ask them.

Examples
-- Create a Question object
q = Question.new{
    "Let's talk about the weather", 0,
    "Are you a cat or a dog person?", 1,
    "Let's talk about the sociopolitical situation", 2
}

-- Remove options after the player selects them
q.removeAfterSelection = true

-- Let the player select an option until there are no more options to select
while q.count > 0 do
    -- Text of the question
    s "What do you want to talk about?"

    -- Show the choices to the player
    q:ask()
end
The count property

Gets the number of options the player will be able to select when the ask method is called.

Examples
-- Create a Question object
q = Question.new{
    "Let's talk about the weather", 0,
    "Are you a cat or a dog person?", 1,
    "Let's talk about the sociopolitical situation", 2
}
--> At this moment, q.count is 3

-- Remove options after the player selects them
-- This will decrease the value of q.count each time the player selects an option
q.removeAfterSelection = true

-- Let the player select an option until there are no more options to select
while q.count > 0 do
    -- Text of the question
    s "What do you want to talk about?"

    -- Show the choices to the player
    q:ask()
end
Type Name Default value Description
any answer undefined Gets the value associated with the option selected by the player
bool removeAfterSelection false Gets or sets whether or not options should be removed after the player selects them
count count   Gets the number of options in a Question
Member functions
Question constructor
Syntax:Question.new(table choices)

Constructs a Question object with the specified choices.

Parameters
Type Name Description
table choices A list of options the player can choose from; see remarks for details
Remarks

The list of options must be a table that contains exactly two entries for each option in the following order:

Type Name Description
string text The text that will be displayed in the menu for this option
any value A value of any type associated to this option

The choice is presented to the player using the ask method. After the call to this method has returned, the answer property of the object will contain the value associated with the option that the player selected. If this value was a function, that function will be called automatically.

When the argument of a function is a single table the parentheses can be omitted, so instead of Question.new({ ... }), you can use Question.new{ ... }.

Examples

Question object where the value associated to each option is a function:

-- First, we define a function for each option
function drink()
    say "I'm thirsty too. I should have a drink."
end

function iceCream()
    say "Ice cream is probably the best option."
end

-- Then we create a Question object by giving it a list of options and
-- the corresponding functions to call when the player selects them
q = Question.new{
    "Have a drink", drink,
    "Have an ice cream", iceCream
}

-- We can ask the player by calling q:ask()
say "It's so hot here. What should I do?"
q:ask()
-- The function corresponding to the selected option will be called automatically

An alternative way to create the same Question object:

-- This time, we will define the functions while creating the question
q = Question.new{
    "Have a drink", function()
        say "I'm thirsty too. I should have a drink."
    end,

    "Have an ice cream", function()
        say "Ice cream is probably the best option."
    end
}

-- Now we can ask the player to make the choice
say "It's so hot here. What should I do?"
q:ask()

Question object where the value associated to each option is not a function:

-- Language selector
local q = Question.new{
    "日本語", "ja/",
    "English", "en/",
    "Español", "es/"
}

-- Ask the player to select a language
q:ask()

-- Save the selected language in a global variable
-- so that all scripts can check it
lang = q.answer
--> Will be "ja/", "en/" or "es/" depending on the option selected by the player
The ask method
Syntax:ask()
Returns:nil

This method is used to show the player a menu with the options of this question.

The execution of the script will be paused until the player has slected one of the options, after which the answer property will contain the value associated with the option the player selected. If this value was a function, that function will be called automatically.

The appearance of the menu can be customized in the config file.

Examples
-- First, we define a function for each option
function drink()
    say "I'm thirsty too. I should have a drink."
end

function iceCream()
    say "Ice cream is probably the best option."
end

-- Then we create a Question object by giving it a list of options and
-- the corresponding functions to call when the player selects them
q = Question.new{
    "Have a drink", drink,
    "Have an ice cream", iceCream
}

-- We can ask the player by calling q:ask()
say "It's so hot here. What should I do?"
q:ask()
Method Description
(constructor) Create a Question object
ask Present the choice to the player
The Sprite class

The Sprite class is used to display images on the screen. See Working with visuals for a quick explanation on how to use them.

Properties
The visible property

Gets whether or not the sprite is currently visible on the screen.

Examples
-- Create a Sprite object
ball = Sprite.new("ball.png", 1)
--> ball.visible is 'false'

-- Show the sprite
ball:show()
--> ball.visible is 'true'

-- Hide the sprite
ball:hide({type=Transition.fade, time=0.3, block=true})
--> ball.visible is 'false' after the transition has finished
Type Name Default value Description
bool visible false Gets whether or not the sprite is currently being shown in the screen
Member functions
Sprite constructor
Syntax:Sprite.new(string image, number zindex)

Constructs a Sprite object using the provided image with the specified z-index.

This sprite will be placed at coordinates (0, 0), and its origin will be the top left corner of the image.

Parameters
Type Name Description
string image Path to the image to use as sprite; see remarks for details
number zindex The z-index of this sprite
Remarks

The path of the image parameter must be relative to the sprites path specified in the config file.

Examples
-- Create a Sprite object
ball = Sprite.new("ball.png", 1)
The show method
Syntax:show([TransitionObject transition])
Returns:nil

This method is used to make the sprite appear on the screen.

Parameters
Type Name Description
TransitionObject transition Transition to use; se remarks for details
Remarks

If no transition is given, this one will be used by default:

{type=Transition.fade, time=0.3, block=false}

This method supports the following transition types:

  • Transition.none
  • Transition.fade
Examples
-- Create a Sprite object
ball = Sprite.new("ball.png", 1)

-- Make it appear on the screen with the default transition
ball:show()

...

-- Show the sprite using a blocking fade transition with a duration of 5 seconds
ball:show({type=Transition.fade, time=5, block=true})
The hide method
Syntax:hide([TransitionObject transition])
Returns:nil

This method is used to make the sprite disappear from the screen.

Parameters
Type Name Description
TransitionObject transition Transition to use; se remarks for details
Remarks

If no transition is given, this one will be used by default:

{type=Transition.fade, time=0.3, block=false}

This method supports the following transition types:

  • Transition.none
  • Transition.fade
Examples
-- Create a Sprite object
ball = Sprite.new("ball.png", 1)

-- Make it appear on the screen
ball:show()

...

-- Stop showing the sprite on the screen
ball:hide()

-- Hide the sprite using a blocking fade transition with a duration of 5 seconds
ball:hide({type=Transition.fade, time=5, block=true})
The setAlpha method
Syntax:setAlpha(number alpha)
Returns:nil

Sets the opacity of the sprite.

Parameters
Type Name Description
number alpha A number in the range [0, 255], where 0 is completely transparent and 255 the original opacity
Remarks

If alpha is greater than 0, the sprite will be made visible.

Calling this function will skip any fade transition currently taking place for this sprite.

Calling show or hide will restore the alpha value to 255.

Examples
-- Create a Sprite object
ball = Sprite.new("ball.png", 1)

-- Set the alpha to 100
ball:setAlpha(100)
The skipTransition function
Syntax:skipTransition()
Returns:nil

This method is used to instantly finish any transitions currently affecting this object, including fades and movement animations started with the move method.

Remarks

As blocking transitions pause the execution of the script, it is only possible to skip non-blocking transitions using this method.

Examples
-- Create a Sprite object and show it
ball = Sprite.new("ball.png", 1)
ball:show()

-- Start a non blocking movement animation with a duration of 10 seconds
ball:move(1000, 0, 10, false)

-- Wait 5 seconds
sleep(5)

-- Instantly finish the animation
ball:skipTransition()
The setPosition method
Syntax:setPosition(number x, number y)
Returns:nil

This method is used to set the position of the sprite.

Parameters
Type Name Description
number x Distance in pixels from the left side of the screen
number y Distance in pixels from the top of the screen
Remarks

The exact pixel of the image that lands in the provided position is called the origin. You can change the origin of a sprite with the setOrigin method.

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Create a sprite
ball = Sprite.new("ball.png", 1)

-- Place it in the position (50, 60)
ball:setPosition(50, 60)
The getPosition method
Syntax:getPosition()
Returns:number x, number y

This method returns the current position of the sprite.

Return values
Type Name Description
number x Distance in pixels from the left side of the screen
number y Distance in pixels from the top of the screen
Examples
-- Create a sprite and place it in the position (50, 60)
ball = Sprite.new("ball.png", 1)
ball:setPosition(50, 60)

-- Get its position with the getPosition method
x, y = ball:getPosition()
--> Now, x = 50 and y = 60
The setOrigin method
Syntax:setOrigin(number x, number y)
Returns:nil

When a sprite is in a certain position, the exact pixel of the image that lands in that position is called the origin. By default, the origin of a sprite is in its top left corner, but you can change it using this method.

You can see how the origin affects the position of a sprite in the following image:

_images/origin_example.png
Parameters
Type Name Description
number x Distance in pixels from the left side of the image
number y Distance in pixels from the top of the image
Examples
-- Create a sprite
ball = Sprite.new("ball.png", 1)

-- Set the origin of the sprite
ball:setOrigin(60, 60)
The move method
Syntax:
move(
number x,
number y,
number time,
bool shouldBlock,
Interpolator interpolator = Interpolator.easeInOut
)
Returns:nil

Use this method to start a movement animation where the sprite will move from its current position to the specified position over time.

Parameters
Type Name Description
number x The x location of the position you want the sprite to move to
number y The y location of the position you want the sprite to move to
number time The duration in seconds of the movement animation
bool shouldBlock Whether or not this animation should be a blocking transition
Interpolator interpolator Interpolator function to use
Remarks

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Create and show a Sprite
ball = Sprite.new("ball.png", 1)
ball:show()

-- Move the ball sprite from its current position to (1112, 81) using an ease-out interpolator
-- This animation will have a duration of 2 seconds and will be a blocking transition
ball:move(1112, 81, 2, true, Interpolator.easeOut)

-- Move the ball back to its starting position using the default interpolator
ball:move(1112, 81, 2, true)
The defineSpriteSheet method
Syntax:defineSpriteSheet(number frameCount, number cols, number rows, number fps)
Returns:nil

Tell the engine to treat the image of the sprite as a sprite sheet. For example, this image

_images/sprite_sheet.png

results in the following animation:

_images/animated_sprite.gif
Parameters
Type Name Description
number frameCount The number of frames of the animation
number cols The number of columns the sprite sheet has
number rows The number of rows the sprite sheet has
number fps The framerate of the animation in frames per second
Remarks

If the framerate is 0, the animation won’t play and you will be able to manually set which frame to display using the setFrame function.

Examples
-- Create an sprite using the previous sprite sheet as the image
animated = Sprite.new("sprite sheet.png", 1)

-- Define the properties of the sprite sheet
-- 89 frames, 13 columns, 7 rows, 60 FPS
animated:defineSpriteSheet(89, 13, 7, 60)

-- Show the animated sprite
animated:show()
The setFrame method
Syntax:setFrame(number frame)
Returns:nil

If this object has been defined as a sprite sheet using defineSpriteSheet, this method can be used to manually set the current frame of the animation.

This is more useful when the framerate of the animation is 0.

Parameters
Type Name Description
number image The index of the frame to display, should be an integer in the range [0, NumberOfFrames - 1]
Examples
-- We have a sprite sheet where each frame contains a number from 0 to 9
counter = Sprite.new("numbers.png", 1)
counter:defineSpriteSheet(10, 10, 1, 0)

-- With setFrame, we can display the digit we want
-- Display the number 3
counter:setFrame(3)
Method Description
(constructor) Create a Sprite object
show Make the sprite visible
hide Make the sprite invisible
setAlpha Set the opacity of the sprite
skipTransition Instantly finish any transition affecting this object
setPosition Set the position of the sprite
getPosition Get the position of the sprite
setOrigin Set the origin of the sprite
move Start a movement animation
defineSpriteSheet Animate this sprite as a sprite sheet
setFrame Manually set the current frame of the sprite sheet animation
The Button class

This class is used to create buttons the player can interact with using the mouse.

Buttons are actually sprites, which means you can use methods like move to animate them, but they offer additional functionality to handle mouse input.

In order to create a button you will need an image like this:

_images/exit_btn.png

This image includes the four possible states of a button:

  • Up: when the player is not interacting with the button
  • Hover: when the mouse is over the button
  • Down: when the button is being pressed
  • Disabled: when the player is not allowed to interact with the button

In the previous example we’ve included the text of the button in the image itself, but this is not necessary, as this class allows you to add a string of text on top of the image.

You can control the actions that will be performed when the player interacts with the button using the properties defined below.

Properties
The enabled property

Sets wheter the player is able to interact with this button.

If set to false, the button will visually indicate to the player that it’s disabled.

Examples
-- Create a button
exit = Button.new("exit button.png", 50)
exit:setPosition(0, 552)

-- Disable and show it
exit.enabled = false
exit:show()
The onMouseEnter property

Sets a function to execute when the mouse enters this button.

If set to nil, this event will be disabled.

Examples
-- Create a button
exit = Button.new("exit button.png", 50)
exit:setPosition(0, 552)

-- This function will be executed when the mouse enters the button
-- In this case, we will close the game
exit.onMouseEnter = function()
    -- Stop the music and fade to black
    fadeOutMusic(2)
    scene("black.png", 2)

    -- Quit the game
    exitGame()
end

-- Show the button so that the player can interact with it
exit:show()
The onMouseExit property

Sets a function to execute when the mouse leaves this button.

If set to nil, this event will be disabled.

Examples
-- Create a button
exit = Button.new("exit button.png", 50)
exit:setPosition(0, 552)

-- This function will be executed when the mouse leaves the button
-- In this case, we will close the game
exit.onMouseExit = function()
    -- Stop the music and fade to black
    fadeOutMusic(2)
    scene("black.png", 2)

    -- Quit the game
    exitGame()
end

-- Show the button so that the player can interact with it
exit:show()
The onClick property

Sets a function to execute when the player clicks this button.

If set to nil, this event will be disabled.

Examples
-- Create a button
exit = Button.new("exit button.png", 50)
exit:setPosition(0, 552)

-- This function will be executed when the player clicks the button
-- In this case, we will close the game
exit.onClick = function()
    -- Stop the music and fade to black
    fadeOutMusic(2)
    scene("black.png", 2)

    -- Quit the game
    exitGame()
end

-- Show the button so that the player can interact with it
exit:show()
Type Name Default value Description
bool enabled true Sets whether or not the player can interact with the button
function onMouseEnter nil Sets the function to call when the mouse enters the button
function onMouseExit nil Sets the function to call when the mouse leaves the button
function onClick nil Sets the function to call when the player clicks the button

The Button class inherits all of the properties of the Sprite class.

Member functions
Button constructor
Syntax:
Button.new(string image, number zindex, bool verticalLayout = false)
Button.new(string image, number zindex, string text, bool verticalLayout = false)
Button.new(
string image,
number zindex,
string text,
bool verticalLayout,
table font,
table disabledColor,
table disabledShadowColor
)

Constructs a Button object using the provided background image.

Parameters
Type Name Description
string image The background image of the button; see remarks for details
number zindex The z-index of this sprite
string text The text of the button
bool verticalLayout Whether the layout of the background image is vertical; see remarks for details
table font The font to use to render the text of the button; see remarks for details
table disabledColor The color of the text when the button is disabled; see remarks for details
table disabledShadowColor The color of the shadow of the text when the button is disabled; see remarks for details
Remarks

The path of the image parameter must be relative to the gui path specified in the config file.

The provided image should include the background for the four possible states of a button in the following order:

  • Up: when the player is not interacting with the button
  • Hover: when the mouse is over the button
  • Down: when the button is being pressed
  • Disabled: when the player is not allowed to interact with the button

If verticalLayout is false, the engine expect them to be aligned horizontally, like in this example:

_images/exit_btn.png

If verticalLayout is true, they should be aligned vertically, like this:

_images/question_btn.png

You can specify the font to use to render the text of the game with a table with the following fields:

Type Name Description
string file Path to the font file
number size The point size (based on 72 DPI) of the font
table color A table with the fields r, g, b and a (alpha) specifying the color of the text
number shadowDistance Distance in pixels of the drop shadow. If 0, no shadow will be drawn.
table shadowColor A table with the fields r, g, b and a (alpha) specifying the color of the text shadow

Here is an example:

{
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

If no font is specified, the text will be rendered using the same settings as the text window.

The arguments disabledColor and disabledShadowColor should be tables with the fields r, g, b and a (alpha).

Examples
-- Create a button with horizontal layout and no text
button1 = Button.new("exit_btn.png", 1)

-- Create a button with vertical layout and no text
button2 = Button.new("choices_BG.png", 1, true)

-- Create a button with horizontal layout and the text "Start"
button3 = Button.new("start_btn.png", 1, "Start")

-- Create a button with vertical layout and the text "Go to school"
button4 = Button.new("choices_BG.png", 1, "Go to school", true)

-- Create a button with horizontal layout and a custom font
local exampleFont = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

button5 = Button.new("button.png", 1, "Text", false, exampleFont, {r=255, g=255, b=255, a=255}, {r=0, g=0, b=0, a=0})
Method Description
(constructor) Create a Button object

The Button class inherits all of the methods of the Sprite class except defineSpriteSheet and setFrame.

The Text class

This class is used to display text on the screen outside of the text window.

Objects of this class behave like sprites, which means you can use methods like move to animate them.

Properties
The ellipsis property

If the Text object has a maximum size, the text might be too long to fit. In such cases, the string set in this property will be apended to the displayed text so that the player is aware of this fact.

Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create a Text object
local text = Text.new(font, 1)

-- Set a max size and the text to display
text:setText("This is the text to display")
text:setMaxSize(160, 1)
text:show()

-- Set the ellipsis string (the default value is "...")
text.ellipsis = "--"

-- The player will see the following text:
-- "This is the te--"
The spacing property

Sets the line spacing in pixels. This will be added to the recommended line spacing of your font, which it’s usually a few more pixels than necessary for lines to not overlap. Negative numbers bring lines together.

Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create a Text object
local text = Text.new(font, 1)

-- Set a max size and the text to display
text:setText("This is the text to display")
text:setMaxSize(160, 0)
text:show()

-- Set the line spacing so that lines are a bit closer
text.spacing = -5
Type Name Default value Description
string ellipsis “…” Sets the ellipsis string to use when the text is truncated
number spacing 0 Sets the spacing of the lines

The Text class inherits all of the properties of the Sprite class.

Member functions
Text constructor
Syntax:Text.new(table font, number zindex)

Constructs a Text object.

This object will be placed at coordinates (0, 0), and its origin will be the top left corner.

Parameters
Type Name Description
table font Properties of the font to use to render the text; see remarks for details
number zindex The z-index of this sprite
Remarks

The font argument must be a table with the following fields:

Type Name Description
string file Path to the font file
number size The point size (based on 72 DPI) of the font
table color A table with the fields r, g, b and a (alpha) specifying the color of the text
number shadowDistance Distance in pixels of the drop shadow. If 0, no shadow will be drawn.
table shadowColor A table with the fields r, g, b and a (alpha) specifying the color of the text shadow
Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create text object
text = Text.new(font, 1)

-- Set the text and show the object
text:setText("This is an example")
text:show()
The setText method
Syntax:setText(string text)
Returns:nil

Sets the string to display by this Text object.

Parameters
Type Name Description
string text The text to display
Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create text object
text = Text.new(font, 1)

-- Set the text and show the object
text:setText("This is an example")
text:show()
The setMaxSize method
Syntax:setMaxSize(number width, number height)
Returns:nil

Sets a maximum size in pixels for the text.

The text will be split in lines or truncated so that it fits the specified size.

Parameters
Type Name Description
number width The maximum width in pixels; see remarks for details
number height The maximum height in pixels; see remarks for details
Remarks

Specifying a value of 0 for either width or height will disable this feature for that axis, allowing the text to grow infinitely.

Regardless of the maximum height specified, the Text class will always display at least one line of text, so setting this value to 1 is an easy way to limit the height of the text to one line.

Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create a Text object
local text = Text.new(font, 1)

-- Set the text to display
text:setText("This is the text to display")

-- Set the maximum size to 160 pixels horizontally
-- and one line of text vertically
text:setMaxSize(160, 1)

-- Set the maximum size to 160 pixels horizontally
-- and 500 pixels vertically
text:setMaxSize(160, 500)
The getCurrentTextSize method
Syntax:getCurrentTextSize()
Returns:number width, number height

Returns the size in pixels of the text currently being displayed. This is not the maximum size you can specify with the setMaxSize method, but the actual size of the text.

Return values
Type Name Description
number width The width in pixels of the longest line
number height The height in pixels of the text
Examples
-- Font properties
font = {
    file = "assets/fonts/Roboto-Medium.ttf",
    size = 28,
    color = {r = 255, g = 255, b = 255, a = 255},
    shadowDistance = 0,
    shadowColor = {r = 0, g = 0, b = 0, a = 0}
}

-- Create a Text object
local text = Text.new(font, 1)

-- Set the text to display
text:setText("This is the text to display")

-- Set the maximum size of the text
text:setMaxSize(160, 0)

-- Get the size
width, height = text:getCurrentTextSize()

-- The values returned are
-- width = 134
-- height = 99
Method Description
(constructor) Create a Text object
setText Set the text to display
setMaxSize Set the maximum size of the text box
getCurrentTextSize Get the size of the text currently being displayed

The Text class inherits all of the methods of the Sprite class except defineSpriteSheet and setFrame.

The Rectangle class

This class is used to draw filled rectangles on the sreen.

Objects of this class behave like sprites, which means you can use methods like move to animate them.

Properties

The Text class inherits all of the properties of the Sprite class.

Member functions
Rectangle constructor
Syntax:Rectangle.new(number zindex)

Constructs a Rectangle object.

This object will be placed at coordinates (0, 0), and its origin will be the top left corner.

Parameters
Type Name Description
number zindex The z-index of this sprite
Examples
-- Create a rectagle
rect = Rectangle.new(3)

-- Set color and size
rect:setColor({r = 255, g = 0, b = 0, a = 255})
rect:setSize(15, 55)

-- Show it
rect:show()
The setSize method
Syntax:setSize(number width, number height)
Returns:nil

Sets the size of the rectangle.

Parameters
Type Name Description
number width The width in pixels
number height The height in pixels
Examples
-- Create a rectagle
rect = Rectangle.new(3)

-- Set color, size and position
rect:setColor({r = 255, g = 0, b = 0, a = 255})
rect:setSize(15, 55)
rect:setPosition(50, 50)

-- Show it
rect:show()
The setColor method
Syntax:setColor(table color)
Returns:nil

Sets the color of the rectangle.

Parameters
Type Name Description
table color The color; see remarks for details
Remarks

The color argument should be a table with the following fields:

Type Name Description
number r The red value in the range [0, 255]
number g The green value in the range [0, 255]
number b The blue value in the range [0, 255]
number a The alpha value in the range [0, 255]
Examples
-- Create a rectagle
rect = Rectangle.new(3)

-- Set color, size and position
rect:setColor({r = 255, g = 0, b = 0, a = 255})
rect:setSize(15, 55)
rect:setPosition(50, 50)

-- Show it
rect:show()
Method Description
(constructor) Create a Rectangle object
setSize Set the size of the rectangle
setColor Set the color of the rectangle

The Rectangle class inherits all of the methods of the Sprite class except defineSpriteSheet and setFrame.

The Video class

This class is used to play video files.

Objects of this class behave like sprites, which means you can use methods like move to animate them.

Important

Audio bitrate must be 44100 kHz, otherwise the audio will sound distorted.

Properties

The Video class inherits all of the properties of the Sprite class.

Member functions
Video constructor
Syntax:Video.new(string file, bool playAudio, bool shouldLoop, number zindex)

Constructs a Video object.

This object will be placed at coordinates (0, 0), and its origin will be the top left corner.

Videos will start buffering as soon as they are constructed. Try to allow some time for the beginning of the video to buffer before starting playback to avoid stuttering. Half a second is usually enough.

Parameters
Type Name Description
string file Path to the video file; see remarks for details
bool playAudio Whether to play the audio track of this video; see remarks for details
bool shouldLoop Whether the video should loop after it finishes playing
number zindex The z-index of the video
Remarks

The path of the file parameter must be relative to the videos path specified in the config file.

If audio playback is enabled, the audio track of the video will replace the current music, which will be paused while the video is playing. This does not affect other sounds. It is not possible to play the audio track of more than one video at the same time.

Important

Audio bitrate must be 44100 kHz, otherwise the audio will sound distorted.

Examples
-- Create video object
-- We want to play the video with sound, and we only want it to play once
local opening = Video.new("op.ogv", true, false, 1)

-- Make some time so that the video can buffer before we start playing it
say "This is the opening of the game."
hideText()

-- Show the video
opening:show({type=Transition.none})

-- Start playback
opening:play(true)
The play method
Syntax:play(bool shouldBlock)
Returns:nil

Starts video playback.

Tip

Use the show method to make the video visible before starting playback.

Parameters
Type Name Description
bool shouldBlock Whether to block script execution until the video has finished playing
Remarks

If audio playback is enabled, the audio track of the video will replace the current music, which will be paused while the video is playing. This does not affect other sounds. It is not possible to play the audio track of more than one video at the same time.

Important

Audio bitrate must be 44100 kHz, otherwise the audio will sound distorted.

The video will be hidden automatically when it finishes playing.

Examples
-- Create video object
-- We want to play the video with sound, and we only want it to play once
local opening = Video.new("op.ogv", true, false, 1)

-- Make some time so that the video can buffer before we start playing it
say "This is the opening of the game."
hideText()

-- Show the video
opening:show({type=Transition.none})

-- Start playback
opening:play(true)
The stop method
Syntax:stop()
Returns:nil

Stops video playback and hides the video object.

Examples
-- Create video object
local opening = Video.new("op.ogv", true, false, 1)

-- Start playback
opening:show({type=Transition.none})
opening:play(false)

-- Wait 5 seconds and stop the video
sleep(5)
opening:stop()
The waitUntilFinished method
Syntax:waitUntilFinished()
Returns:nil

Blocks the execution of the script until the video has finished playing.

Calling this method after the video has finished playing will not have any effects.

Examples
-- Create video object
local opening = Video.new("op.ogv", true, false, 1)

-- Start playback
opening:show({type=Transition.none})
opening:play(false)

-- Show some text to the player
say "This text will be shown while the video is playing."
hideText()

-- Once the player has read the text, wait until the video finishes playing
video:waitUntilFinished()
Method Description
(constructor) Create a Video object
play Starts video playback
stop Stops video playback
waitUntilFinished Blocks the execution of the script until the video has finished playing

The Video class inherits all of the methods of the Sprite class except defineSpriteSheet and setFrame.

The CharacterSprite class

The CharacterSprite class is used to display images of your characters on the screen. It offers functionality to make showing the characters of your games with different expressions easier.

See Working with visuals for an explanation on how to use them.

Member functions
CharacterSprite constructor
Syntax:
CharacterSprite.new(
string baseImage,
Position position = Position.center
[, number zindex]
)
CharacterSprite.new(
string baseImage,
table positionVector,
[, number zindex]
)

Constructs a CharacterSprite object.

The origin of character sprites is located at the bottom center of the sprite, as this makes it easier to align them with the bottom of the screen.

Parameters
Type Name Description
string baseImage Path to the image to use as the base of the character sprite; see remarks for details
Position position The Position of the character sprite; see remarks for details
table positionVector A vector with the position of the sprite; see remarks for details
number zindex The z-index of this character sprite; see remarks for details
Remarks

The path of the baseImage parameter must be relative to the characters path specified in the config file.

You can specify the position of the character sprite using the Position enum or a table. If you use the Position enum, the bottom of the character sprite will be aligned with the bottom of the screen. Additionally:

  • Position.left will align the left side of the character sprite with the left side of the screen
  • Position.center will center the sprite horizontally
  • Position.right will align the right side of the character sprite with the right side of the screen

Alternatively, you can use a table to specify the exact coordinates of your character sprite. For example, if you want to place the sprite at coordinates (100, 700), you can use the following table: {x=100, y=700}. Keep in mind that the origin of character sprites is located at the bottom center of the sprite.

If the zindex parameter is not specified, the engine will use the default z-index for characters defined in the config file.

Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Define a character sprite centered on the screen and with a z-index of 200
sakura = CharacterSprite.new("sakura2.png", Position.center, 200)

-- Define a character sprite using a table to set its position
sakura = CharacterSprite.new("sakura2.png", {x=29, y=700})
The show method
Syntax:show(string expression [, TransitionObject transition])
Returns:nil

This method is used to change the expression of the character sprite. If the sprite was not visible, this method will make it visible.

Parameters
Type Name Description
string expression The facial expression of the characer sprite; see remarks for details
TransitionObject transition Transition to use; se remarks for details
Remarks

If the expression base for this character is sakura1.png and the provided expression is smiling, the expression image that will be drawn is sakura1 smiling.png. In this example, the name of the base image and the name of the expression have been connected with a space character to form the final filename of the expression image, but you can alter this behavior in the config file.

If no transition is given, these ones will be used by default:

-- If the character sprite was not visible
{type=Transition.fade, time=0.3, block=false}

-- If the character sprite was visible
{type=Transition.dissolve, time=0.3, block=false}

This method supports the following transition types:

  • Transition.none
  • Transition.fade (if the character sprite is not visible)
  • Transition.dissolve (if the character sprite is visible)
Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Make it visible with a smile expression
sakura:show("smiling")
say "I'm smiling now."

-- Change the expression of the character sprite while it's visible
sakura:show("normal")
say "And this is my neutral expression."

-- Change the expression using a blocking dissolve transition
sakura:show("laughing", {type=Transition.dissolve, time=0.3, block=true})
say "And now I'm laughing."
The hide method
Syntax:hide([TransitionObject transition])
Returns:nil

This method is used to make the character sprite disappear from the screen.

Parameters
Type Name Description
TransitionObject transition Transition to use; se remarks for details
Remarks

If no transition is given, this one will be used by default:

{type=Transition.fade, time=0.3, block=false}

This method supports the following transition types:

  • Transition.none
  • Transition.fade
Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Make it visible with a smile expression
sakura:show("smiling")
say "I'm smiling now."

-- Hide it using the default transition
sakura:hide()
The setBase method
Syntax:
setBase(
string baseImage,
string expressionBase,
string expression
[, TransitionObject transition]
)
setBase(
string baseImage,
string expression
[, TransitionObject transition]
)
Returns:nil

This methods allows you to change the base image of a character sprite at any time, even if it’s visible.

Note

In the current version of the engine, the new base image must have the same resolution as the previous one, otherwise one of the images will be stretched during the transition.

Parameters
Type Name Description
string baseImage Path to the image to use as the base of the character sprite; see remarks for details
string expressionBase The base image of the set of expressions to use; see remarks for details
string expression The facial expression of the characer sprite; see remarks for details
TransitionObject transition Transition to use; se remarks for details
Remarks

The path of the baseImage and expressionBase parameters must be relative to the characters path specified in the config file.

The base image that will be drawn is the one specified in the baseImage parameter. The expressionBase parameter specifies the base image used when constructing the filenames of expression images, allowing you to use the set of expressions corresponding to a different base image than the one you want to use to draw the character.

If the expressionBase is sakura1.png and the provided expression is smiling, the expression image that will be drawn is sakura1 smiling.png. In this example, the name of the base and the name of the expression have been connected using a space character to form the final filename of the expression image. This behavior can be altered in the config file.

The version of this method that does not take a expressionBase parameter will not change the expression base of the character sprite. That means that the previous expression base will be used when constructing filenames.

If no transition is given, this one will be used by default:

{type=Transition.dissolve, time=0.3, block=false}

This method supports the following transition types:

  • Transition.none
  • Transition.dissolve

If the character sprite is not visible, the transition parameter will be ignored.

Examples
-- Define a character sprite that uses sakura1.png as the base image
sakura = CharacterSprite.new("sakura1.png")
sakura:show("smiling")

...

-- Change the base to sakura2.png and use the set of expressions of sakura2.png
sakura:setBase("sakura2.png", "sakura2.png", "smiling")

-- Change the base to sakura3.png but keep using the set of expressions of sakura2.png
sakura:setBase("sakura3.png", "smiling")

-- Do the same using a blocking dissolve transition
sakura:setBase("sakura3.png", "smiling", {type=Transition.dissolve, time=0.3, block=true})
The setColorLUT method
Syntax:setColorLUT(string colorLUT, number time)
Returns:nil

A Lookup Table (LUT) image can be used to apply color correction to a character sprite. This allows you to alter the color of your characters so that they match the lightning conditions of the background.

_images/colorGradingExample.png

You can also create other interesting effects such as drawing your characters in grayscale.

In order to create a LUT image, you’ll need an image editing application such as Photoshop or GIMP.

  1. Open a representative image of your game in this application and use adjustment layers to apply any color grading effects you want for your character.

  2. Once you’ve achieved your desired look, open a copy of the Neutral Color LUT on its own.

    • _images/neutralLUT.png

      Neutral Color LUT (right-click and Save as)

  3. Copy the adjustment layers to the Neutral Color LUT. This way, you will apply those color grading effects to this image.

  4. Now, save your LUT with a new name. Any character sprites that use this LUT for color grading will receive the same color grading effects you applied to the image.

If your image editing application doesn’t support adjustment layers, you’ll need to apply the color grading effects directly to the Neutral Color LUT.

Parameters
Type Name Description
string colorLUT The color lookup table image to use; see remarks for details
number time The duration in seconds of the color grading transition
Remarks

The path of the colorLUT parameter must be relative to the luts path specified in the config file.

Color grading transitions are always non-blocking. If you call this method while a color grading transition is taking place, that transition will be finished instantly before starting the new one.

Examples
-- Define a character sprite
sakura = CharacterSprite.new("sakura1.png")

-- Show the background and the sprite without color grading
scene("street day.png")
sakura:show("normal")
say "Day."

-- Change the background to an evening setting at the same time
-- we change the color grading of our character
setBackground("street evening.png")
sakura:setColorLUT("evening.png", 0.5)
say "Evening."

-- Change the background to a night setting at the same time
-- we change the color grading of our character
setBackground("street night.png")
sakura:setColorLUT("night.png", 0.5)
say "Night."
The disableColorGrading method
Syntax:disableColorGrading(number time)
Returns:nil

Disable color grading effects for this character sprite.

Parameters
Type Name Description
number time The duration in seconds of the color grading transition
Remarks

Color grading transitions are always non-blocking. If you call this method while a color grading transition is taking place, that transition will be finished instantly before starting the new one.

Examples
-- Define a character sprite
sakura = CharacterSprite.new("sakura1.png")

-- Show a night background and the character sprite with color grading
scene("street night.png")
sakura:setColorLUT("night.png", 0)
sakura:show("normal")
say "Night."

-- Change the background to a day setting at the same time
-- disable color grading for our character
setBackground("street day.png")
sakura:disableColorGrading(0.5)
say "Day."
The skipTransition function
Syntax:skipTransition()
Returns:nil

This method is used to instantly finish any transitions currently affecting this object (except for color grading transitions), including fades and movement animations started with the move method.

Remarks

As blocking transitions pause the execution of the script, it is only possible to skip non-blocking transitions using this method.

Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Make it visible with a smile expression
sakura:show("smiling")

-- Start a non blocking movement animation with a duration of 10 seconds
sakura:moveX(0, 10, false)

-- Wait 5 seconds
sleep(5)

-- Instantly finish the animation
sakura:skipTransition()
The setPosition method
Syntax:
setPosition(number x, number y)
setPosition(Position position)
Returns:nil

This method is used to set the position of the character sprite.

Parameters
Type Name Description
number x Distance in pixels from the left side of the screen
number y Distance in pixels from the top of the screen
Position position The Position of the character sprite; see remarks for details
Remarks

The exact pixel of the image that lands in the provided position is called the origin. The origin of character sprites is located at the bottom center of the sprite.

If you use the Position enum, the bottom of the character sprite will be aligned with the bottom of the screen. Additionally:

  • Position.left will align the left side of the character sprite with the left side of the screen
  • Position.center will center the sprite horizontally
  • Position.right will align the right side of the character sprite with the right side of the screen

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Set its position to (29, 700)
sakura:setPosition(29, 700)

-- Set its position to the center of the screen
sakura:setPosition(Position.center)
The setX method
Syntax:setX(number x)
Returns:nil

Most of the time you will only need to move the character sprite horizontally. This method allows you to set the x position of the sprite, while the y position will be automatically calculated so that the bottom of the sprite is aligned with the bottom of the screen.

Parameters
Type Name Description
number x Distance in pixels from the left side of the screen
Remarks

The exact pixel of the image that lands in the provided position is called the origin. The origin of character sprites is located at the bottom center of the sprite.

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

-- Set its horizontal position
sakura:setX(100)
The move method
Syntax:
move(
number x,
number y,
number time,
bool shouldBlock,
Interpolator interpolator = Interpolator.easeInOut
)
move(
Position position,
number time,
bool shouldBlock,
Interpolator interpolator = Interpolator.easeInOut
)
Returns:nil

Use this method to start a movement animation where the character sprite will move from its current position to the specified position over time.

Parameters
Type Name Description
number x The x location of the position you want the sprite to move to
number y The y location of the position you want the sprite to move to
Position position The position you want the sprite to move to; see remarks for details
number time The duration in seconds of the movement animation
bool shouldBlock Whether or not this animation should be a blocking transition
Interpolator interpolator Interpolator function to use
Remarks

The exact pixel of the image that lands in the provided position is called the origin. The origin of character sprites is located at the bottom center of the sprite.

If you use the Position enum, the bottom of the character sprite will be aligned with the bottom of the screen. Additionally:

  • Position.left will align the left side of the character sprite with the left side of the screen
  • Position.center will center the sprite horizontally
  • Position.right will align the right side of the character sprite with the right side of the screen

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Define a character sprite and make it visible
sakura = CharacterSprite.new("sakura1.png")
sakura:show("smiling")

-- Move the sprite from its current position to (80, 700) using an ease-in-out interpolation
-- This animation will have a duration of 1 second and will be a blocking transition
sakura:move(80, 700, 1, true)

-- Move the sprite to the right side of the screen using an ease-out interpolation
-- This animation will have a duration of 1 second and will be a non-blocking transition
sakura:move(Position.right, 1, false, Interpolator.easeOut)
The moveX method
Syntax:
moveX(
number x,
number time,
bool shouldBlock,
Interpolator interpolator = Interpolator.easeInOut
)
Returns:nil

Most of the time you will only need to move the character sprite horizontally. This method allows you to move the character sprite along the x axis. The final y position of the movement will be automatically calculated so that the bottom of the sprite is aligned with the bottom of the screen.

Parameters
Type Name Description
number x The x location of the position you want the sprite to move to
number time The duration in seconds of the movement animation
bool shouldBlock Whether or not this animation should be a blocking transition
Interpolator interpolator Interpolator function to use
Remarks

The exact pixel of the image that lands in the provided position is called the origin. The origin of character sprites is located at the bottom center of the sprite.

Warning

While this method allows you to use non-integer coordinates, keep in mind that if a sprite is not aligned with the pixel grid it will look blurry due to anti-aliasing.

Examples
-- Define a character sprite and make it visible
sakura = CharacterSprite.new("sakura1.png")
sakura:show("smiling")

-- Move the sprite from its current position to x=80 using an ease-in-out interpolation
-- This animation will have a duration of 1 second and will be a blocking transition
sakura:moveX(80, 1, true)

-- Move the sprite to x=500 using an ease-out interpolation
-- This animation will have a duration of 1 second and will be a non-blocking transition
sakura:moveX(500, 1, false, Interpolator.easeOut)
The setExpressionBase method
Syntax:setExpressionBase(string expressionBase)
Returns:nil

Let’s say you have a base image called “sakura3.png” that should use the same expression images as “sakura2.png”. The setExpressionBase method allows you to do that.

Parameters
Type Name Description
string expressionBase The base image of the set of expressions to use; see remarks for details
Remarks

The path of the expressionBase parameter must be relative to the characters path specified in the config file.

The expressionBase parameter specifies the base image used when constructing the filenames of expression images, allowing you to use the set of expressions corresponding to a different base image than the one you want to use to draw the character.

Error

Using this method while the character sprite is visible will result in an error.

Examples
-- Define a character sprite that uses "sakura2.png" as the base image
sakura = CharacterSprite.new("sakura2.png")

-- Set "sakura1.png" as the expression base
sakura:setExpressionBase("sakura1.png")

-- Show the character sprite using "sakura2.png" as the base image
-- and "sakura1 smiling.png" as the expression image
sakura:show("smiling")
Method Description
(constructor) Create a CharacterSprite object
show Change the expression of a character and make it visible
hide Make the character sprite invisible
setBase Set the base image of the character sprite
setColorLut Set the color LUT to use for color grading
disableColorGrading Disable color grading for this character sprite
skipTransition Instantly finish any transition affecting this object
setPosition Set the position of the sprite
setX Set the position of the sprite while aligning it with the bottom of the screen
move Start a movement animation
moveX Start a movement animation where the end position is aligned with the bottom of the screen
setExpressionBase Set the base image that will be used when searching for expression images
The Cursor class

This class, in combination with the setCursor function allows you to use custom mouse cursors in your game.

Member functions
Cursor constructor
Syntax:Cursor.new(string image, number hotX, number hotY)

Constructs a Cursor object with the specified image.

Parameters
Type Name Description
string image The path to the cursor image; see remarks for details
number hotX The x position of the cursor hot spot
number hotY The y position of the cursor hot spot
Remarks

The path of the image parameter must be relative to the gui path specified in the config file.

Examples
-- Create a mouse cursor
pointer = Cursor.new("red arrow.png", 0, 0)

-- Change the mouse cursor to the one we just created
setCursor(pointer)

...

-- Restore the default system cursor
setCursor(nil)
Method Description
(constructor) Create a cursor object
The ClickableMap class

Clickable maps allow you to define several regions on the screen that the player will be able to click. This is done using an image in which each region is represented with a different color.

For example, let’s say we have the following background in our game showing three drawers:

_images/drawers.png

If we want the player to be able to click on the drawers to see what’s inside them, we can create a clickable map using the following image:

_images/drawers_map.png

As you can see, each one of the drawers is represented in the second image with a different color: red, green and blue, respectively. These will be the clickable regions of our map.

If there are two separate regions with the same color, the engine will treat them as if they were the same region.

Warning

Make sure your drawing program does not apply anti-aliasing to the border of the regions of the image, as this will alter the color of the pixels around the borders and will cause problems.

Important

Save your images in PNG, BMP or any other image format with lossless compression. JPEG is NOT suitable for this type of images as the compression can alter the color of the regions.

Now, all we have to do is create the clickable map like so:

-- Show the background with the drawers to the player
scene("drawers.png")

-- Create a clickable map using the previous image
map = ClickableMap.new("drawers_map.png")

And then, define the function that will be executed when the player clicks on each region:

-- Define the function to call when the player clicks a region with
-- the color rgb(255, 0, 0)
map:setOnClick(255, 0, 0, function()
    say "This is the first drawer."
    hideText()
end)

-- Define the function to call when the player clicks a region with
-- the color rgb(0, 255, 0)
map:setOnClick(0, 255, 0, function()
    say "This is the second drawer."
    hideText()
end)

-- Define the function to call when the player clicks a region with
-- the color rgb(0, 0, 255)
map:setOnClick(0, 0, 255, function()
    say "This is the third drawer."
    hideText()
end)

Now that the clickable map is defined, we can let the player interact with it:

-- Enable the clickable map
map:enable()

Once the player clicks on a region the map will be disabled automatically. If you want the player to be able to interact with this map again you will need to call map:enable() again. You can use a loop for this:

-- The player will be able to examine all of the drawers as many times as they want
-- In fact, it will be the only thing they will be able to do in this game
while true do
    map:enable()
end

You can use any color you want for the regions, and if you only use the red channel (the green and blue channels are set to 0), there is a shorter version of setOnClick that only requires you to give a value for that channel:

-- Define the function to call when the player clicks a region with
-- the color rgb(255, 0, 0)
map:setOnClick(255, function()
    say "This is the first drawer."
    hideText()
end)
Properties
The disableOnClick property

If set to true, the clickable map will be disabled automatically when the player clicks on a region. This will prevent the player from clicking on another region while the function for that region is being executed.

The clickable map will only be disabled if there is a function associated with the region the player clicked.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Set disableOnClick to false
map.disableOnClick = false
The nonBlocking property

By default, the enable method is a blocking function, which means that the execution of the script is paused until the clickable map is disabled. However, if nonBlocking is set to true, the execution of the script will not be paused while the map is enabled.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Set nonBlocking to true
map.nonBlocking = true
Type Name Default value Description
bool disableOnClick true Sets whether the clickable map will be disabled automatically after the player clicks a region
bool nonBlocking false Sets whether the execution of the script should be paused while the clickable map is enabled
Member functions
ClickableMap constructor
Syntax:ClickableMap.new(string image)

Constructs a ClickableMap object with the specified image.

Parameters
Type Name Description
string image Path to the image describing the regions; see remarks for details
Remarks

The path of the image parameter must be relative to the gui path specified in the config file.

In this image, each region must be represented using a different color. All of the pixels of the image with the same color will be considered part of the same region.

This image must have the same resolution as the window of your game. The pixels outside the window of the game are considered as black: rgb(0, 0, 0).

Warning

Make sure your drawing program does not apply anti-aliasing to the border of the regions of the image, as this will alter the color of the pixels around the borders and will cause problems.

Important

Save your images in PNG, BMP or any other image format with lossless compression. JPEG is NOT suitable for this type of images as the compression can alter the color of the regions.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")
The enable method
Syntax:enable()
Returns:nil

This method is used to allow the player to interact with a ClickableMap object.

If the nonBlocking property is set to false, the execution of the script will be paused until the clickable map is disabled.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

...

-- Enable the clickable map
map:enable()
The disable method
Syntax:disable()
Returns:nil

This method is used to disable a ClickableMap object.

After a call to this method, the player will not be able to interact with the clickable map.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Disable the map when the mouse enters a region
-- with the color rgb(255, 0, 0)
map:setOnMouseEnter(255, function()
    map:disable()
end)

-- Enable the map
map:enable()

-- map:enable() is a blocking function, so this text will only
-- show up after the map has been disbled
say "The clickable map has been disabled."
The setOnMouseEnter method
Syntax:
setOnMouseEnter(number r, number g, number b, function function)
setOnMouseEnter(number r, function function)
Returns:nil

Sets a function to execute when the mouse enters a region with the specified color.

Parameters
Type Name Description
number r Red component of the color of the region; see remarks for details
number g Green component of the color of the region
number b Blue component of the color of the region
function function The function to execute; see remarks for details
Remarks

If the function parameter is nil, this event will be disabled.

The second overload of this function only requires the red component of the color. This will save you some typing for regions where the green and blue channels are set to 0.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Play a sound when the mouse enters a region
-- with the color rgb(255, 0, 0)
map:setOnMouseEnter(255, function()
    playSound("hover.ogg")
end)

-- Enable the map
map:enable()
The setOnMouseExit method
Syntax:
setOnMouseExit(number r, number g, number b, function function)
setOnMouseExit(number r, function function)
Returns:nil

Sets a function to execute when the mouse leaves a region with the specified color.

Parameters
Type Name Description
number r Red component of the color of the region; see remarks for details
number g Green component of the color of the region
number b Blue component of the color of the region
function function The function to execute; see remarks for details
Remarks

If the function parameter is nil, this event will be disabled.

The second overload of this function only requires the red component of the color. This will save you some typing for regions where the green and blue channels are set to 0.

Examples
-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Play a sound when the mouse leaves a region
-- with the color rgb(255, 0, 0)
map:setOnMouseExit(255, function()
    playSound("hover.ogg")
end)

-- Enable the map
map:enable()
The setOnClick method
Syntax:
setOnClick(number r, number g, number b, function function)
setOnClick(number r, function function)
Returns:nil

Sets a function to execute when the player clicks on a region with the specified color.

Parameters
Type Name Description
number r Red component of the color of the region; see remarks for details
number g Green component of the color of the region
number b Blue component of the color of the region
function function The function to execute; see remarks for details
Remarks

If the function parameter is nil, this event will be disabled.

If the disableOnClick property is set to true, the map will be disabled automatically before the provided function is executed. This is only true for regions where this event is enabled (the function is not nil).

The second overload of this function only requires the red component of the color. This will save you some typing for regions where the green and blue channels are set to 0.

Examples
-- Show a background with three drawers to the player
scene("drawers.png")

-- Create a clickable map
map = ClickableMap.new("drawers_map.png")

-- Define the function to call when the player clicks a region with
-- the color rgb(255, 0, 0)
map:setOnClick(255, 0, 0, function()
    say "This is the first drawer."
    hideText()
end)

-- Define the function to call when the player clicks a region with
-- the color rgb(0, 255, 0)
map:setOnClick(0, 255, 0, function()
    say "This is the second drawer."
    hideText()
end)

-- Define the function to call when the player clicks a region with
-- the color rgb(0, 0, 255)
map:setOnClick(0, 0, 255, function()
    say "This is the third drawer."
    hideText()
end)

-- Enable the clickable map
map:enable()
Method Description
(constructor) Create a ClickableMap object
enable Enable the clickable map
disable Disable the clickable map
setOnMouseEnter Set the function to call when the mouse enters the specified region
setOnMouseExit Set the function to call when the mosue leaves the specified region
setOnClick Set the function to call when the player clicks the specified region
Class Description
Character A character that can be used for dialogue
Question Used to present a choice to the player
Sprite An image that can be drawn on the screen
Button A button the user can click
Text Used to draw text on the screen
Rectangle Used to draw a filled rectangle on the screen
Video A video player
CharacterSprite An image that represents a character
Cursor A mouse cursor icon
ClickableMap Used to make certain areas of the screen clickable
Enumerations
The Position enum

An enumeration of horizontal positions used to align text and character sprites to the screen.

Values
Value
Position.left
Position.center
Position.right
The Transition enum

An enumeration of transitions used to create TransitionObjects.

Values
Value
Transition.none
Transition.fade
Transition.dissolve
Transition.imageDissolve
Remarks

In Iris Engine, transitions are defined using Lua tables. For a table to correctly define a transition, it must associate the type key to one of the values of the Transition enum. In addition, each transition type may require additional keys to be given a value. These keys are the parameters of the transition.

Here is a description of each transition type and its required parameters.

Transition.none

No transition, the change will be instant. It doesn’t require additional parameters.

Example:

{type=Transition.none}
Transition.fade

Used to make objects appear or disappear from the screen. The opacity of the object will gradually change over time. Here are the required parameters:

Type Name Description
number time The duration in seconds of the transition
bool block Whether this transition is a blocking transition

Example:

{type=Transition.fade, time=0.3, block=false}
Transition.dissolve

Used to smoothly transition from one image to another.

Here are the required parameters:

Type Name Description
number time The duration in seconds of the transition
bool block Whether this transition is a blocking transition

Example:

{type=Transition.dissolve, time=0.5, block=false}
Transition.imageDissolve

A dissolve transition controlled with a grayscale image, where black pixels in the control image dissolve first and white pixels dissolve last. Here is a video showing some examples. The control image used is shown in the top right corner.

Here are the required parameters:

Type Name Description
number time The duration in seconds of the transition
bool block Whether this transition is a blocking transition
string image Path to the control image, relative to the transitions path specified in the config file

Example:

{type=Transition.imageDissolve, time=1, image="wipe right.png", block=true}
The Interpolator enum

An enumeration of interpolation functions used to control the acceleration of some effects.

Values
Value Description
Interpolator.linear Constant speed
Interpolator.easeIn Slow start
Interpolator.easeOut Slow end
Interpolator.easeInOut Slow start and end
Remarks

The following video shows the differences between these interpolation functions:

Enumeration Description
Position Used to align text and character sprites on the screen
Transition Types of transitions
Interpolator Interpolation functions

Working with visuals

What’s a visual novel without images? In this section you will learn how Iris Engine handles the visual part of visual novels.

Tip

It is highly recommended that you read the section Language reference before this one.

Backgrounds

The action of your novel will probably take place somewhere. This is usually shown to the player by drawing an image that fills the entire screen behind the characters. These images are called backgrounds.

Note

In the current version of the engine all backgrounds must have the same resolution. This will be fixed in a future release.

Using the scene function to change the background

Most of the time, when you need to change the background it’s because the action is moving to a different place, so you also need to hide the rest of the objects that are currently being shown in the screen. In those cases, you can use the scene function.

This function will hide all the objects in the screen and change the background image. Here is an example of its usage:

-- Change the background to the image "sky.png"
scene("sky.png")

Iris Engine searches for background images in the folder specified in the config file.

By default, this function will change the background using a dissolve transition with a duration of 0.5 seconds that looks like this:

We can modify the duration of the transition adding a second parameter to the function:

-- This will use a dissolve transition with a duration of 1.5 seconds
scene("sky.png", 1.5)

However, we can also use the scene function with other types of transitions. This is done by passing a transition object as the second parameter of the function.

A transition object is just a set of parameters in curly brackets ({}) that describe a transition. Let’s some examples:

-- We must specify the type of transition we want to use
-- If we use 'Transition.none', no transition will be used
-- and the background switch will be instant
scene("sky day.png", {type=Transition.none})

-- Other types of transitions require extra parameters:
-- Use a dissolve transition with a duration of 1.5 seconds
scene("street day.png", {type=Transition.dissolve, time=1.5})
--> This produces the same result as 'scene("street day.png", 1.5)'

Tip

You can read more about transition objects and types in the following page: The Transition enum.

The imageDissolve transition

There is a special type of transition that currently can only be used with the scene function called image dissolve. This type of transition lets you create a dissolve transition that is controlled with a grayscale image, where black pixels dissolve first and white pixels dissolve last. This is best illustrated with an example.

An image dissolve transition using the following control image

_images/wipe_right.png

produces this result:

And here is what the code looks like:

-- Use an imageDissolve transition with "wipe right.png" as the control image
scene("sky day.png", {type=Transition.imageDissolve, time=1, image="wipe right.png"})

You can get really creative with these images to produce a lot of different effects. Here is a video showing more examples. The control image used is shown in the top right corner.

Iris Engine searches for transition images in the folder specified in the config file.

Using the setBackground function

While most of the time you will use the scene function, sometimes you might need to change the background without affecting the rest of the scene. This is done using the setBackground function.

Let’s see an example:

-- Change the background to the image "street evening.png"
setBackground("street evening.png")

The previous code will change the background using a dissolve transition with a duration of 0.5 seconds:

There is, however, a big difference between the scene and the setBackground functions when it comes to transitions: while all scene transitions are blocking, the setBackground function allows us to decide if we want to use a blocking or a non-blocking transition. The difference between the two is that blocking transitions pause the execution of the script until the transition has finished, while non-blocking transitions don’t. Here is a video that shows this difference:

The default transition of this function is non-blocking. We can control this behavior by passing a custom transition object as the second parameter. Here is the code of the previous video:

s "First, I'm going to show you a blocking transition."

-- Hide the text window so that the effect can be seen clearly
hideText()

-- Use a blocking dissolve with a duration of 2 seconds
setBackground("street evening.png", {type=Transition.dissolve, time=2, block=true})

s "As you can see, the next line of text doesn't show up until the transition has finished."
s "Now let's see a non-blocking transition."
hideText()

-- Use a non-blocking dissolve with a duration of 2 seconds
setBackground("street night.png", {type=Transition.dissolve, time=2, block=false})

s "As you can see, the next line of text appears at the same time the transition starts."

As you can see, the block parameter is used to specify whether or not the transition is blocking. This parameter is required for all transition types except for Transition.none, and the only function without this requirement is the scene function.

Sprites

Apart from backgrounds, you might also want to add other images to your game. In order to do that, you will need to create a Sprite object and store it in a variable. Here is an example:

-- Create a Sprite object
ball = Sprite.new("ball.png", 1)

As you can see, in order to define a sprite you need to specify two parameters. The first one is the filename of the image you want to use, while the second one is the z-index.

While visual novels are 2D games, when two objects overlap we need to know which one should be drawn on top of the other. For this reason, all objects that can be drawn on the screen have a z-index. You can think of z-indexes as the layers of a drawing program.

_images/layers.png

The z-index tells the engine in which layer to draw the image

An object with greater z-index is always in front of an object with a lower z-index. If two objects have the same z-index, the one that was defined last will be drawn on top.

The z-index of the background and the text window is specified in the config file.

Showing sprites

Once the sprite is defined, we can make it appear on the screen using show like this:

-- First we define a sprite and store it in a variable called 'ball'
ball = Sprite.new("ball.png", 1)

-- Then we make it appear on the screen by calling ball:show()
ball:show()

By default, the sprite will appear on the screen with a non-blocking fade with a duration of 0.3 seconds, but you can also specify a custom transition object:

-- Show the sprite without a transtition
ball:show({type=Transition.none})

-- Show the sprite using a blocking fade transition with a duration of 5 seconds
ball:show({type=Transition.fade, time=5, block=true})

Tip

Transition objects can be stored in variables. This way, you don’t have to write all of the parameters every time you want to use them.

-- Create a variable with a blocking fade with a duration of 0.5 seconds
blockFade05 = {type=Transition.fade, time=0.5, block=true}

-- Instead of writing the parameters, you can use the variable
ball:show(blockFade05)

If you want to hide the sprite, you can use hide in the same way as show:

-- Hide the ball sprite with the default transition
ball:hide()

-- Hide the ball sprite with a custom transition
ball:hide({type=Transition.fade, time=0.5, block=true})
Placement of sprites

If you have been following along, you probably noticed that the sprites appear in the top left corner of the screen. You can set the position of a sprite with setPosition(x, y), where x is the distance from the left of the screen measured in pixels and y the distance from the top of the screen.

-- Create a sprite named ball
ball = Sprite.new("ball.png", 1)

-- Place that sprite in the position (50, 60)
ball:setPosition(50, 60)

When a sprite is in a certain position, the exact pixel of the image that lands in that position is called the origin. By default, the origin is the top left corner of the sprite, but you can change it with setOrigin(x, y). You can see how this affects the position of the sprite in the following image:

_images/origin_example.png
-- Set the origin of the sprite
ball:setOrigin(60, 60)
Movement

It is also possible to move the sprites around the screen with an animation. This is done using move(x, y, time, shouldBlock), where x and y determine the position you want to move the sprite to, time specifies the duration of the animation in seconds, and shouldBlock sets whether or not the engine should treat this animation as a blocking transition.

-- Move the ball sprite from its current position to (1112, 81)
-- This animation will have a duration of 2 seconds and will be a blocking transition
ball:move(1112, 81, 2, true)

You can specify the type of interpolation to use for this animation as an additional parameter. These are the interpolators you can choose from:

  • Interpolator.linear
  • Interpolator.easeIn
  • Interpolator.easeOut
  • Interpolator.easeInOut

Interpolators are used to control the acceleration of the sprite during the animation. The following video shows the differences between them:

Here is an example of how to use them in a script:

-- Move the ball sprite like in the previous example but using an ease-out interpolator
ball:move(1112, 81, 2, true, Interpolator.easeOut)

When no interpolator is specified, Interpolator.easeInOut will be used by default.

Animated sprites

Iris Engine supports sprite sheets, which are images that describe an animation. For example, the following image

_images/sprite_sheet.png

results in this animation:

_images/animated_sprite.gif

In order to create an animated sprite, you first need to define a Sprite object with the sprite sheet you want to use as the image, and then use defineSpriteSheet(frameCount, cols, rows, fps), where frameCount is the number of frames of your animation, cols and rows is the number of columns and rows your sprite sheet has, and fps is the framerate of the animation. After that, you can use this object in the same way as any other sprite. Here is an example using the previous sprite sheet:

-- Create an sprite using the sprite sheet as the image
animated = Sprite.new("sprite sheet.png", 1)

-- Define the properties of the sprite sheet
-- 89 frames, 13 columns, 7 rows, 60 FPS
animated:defineSpriteSheet(89, 13, 7, 60)

-- Show the animated sprite
animated:show()

Character sprites

Character sprites are a special kind of sprites with added functionality to make showing the characters of your games with different expressions easier.

Bases and expressions

In Iris Engine, character sprites are composed of a base, which is an image of the character without a face, and a set of expressions.

_images/baseVSexpressions1.png

The reason for this is that it allows us to reuse the same expressions with different base images, which is really useful when a character has multiple outfits or when we have multiple base images for the same character with slightly different poses, such as in this example:

_images/different_poses.png

Each expression should be its own image file, with the same resolution as the base image. For this reason, the best way to create these images is to separate the base and the expressions in their own layers in your drawing program and then export each layer separately.

Due to the way transitions work, expression images should include part of the base image underneath the facial expressions, like this:

_images/expressions_how.png

As for the name of the files, if the name of the base image is base.png, the expressions that will be used with that base image should be called base expression.png. For example, if the base image is called sakura1.png, the images of the expressions should be called sakura1 smiling.png, sakura1 angry.png, sakura1 shy.png and so on. Of course, we can later tell the engine to use these expressions with a different base image without having to edit their names.

Making your characters express themselves

There are several ways to define a character sprite, but the simplest one only requires the name of the base image to use:

-- Define a character sprite that uses "sakura1.png" as the base image
sakura = CharacterSprite.new("sakura1.png")

The sprite will be automatically placed in the center of the screen, so most of the time you won’t need to manually set its position.

Once defined, we can make the sprite appear on the screen using show, but this time we have to specify the expression to use:

-- Show the character sprite with the expression "sakura1 smiling.png"
sakura:show("smiling")

As was the case with simple sprites, the transition used by default will be a non-blocking fade with a duration of 0.3 seconds, but you can specify a custom transition object as the second parameter.

show is also used to change the expression of a character sprite that was already visible:

sakura:show("smiling")
s "I'm smiling now."

sakura:show("normal")
s "And this is my neutral expression."

sakura:show("laughing")
s "And now I'm laughing."

In this case, the default transition is a dissolve instead of a fade.

Now, let’s say we have a second base image called “sakura2.png” that should use the same expression images as “sakura1.png”. This can be achieved with setExpressionBase:

-- Define a character sprite that uses "sakura2.png" as the base image
sakura = CharacterSprite.new("sakura2.png")

-- Set "sakura1.png" as the expression base
sakura:setExpressionBase("sakura1.png")

-- Show the character sprite using "sakura2.png" as the base image
-- and "sakura1 smiling.png" as the expression image
sakura:show("smiling")
Placement and movement of Character Sprites

You can use setPosition and move in the same way as with simple sprites, however, keep in mind that the origin of character sprites is located at the bottom center of the sprite, as this makes it easier to align them with the bottom of the screen. You can also replace the x and y parameters in both functions with one of the following options:

  • Position.left
  • Position.center
  • Position.right

This way, you don’t have to figure out the exact coordinates of these positions by yourself.

Switching the base of your characters

It is also possible to transition smoothly from one base image to another while the character sprite is visible, allowing you to do things like this:

This is done with setBase(base, expressionBase, expression), where base is the new base image to use, expressionBase is the name of the base image of the expressions you want to use, and expression is the name of the expression you want your character to make.

You can optionally add a custom transition object as the last parameter, otherwise a non-blocking dissolve with a duration of 0.3 seconds will be used.

-- Define a character sprite that uses sakura2.png as the base image
sakura = CharacterSprite.new("sakura2.png")
sakura:show("smiling")

...

-- Transition to sakura3.png using the set of expressions of sakura2.png
sakura:setBase("sakura3.png", "sakura2.png", "smiling")

Note

In the current version of the engine both base images must have the same resolution, otherwise one of the images will be stretched during the transition. This will be fixed in a future release.

The config file

The config file, named config.lua and located in the same folder as the Iris Engine executable, is a Lua script that defines some variables that control the behavior of the game.

In this page you can find detailed information about all the settings you can customize in the config file.

Tip

You don’t need to create a config file from scratch. Download a template and edit the included config file to suit your needs.

Game

This section contains the description of your game.

name
The name of your game. It will be displayed as the title of the window.
iconFile
Path to the image to use as the icon of your game. It will be displayed in the Windows taskbar and it will be used as the icon of the window of your game. This image can be in any supported format.
startScript

Path to the script to run when the game starts.

This path must be relative to the scripts path specified in the paths section.

Screen

This section defines the properties of the window of your game.

fullscreen

Whether to launch the game in fullscreen mode.

The player can toggle fullscreen mode by pressing Alt+Enter.

resolution

The native resolution of your game.

The game will be rendered at this resolution and then scaled to the actual size of the window using letterboxing when necessary.

Text window

This section defines the properties of the box where the text of dialogue and narration appears.

position
The position of the text window.
size
The size in pixels of the text window.
margin
The margin allows you to leave some space between the area where the text will be written and the borders of the text window. This space is specified in pixels.
background

Path to the image to use as the background of the text window. This image will be stretched to fill the text window.

This path must be relative to the gui path specified in the paths section.

backgroundAlpha
The opacity of the background image of the text window defined as a number in the range [0, 255] where 0 is completely transparent and 255 the opacity of the original image.
font
Path to the font file to use to render the text of your game.
fontSize
The point size (based on 72 DPI) of the font to use to render the dialogue and narration text of your game.
fontColor
The color in rgb of the narration and dialogue text of your game.
shadowDistance
Distance in pixels of the drop shadow of the text of your game. If set to 0, no shadow will be drawn.
shadowColor
The color in rgba of the drop shadow of the text of your game.
spacing
Line spacing in pixels. This will be added to the recommended line spacing of your font, which it’s usually a few more pixels than necessary for lines to not overlap. Negative numbers bring lines together.
wordWrapping
If enabled, the text of the text window will be split breaking lines between words rather than within words, when possible.
formatJapaneseText

If enabled, pages that start with ‘「’, ‘『’ or ‘(’ will be indented as is common in Japanese visual novels.

_images/formatJapanese_true.png

formatJapaneseText enabled

_images/formatJapanese_false.png

formatJapaneseText disabled

characterDelay
Controls the typewriter effect of the text window. The time in seconds it takes for each character to appear.
namePosition
The position within the text window of the name of the character that is speaking.
nameFontSize
The point size (based on 72 DPI) of the name of the character that is speaking.
nameFontColor
The color in rgb of the name of the character that is speaking.
nameShadowDistance
Distance in pixels of the drop shadow of the name of the character that is speaking. If set to 0, no sadow will be drawn.
nameShadowColor
The color in rgba of the drop shadow of the name of the character that is speaking.
indicatorImage

Path to the image to use to tell the player that they can click to dismiss the text currently displayed in the text window.

The arrow in the bottom right corner of this image is an example of an indicator image:

_images/formatJapanese_true.png

The indicator image will be treated as a sprite sheet.

This path must be relative to the gui path specified in the paths section.

indicatorPosition
The position of the indicator image within the text window.
showIndicatorAfterLastCharacter

If true, indicatorPosition will be ignored and the indicator image will be placed after the last character of text.

_images/indicator_lastCharacter.png

showIndicatorAfterLastCharacter set to true

indicatorSpriteSheet
The properties of the sprite sheet of the indicator image.
showTransition
Properties of the transition used to make the text window visible.
hideTransition
Properties of the transition used to make the text window invisible.

Choices

This section defines the properties of the menus used to present choices to the player.

position
Position of the area where the options will appear. The buttons will be vertically and horizontally centered in this area.
size
Size in pixels of the area where the options will appear. The buttons will be vertically and horizontally centered in this area.
background
The background image used to create the buttons. Read Button constructor for more details.
useVerticalLayout
Wether the layout of the background image used to create the buttons is vertical. Read Button constructor for more details.
separation
Distance in pixels from the top left corner of one button to the top left corner of the next.
showTransition
Properties of the transition used to show the options to the player.
hideTransition
Properties of the transition used to hide the options.

Paths

This section defines the folders where the most common asset types are located, so that you don’t have to write the full path when using these assets in your scripts. They can all point to the same folder if you want to.

scripts
Path to the folder where scripts are located.
sprites
Path to the folder where images of sprites are located.
characters
Path to the folder where images of character sprites are located.
backgrounds
Path to the folder where background images are located.
transitions
Path to the folder where control images of imageDissolve transitions are located.
gui
Path to the folder where GUI images are located.
luts
Path to the folder where the lookup tables (LUTs) used for color grading are located.
music
Path to the folder where the soundtrack of your game is located.
sounds
Path to the folder where the sounds of your game are located.
videos
Path to the folder where video files are located.
separator
String used as a separator when constructing the filenames of expression images.

Sounds

This section defines some GUI sounds.

buttonHoverSound

Path to the sound to play when the mouse enters a button.

This path must be relative to the sounds path specified in the paths section.

buttonClickSound

Path to the sound to play when the player clicks a button.

This path must be relative to the sounds path specified in the paths section.

Z-indexes

While visual novels are 2D games, when two objects overlap we need to know which one should be drawn on top of the other. For this reason, all objects that can be drawn on the screen have a z-index. You can think of z-indexes as the layers of a drawing program.

An object with greater z-index is always in front of an object with a lower z-index.

This section defines the default z-index of some objects of the game.

sceneTransitionEffects
Some transition effects draw an image in front of all of the objects of the scene. This is the z-index of those effects. Should be the highest.
textWindow
The z-index of the text window.
choices
The z-index of the menus used to present choices to the player.
characters
The default z-index of character sprites.
backgrounds
The z-index of the background.

Cache

Images, sounds and other assets need to be loaded into memory before they can be used in the game. However, loading takes time and can cause stutter and framerate drops during gameplay. For this reason, once an asset has been loaded, it remains in memory as long as possible so that the next time it is needed we don’t have to load it again. The part of the memory where these assets reside is called the cache.

This section defines the properties of the cache and controls the way Iris Engine loads assets into memory.

maxSizeInMiB
The maximum size of the cache in MiB. Keep in mind that this only takes into account the size of the assets themselves, so the actual memory requirements of your game will be higher.
allowPrecaching

Iris Engine loads assets the first time they are needed. This means that the images of sprites, for example, are loaded the first time the sprite is displayed on the screen. This can cause stutter during gameplay.

However, if this option is enabled, the loading will take place when the object is defined, which is usually at the beginning of the script. This way, the player will be less likely to notice the stutter, especially if the loading happens just before a scene transition.

finishLoadingSceneTransitions

As backgrounds don’t need to be defined, they can’t be precached even if allowPrecaching is enabled. This may result in the game skipping the first frames of scene transitions.

If this option is enabled, the start of scene transitions will be delayed until the background image has been loaded, making it impossible for the player to notice the stutter.

This option only has an effect on the scene function.

Supported formats

Here you will find a list of the file formats supported by Iris Engine.

Audio file formats

  • WAV
  • FLAC
  • OGG

Image file formats

  • JPG
  • PNG
  • BMP

Font file formats

  • TTF
  • OTF

Video file formats

  • OGV (audio bitrate must be 44100 kHz)

Glossary

Text window
The box where dialogue and narration will appear.
Blocking transition
A transition that pauses the execution of the script until it has finished. This means that if you declare two blocking transitions one after another in a script, the second one will not start until the first one has been completed.
Non-blocking transition
A transition that doesn’t pause the execution of the script. This means that if you declare two non-blocking transitions one after another in a script, both of them will start at the same time.
Blocking function
A function that suspends the execution of the script until a certain condition has been met. Examples of such functions are the say and the sleep functions.

Indices and tables