VISIONAIRE GUIDE

MAKE YOUR OWN

ADVENTURE GAME

with

Below you’ll find a consolidate and structured guide that will help you start building up your own game.

Have fun and be creative!

Have fun and be creative!

Introduction
Visionaire is a really powerful engine designed originally for 2D point ‘n click adventure games and it’s among the best options if you plan to make such a game. It has been used in many successful commercial games, most notably by Daedalic Entertainment. You can see a comprehensive list of games made with this engine here. This guide will help newcomers to easily setup and build their first game, but is also a handy ref for experienced developers during the production of our game. Apart from our own studio’s experience with working with the engine, this guide practically contains consolidated and structured information and examples available in the following links:

https://wiki.visionaire-tracker.net (Wiki)
http://www.visionaire-studio.com/luadocs (API Reference)
https://www.visionaire-studio.net/forum (Forum)
https://discord.gg/feQkHgNe (Discord)
Yes No Suggest edit
0 of 0 users found this section helpful
Quickstart
Installation
Resolution Handling
One of the first things you need to do is to set the resolution of your game through the game properties:


This will be the default resolution of your game, and normally it should match your graphics resolution. You can get the current resolution using getProperty(“display_resolution”) which returns the rectangle that is drawn in (excluding any black borders):

local resx = getProperty("display_resolution").width
local resy = getProperty("display_resolution").height
Yes No Suggest edit
0 of 0 users found this section helpful
Scenes
Query name of scene

Wrap in If lua action part:

return game.CurrentScene == Scenes["101_river"]

Check if the name of the scene contains specific string

Good for filtering scenes!

if string.match(game.CurrentScene:getName(), "minigame") then ... end

Check if a scene is a Menu

game.CurrentScene.SceneIsMenu
Yes No Suggest edit
0 of 0 users found this section helpful
Objects
Get the VS object name (left column of objects in scene)
game.CurrentObject:getName() -- For object under cursor

game.SavedObject:getName() -- For saved object

game.UsedItem:getName() -- For the item at hand
Get the object name as it appears in game:
game.CurrentObject:getTextStr(VObjectName))

game.SavedObject:getTextStr(VObjectName))
Change the name of the object as it appears in game.
game.CurrentScene.Objects["obj"]:setTextStr(VObjectName, "string")
Note: if you want to change it in all languages you need to do a for loop through all languages. Check if a string value is not empty (zero length)
string.len(game.CurrentObject:getTextStr(VObjectName)) ~= 0
How to clear/unlink an object value? Using the ‘emptyObject’, e.g.:
Characters["Tom"].FollowCharacter = emptyObject
Item at hand The currently used item, either with the ‘Set item’ action part or dragged item:
game.UsedItem
Hide an Object
Objects["bottle"].Visibility = 0
Note: it hides only the image, not the interaction polygon. Get the Sprite position of an object
Objects["name"].Sprite.Sprite -- holds a table with information about the sprite path, position , etc
Get the position of the sprite
Objects["name"].Sprite.Sprite:getPosition().y -- for the y-axis position
Move or Check if an object has moved to another position (x,y)
game.CurrentScene.Objects[“key”].ObjectOffset
Yes No Suggest edit
0 of 0 users found this section helpful
Duplicate Objects
You can create a new object from an existing one:

local obj = game.CurrentScene.Objects.["table"]:duplicate("duplTable") -- duplicate object is created and then stored into a variable
You can delete this new object with:

obj:remove()
 
Yes No Suggest edit
0 of 0 users found this section helpful
Scene Transitions
When showing or changing to a new scene/menu we have the option to do this with a fading effect. By default, the ‘Fade out and fade in’ effect is used. If we want a different effect, we can choose one using the ‘Set fade effect to new scene’ action part. We can also define the duration of the effect:



There is a variety of fade effects to choose from:

  • Fade in
  • Fade out
  • Fade out and fade in
  • Fade to new scene
  • Shift left
  • Shift right
  • Tunnel effect

Note: the change in the fade effect will remain until you change it again.
Yes No Suggest edit
0 of 0 users found this section helpful
Meanwhile Cutscenes
There are a few possible ways to display a ‘Meanwhile’  message as per Lucasarts style. The easiest one:

  • Make a new scene with a black (or any other color you like) background.
  • When needed, use ‘Show scene/menu’ action part to show the black scene.
  • Use ‘Display narration text’ with your meanwhile message.

Another option would be to fade the scene brightness instead of using a black background, using the to() tweening function:

game.CurrentScene:to(500, {SceneBrightness = 0}, easeQuintOut) -- easing is optional
Yes No Suggest edit
0 of 0 users found this section helpful
Action Areas
Event Handler

function onActionArea(movement, actionArea, character)
  if movement == "ENTER" then
    -- do something
  elseif movement == "LEAVE" then
    -- do something else
  end
end

registerEventHandler("actionArea", "onActionArea")
Tip: actionArea == ActionAreas[“example”] (ActionAreas is a table)
Yes No Suggest edit
0 of 0 users found this section helpful
Scrolling
Adjust the scroll speed

Method 1

Game Properties -> Scroll Speed Method 2

game:setValue(VGameScrollSpeed, 300) -- scroll by 300 pixels a second


Snap the scroll position of a scene

game.ScrollPosition = {x = 0, y = 0} -- replace the 0's with whatever coordinates you want to snap the camera to.


Smooth Scrolling

To start the scrolling smoother (i.e. slower at beginning and then reach set speed), tick:
Game Properties -> Smooth Scrolling

Adjust cursor’s distance from the edge of the screen before scene scroll will be triggered.

Lua Method

X-Axis Scroll

game:setValue(VGameCursorHorizontalScrollDistance, 50) -- scroll on X axis when cursor is 50 pixels or less from scene edge


or

game.CursorHorizontalScrollDistance = 50


Y-Axis Scroll

game:setValue(VGameCursorVerticalScrollDistance, 50) -- scroll on Y axis when cursor is 50 pixels or less from scene edge


or
game.CursorVerticalScrollDistance = 50


Adjust character’s distance from the edge of the screen before scene scroll will be triggered.

Lua Method

X-Axis Scroll
[be]
game:setValue(VGameHorizontalScrollDistance, 50) -- scroll on X axis when character is 50 pixels or less from scene edge


Or

game.HorizontalScrollDistance = 50

game:setValue(VGameVerticalScrollDistance, 50) -- scroll on Y axis when character is 50 pixels or less from scene edge


Y-Axis Scroll

Or

game.HorizontalScrollDistance = 50


Method 2

Use ‘Set Horizontal/Vertical Scroll Area’ Action Parts.

If the distance of the current character to the horizontal (or vertical) scene border is equal or smaller than VGameHorizontalScrollDistance (or VGameVerticalScrollDistance) value, then the scene will be scrolled horizontal (or vertical) to center the character (if the scene is larger than the viewable area). If this value is very small the character has to go very close to the border until the scene is scrolled, if the value is half the viewable size or larger then the character will always be centered.

Parallax Scrolling
Yes No Suggest edit
0 of 0 users found this section helpful
Curves
There are 3 types of curves:

  • Curve
  • Continuous Curve
  • Curve via control points


Note: the first point of the curve is the starting point (also for the continuous curve)

With Tween Curves you can move a particle system (through an object) on a curve and rotate, or make non-linear animations like flying/swooping bird or wave motion etc.

Step 1 – Create a Curve in a specific scene. Each curve has an index: 1,2,3…

Example 1 – Move a Particle System (through an object)

Step 2.1 – Create a scene object & call it e.g. “moving”
Step 3.1 – Create a particle & link it to the scene object.


Now let’s write a tween loop to make it move around the curve we have created:
startCallBackTween(duration, function(position) --code-- end, easing, loop, pendulum)

duration: the time needed to complete 1 loop
loop: true = infinite loops, false = 1 loop only
pendulum: if loop = true, it will reverse direction each next loop

startCallbackTween(30000, function(x) -- starts loop function that lasts for x time
local pos = game.CurrentScene.Curves[3]:curveAt(x) -- gets current position of linked curve
local direction = game.CurrentScene.Curves[3]:curveDirection(x) - 1.57 -- gets the current direction based on position of curve in the curve
local p = graphics.getParticles(game.CurrentScene.Objects.moving) -- gets the particle belonging to the scene object ["moving"]
p.emissionDirection = {0.0, direction, 0.0, direction} -- updates the angle of the particle
p.center = {pos.x,pos.y} -- updates the position of the particle
end, easeLinearIn, true, false)

Example 2 (Move Animation)
startCallbackTween(30000, function(x)
local pos = game.CurrentScene.Curves[3]:curveAt(x)
local direction = game.CurrentScene.Curves[3]:curveDirection(x) - 1.57
ActiveAnimations["animation_name"].AnimationCurrentPosition = {x = pos.x, y = pos.y}
end, easeLinearIn, true, false)

You can create curves in each scene. ‘Curves’ is a linklist; you can access a specific curve in the list using the index, in the above example 3.

The curve object has 3 functions:

curveAt(x) -> position
curveDirection(x) -> degree (rad direction)
curveDerivative(x) -> vector pointing in the direction (tangent)


How to stop curve

If the function(x) returns false, then the startCallbackTween() will stop. Taking into consideration that if you exit a scene that has curves used for animation you will get an error as it will not be able to find the curve or the active animations anymore, use the following format:
startCallbackTween(duration, function(x)
if game.CurrentScene == Scenes["Scene that the curves/anims live"] then
-- do your stuff
else return false end -- it will kill the loop in any other scene (returns false)
end, easeLinearIn, true, false)
Yes No Suggest edit
1 of 1 users found this section helpful
Way Systems
A spider web type approach is recommended when creating way paths; try to keep the way paths as simple as possible as the engine will most of the time determine its own path.

Connect or disconnect one way point to/from another

Left click on a way point and then right click on an existing point. This will draw a line between these two points or delete the line if it already exists.

Character scaling

Scale only on the y-axis if possible. It’s highly recommended that you create the scale values on a separate way path outside of the way borders rather than on the complex way paths you have created inside of the way borders.

Drag around and reposition the scene preview window

Hold down the middle mouse button while hovering over the scene preview section of the editor and move the mouse around. It’s the only way that you can access the left & top sides of the scene in case you need to extend your way borders/paths outside of the scene background itself (maybe you want the character to walk out of or into the scene).

Shortcuts:

Hold Shift -> Make straight line

Way Points

Right Click Anywhere -> Deselect all way points
Right Click on a Way Point -> Join it with the selected Way Point
Yes No Suggest edit
0 of 0 users found this section helpful
Lightmaps
Lightmaps allow characters to change brightness or tinting depending on where they stand in the scene so that they follow the light sources in the scene.

Lightmaps maps work based on character positions in the scene, which in turn depends on where you set the character animation center for each of the characters animations (usually somewhere near the feet). Basically the engine:

    1. Checks if a lightmap is assigned to the scene.
    2. Checks the position of the character against the lightmap.
    3. Tints the character based on the color found at the pixel coordinates of where the character is standing.

Notes:

  • The entire character is tinted.
  • Lightmaps only affect the tint of the characters. If you want one to affect the entire scene you could add them as images inside of scene objects.
  • It’s advisable to add feathering as it allows the character tint to smoothly change from one tint to another.

Lightmaps are the easiest way to apply tinting to characters, nevertheless you can also use Lua:

Characters["Dragon"].Tint = 0xFF0000 -- format used by Visionaire is 0xBGR (BBGGRR) so this will tint the character blue
Alternatively you could use shaders to directly apply lighting to your scenes which would affect things in a more dynamic way.
Yes No Suggest edit
0 of 0 users found this section helpful
Setting up a Menu
Checking if a scene is a menu

game.CurrentScene.IsMenu
Yes No Suggest edit
0 of 0 users found this section helpful
Save / Load Menu
Characters
Positioning of a character in a scene.

To position the character above an object in a scene, you must set a YChar in the scene as follows: YChar > YObjCenter [r], where YChar = YChar Actual + YAnim Center
So you basically need to set the YAnimCenter = YChar – YCharActual
Example: I want to place a character with YActual = 344 above an object with YAnim Center = 650, therefore I set YChar = 651, which means than i have to change YAnimCenter  = 651 – 344 = 307

To be able to work with characters, the first thing to do is to retrieve their object and store it in a variable.

Get current character object
local cisco = game:getLink(VGameCurrentCharacter)
Get any character object
local kosmos = getObject("Characters[kosmos]")
Now, you can do anything with your character:

Get the position (x,y) of a character
local pos = cisco:getPoint(VCharacterPosition)
Set the position (x,y) of a character
kosmos:setValue(VCharacterPosition, {x = pos.x, y = pos.y})
Get the Direction of a character
local direction = cisco:getInt(VCharacterDirection)
Set the Direction of a character
cisco:setValue(VCharacterDirection, 0)
Characters["Cisco"].Direction = 0 --shorthand 
game.CurrentCharacter.Direction = 0 -- for current character
Note: 0 = right, 90 = top, 180 = left, 270 = bottom

Hide/Show a character
Characters["cisco"].CharacterActive = false / true
Set the size of a character
Characters["unicorn"].Size = 50 -- in %
Disable character scaling
Characters["franco"].Size = 100 -- First set him to 100%

Characters["franco"].CharacterScale = false
Disable Interaction during animation state of the current Character

You can do this from the game properties but it is possible with lua also
game.DisableInteractionDuringAnim = eDisableInteractionAlways
Possible options:

  • eDisableInteractionAlways 2
  • eDisableInteractionCharacterAnim 1
  • eDisableInteractionNever 0


Get the animation state of a Char

You can actually listen to the animation state of a char by using the following
game.CurrentCharacter.AnimState
  Where AnimState can be:

eCharacterAnim 4 eStandingAnim 3 eTalkAnim 2 eWalkAnim 1 eNoAnim 0 eRandomAnim 5

Example
if Characters["grocery-elf"].AnimState == 2 -- (or == eTalkAnim) then 
  -- do something
end
So for example, you want to check when a character is talking, possible options:

  • Use a mainLoop to listen out for animation state change.
  • textStarted & texts linked to characters
  • Insert a play animation action part into the first frame of each of your talk animations. There is also a ‘Wait until a character stops speaking’ action part.
  • Use the action part hook:
 
local SHOW_TEXT = 23

system.registerActionPartHook(SHOW_TEXT, "charTalk")

function charTalk(actionPart)
  if actionPart.Link:getName() == "Tom" then
    -- do something
  end
end
Prevent Character from Moving
game.LeftClickBehaviour = eMouseActionBehaviourDoNotSendCharacter -- Disable left click from updating/setting destination

game.LeftClickBehaviour = eMouseActionBehaviourSendCharacterToCursor -- Enable left click update/set destination
Character talking and walking

Switch to an outfit where the character’s face/mouth isn’t drawn on. Create a secondary character that has the same canvas height & character center position as the actual character but only contains the face/mouth. Use a script to make sure that the position & alignment of the actual and the secondary characters match. Secondary character to do the talking.

Alternative Option (no lip sync is possible in this case though

Switch to an outfit where the character also includes a talk animation with the walk animations. Set the spoken text as background (text can move with moving char)

Access current character animation
graphics.getCurrentAnimation(char)
Empty the inventory of a character    
Yes No Suggest edit
0 of 0 users found this section helpful
Character Texts
You can control what happens when a character text starts or stops by registering textStarted / textStopped event handlers:

function txtStart(text) -- this function handles actions when the char text starts
  local owner = text:getLink(VTextOwner)
  if owner:getId().tableId == eCharacters and owner:getName() == 'cisco' then
    -- start any actions here
  end
end

function txtEnd(text) -- this function handles actions when the char text finishes
  local owner = text:getLink(VTextOwner)
  if owner:getId().tableId == eCharacters and owner:getName() == 'cisco' then
    -- start any actions here
  end
end

-- * initialize text event handlers * --
registerEventHandler("textStarted", "txtStart")
registerEventHandler("textStopped", "txtEnd")
Yes No Suggest edit
0 of 0 users found this section helpful
Dialogs
Start a dialog or a dialog layer

Use the relevant ‘Start dialog/dialog-layer’ action part.


To start a dialog from the beginning (i.e. 1st layer or super layer), choose one under ‘Characters’


You can also start a specific dialog layer/part (these are the ones that have children dialogue options) by choosing ‘Dialog Parts’.



Use a Dialog Part only once

You can have a dialog part to be selected only one time and then to be removed:

The limitation to the above is that you can only delete the dialog part being selected at a time. If you want to delete a dialog part from any other place, you need to do it with LUA, e.g.:

Characters["townhall-elf-right"].Dialogs.townhall.DialogParts[4].DialogPartAvailable = false -- this will remove the dialog part with ID 4
Access Dialog Parts

You can loop through the dialog if you want; you can access them by directly by name:
Characters.Daniel.Dialogs.feueralarm.DialogParts["1.Test"]
Generally, if you have unique texts/naming you can search them directly:
DialogParts["1.Test"]

or via table/Array number:
Characters[1].Dialogs[1].DialogParts[1]

Checking for availability:
Characters[1].Dialogs[1].DialogParts[1].Available == true

Disable a dialog option
Sometimes you want to disable a dialog option and not delete it, e.g. for testing. Just set False to an empty condition:

Switch to 1st dialog level

The dialog options allow you to switch to the previous dialog level but not the first one. To achieve this, just use the execute action and restart the dialog by adding a Start Dialog action part.
Yes No Suggest edit
0 of 0 users found this section helpful
Outfits
Query the Outfit of a Character
if game.CurrentCharacter.CurrentOutfit == Outfits["sad"] then ... end

if Characters["potion-man"].CurrentOutfit == Outfits["tied"] then ... end
Play a Character Animation
startAnimation(game.CurrentCharacter.CurrentOutfit.OutfitCharacterAnimations["cisco_kosmos_appear_right"])

startAnimation(Characters["cisco"].Outfits["normal"].OutfitCharacterAnimations["cisco_kosmos_appear_right"])
Set Character Speed
game.CurrentCharacter.CurrentOutfit.OutfitCharacterSpeed = 400
Random Animations

Played whenever a character is idle (i.e. doesn’t move and no animation is played) for a certain period (between 10 and 30 seconds). The animation, which is going to be played, is chosen by chance.

You can change above times with Lua:
Characters["cisco"].CurrentOutfit.RandomMinTime = 1500 
Characters["cisco"].Outfits["Surprised"].RandomMinTime = 1500 -- choose a specific outfit

-- Changing the random times for all character's outfits

for i = 1, #Characters["cisco"].Outfits do
 Characters["cisco"].Outfits[i].RandomMinTime = 1500
 Characters["cisco"].Outfits[i].RandomMaxTime = 5000
end
Yes No Suggest edit
0 of 0 users found this section helpful
Spine Animations
Spine is a great tool to create 2D Skeletal animations. You can actually import your Spine animations into Visionaire and use them in your game.

You can try importing Spine’s standard example, called ‘spineboy’ into Visionaire to play around:

  • Download the spineboy zip from here.
  • Open it in spine, go to export and extract the spineboy.atlas, spineboy.png and spineboy-ess.json to a subdirectory of your project.
  • Rename the spineboy-ess.json to spineboy.json, the names need to match.
  • Add the spineboy.json to the Spine files of an outfit.
  • Click on one animation and on the cog wheel select an animation on the right (if the right one seems selected you need to reselect it). It should now be shown in the preview.
Yes No Suggest edit
0 of 0 users found this section helpful
3D Character Models
Using 3D character models is beneficial in many cases as it could save time from designing all character’s animation frames. Visionaire will use the 3D model to display the character in the proper angle automatically.

Note: This guide was made using Blender 2.91.0. You can also download a ready .blend model for testing from here (check video description).

Exporting from Blender

Before you export your character model, it’s suggested to rename your animations in Blender’s Outliner panel to help you assign them to the character after importing to Visionaire:



Under File -> Export -> Collada (Default) (.dae)

From the settings, you only need to adjust the axis orientation to match Visionaire orientation system, as follows:



Finally click EXPORT COLLADA button. This will create your .dae model file. If your model uses textures, the separate file for the texture will also be exported.

Importing to Visionaire

Under your character’s outfit, load the file and adjust any other settings as you wish:



Then, create a new animation under each section (walk /standing / talk etc) – you don’t have to create one for each direction, that’s the good thing with 3d models! – and then select the animation to be played (the name we set in Blender before) and adjust the speed (1 = the normal anim speed)



Now you can assign your character in the scene as you would do normally.
Yes No Suggest edit
0 of 0 users found this section helpful
Lip Sync
Rhubarb is a Lip Sync software that is supported by Visionaire. Download it from here. It generates single files from a .wav file in “tsv” format. Basically text files with start time -> phoneme.