VISIONAIRE STUDIO GUIDE

MAKE YOUR OWN ADVENTURE GAME

Visionaire Studio is everything you need from a modern game engine. It’s among the best options and one of the most powerful engines to start building up your own adventure game. While it is exclusively an ‘Adventure Game’ engine, there are still many different ways to set up mechanics and experiment.

Have fun and be creative!

Introduction #

Visionaire is a powerful engine designed originally for 2D/2.5D 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.com/invite/g5zFejW (Discord)

 

What about other game genres?

 

Visionaire improves its capabilities with every update. Overall, the following game types are currently possible to be made:

 

  • 2D/2.5D third person point & click adventure games.
  • First person myst-like adventure games.
  • Interactive visual novels.
  • FMV point & click adventure games.
  • Games with Strategy / Simulation/ RPG mechanics/elements.
  • Platformer games (using Box2D and Ilios)
  • Isometric style games.

 

Main Features / Highlights

  • Very lightweight (size only abt 100MB), optimized for low resource usage.
  • Easy export to Win, Mac, Linux, HTML5, iOS, Android, Nintendo Switch, Xbox, Playstation
  • Support for both pixel art as well as high resolution games (up to 4K).
  • Built in functionality for easy point and click games creation.
  • Spine / Dragonbones 2D Skeletal Animation Import.
  • Characters 3D Model Import (Blender etc).
  • Rhubarb Lipsync support.
  • Advanced Audio System for Dynamic and Adaptive Sounds/Music (similar to iMuse).
  • FMOD Adaptive Audio Plugin.
  • Easy game creation for beginners without scripting.
  • Lua Scripting for more advanced customizations.
  • C# Like Support (Ilios language) for Component Based programming with Box2D physics engine.
Yes No Suggest edit
10 of 10 users found this section helpful

Quickstart #

Installation #

You have two options to download the engine and start playing around:

 

Test Version

You can download it from here. Its purpose is to test if the software fulfils your needs before buying a license. It is fully featured with the following limitations:

  • Max 10 scenes.
  • You cannot create builds.

 

Full Version

You can buy a license that suits your needs and download the latest version from here. You will then receive the registration details by email and you can activate your full version under Extras -> Register Editor.

 

 

Note: if for any reason the ‘Register editor’ is not showing, edit the Viseditor.ini and delete the line showing RegisteredVersion. You can go directly to the proper folder from here:

 

Yes No Suggest edit
1 of 1 users found this section helpful

Project Files #

.ved  – The project file that holds all the data structure of your project in an XML format. You can also open and edit it with any text editor (only if you know what you are doing!).

 

.veb – A compressed version of the .ved file. It holds the exact same data but it has much less size. It is not viewable or editable.

 

You can choose which of the above formats your project file will be in at any time when saving:

 

 

.vis – The main output file of your compiled game. It holds all your game’s assets (graphics, sounds etc.)

Yes No Suggest edit
5 of 5 users found this section helpful

Initial Game Setup #

Below you can see the minumum required steps to have a game up and running from a blank project, considering a 3rd person game. For more details in each step you can refer to the relevant section of this guide.

 

  1. Add a Scene. The scene needs to have a background image and a way system.
  2. Add Scene Objects for the character to interact with. Define their interaction polygons, give them a name and set the position for the character to walk to when interacting with them.
  3. Add a Font for the text to be displayed in game.
  4. Add the Playable Character and the relevant images. Set his starting position and the font to appear when he talks.
  5. Add your Cursors and their active/inactive images. You can have the main game cursor, cursor for you actions (Look, Use etc). Set the animation center for each one.
  6. Setup the Interface of the game. This includes all commands which represent specific actions and use the cursors we have defined above. Don’t forget to assign the interface to the playable character.
  7. Setup game’s Properties. Set your game’s resolution, the first scene, the playable character.
  8. Create Actions when interacting with Scene Objects.
  9. Save and run your game (CTRL+F9).

See below also some more details on how to get everything up and running.

 

Resources

 

Name Description Author
Creating a Scene from Scratch PDF Tutorial on the setup of Inventory, check also the Youtube Video W. Kruger
Creating a Scene from Scratch Project Files Visionaire Files for the tutorial W. Kruger

 

Yes No Suggest edit
4 of 4 users found this section helpful

config.ini #

Visionaire uses a config.ini file to predefine the settings of the started game. The config.ini is created automatically when you build your game and is placed in the same directory as the player. The default config.ini looks like this:

 

FILE = data.vis
# 
# FULLSCREEN = {yes|no}
# yes - starts the game in fullscreen
# no - starts the game in a window
FULLSCREEN = yes
# 
# RESOLUTION = {Auto|Desktop|Game}
# Auto - wide-screen support is activated if a wide-screen display is detected
# Desktop - current desktop resolution is used when game is started in full screen mode
# Game - game is initialized with the resolution specified in the game
RESOLUTION = desktop
# 
# INTRO = {yes|no}
# yes - Show the intro movie on start-up
# no - Don't show the intro movie
# 
# LANGUAGE = {German|English|...}
# 
# LOGLEVEL = {Info|Warning|Error}
LOGLEVEL = info

Visionaire checks the config.ini when it runs the game and adjusts the settings accordingly; if you want to change any settings edit config.ini manually before starting the game.

 

Dynamic Configuration

 

For a released game with a proper settings screen, you need to write and read from the config.ini dynamically from within the game. The example script below will allow you to do that in a new config.ini file which will be located in the localAppDir of the user. You may adjust as required to suit your game needs. For this particular one you need to create the following conditions/values on a scene:

 

    • Conditions cfg_fullscreen, cfg_subs, cfg_speech_timeout
    • String values cfg_res, cfg_language
    • Integer values cfg_res_x int, cfg_res_y int

 

-- * local variables * --
local fn = "config.ini" -- store filename
-- * --
 
-- * fallback * --
local lglvl = "Error" -- default value for log level
local df = "woc.vis" -- filename, should reflect exported .vis file
game.SpeechLanguage = game.StandardLanguage -- default speech language to standard language
 
-- * tables * --
local t_res = {"Auto","1280x720","1600x900","1920x1080","Desktop"} -- add available resolutions here
local t_lang = game:getLinks(VGameLanguages) -- store all available languages into a table

-- * function used to read data from the config.ini file * --
function read_ini()
 local fr = io.open(localAppDir .. fn, "r") -- read from config.ini
 -- * --
 if fr then -- if file exists then...
  lines = fr:read() -- read currently selected line
  print("-- * --")
  print(fn .. " exists")
  print("retrieving settings from " .. fn)
  for lines in io.lines(localAppDir .. fn) do
   line = string.lower(lines) -- convert all line content to lowercase
   line = string.gsub(line, '\r', '') -- 5/12/2020 -> Fix for Mac / Linux. config.ini is printed with "\n" at the end of the lines, so that everything's in its own line. Windows ignores the "\n" part but mac/linux read it as "\r". So when you do if line == whatever in Windows it's if "line" == "line" for the line you're searching (Correct!) while as in mac or linux it does if "line\r" == "line" and thus fails.
   if not line:find("#") then -- skip all lines containing "#"
    if line:find("file =") then df = string.sub(lines, 8); print("file is currently linked to " .. df) end
    -- * window mode * --
    if line == "fullscreen = no" then Conditions["cfg_fullscreen"].Value = false; print("window mode is currently set to Windowed") end
    if line == "fullscreen = yes" then Conditions["cfg_fullscreen"].Value = true; print("window mode is currently set to Fullscreen") end

    -- * resolution * --
    for i = 1, #t_res do if line == ("resolution = " .. string.lower( t_res[i] )) then Values["cfg_res"].String = t_res[i]; Values["cfg_res"].Int = i; print("resolution is currently set to " .. Values["cfg_res"].String) end end
    -- * subtitles * --
    if line == "subtitles = no" then Conditions["cfg_subs"].Value = false; print("subtitles are currently set to Off") end
    if line == "subtitles = yes" then Conditions["cfg_subs"].Value = true; print("subtitles are currently set to On") end

    -- * text speed * --
    if line:find("textspeed =") then print("text speed = " .. game.TextSpeed) end

    -- * text language * --
    for i = 1, #t_lang do if line == ("textlanguage = " .. string.lower(t_lang[i]:getName() )) then game.StandardLanguage = t_lang[i]; print("text language is currently set to " .. game.StandardLanguage:getName()); Values["cfg_language"].String = t_lang[i]:getName() end end
    -- * speech language * --
    for i = 1, #t_lang do if line == ("speechlanguage = " .. string.lower( t_lang[i]:getName() )) then game.SpeechLanguage = t_lang[i]; print("spoken language is currently set to " .. game.SpeechLanguage:getName()) end end

    -- * speech timeout * --
    if line == "speechtimeout = no" then Conditions["cfg_speech_timeout"].Value = false; print("speech timeout is currently set to Off") end
    if line == "speechtimeout = yes" then Conditions["cfg_speech_timeout"].Value = true; print("speech timeout is currently set to On") end

    -- * log level * --
    if line == "loglevel = error" then lglvl = "Error"; print("log level is currently set to Error") end
    if line == "loglevel = warning" then lglvl = "Warning"; print("log level is currently set to Warning") end
    if line == "loglevel = info" then lglvl = "Info"; print("log level is currently set to Info") end

    -- * sound levels * --
    if line:find("musicvolume =") then print("music volume = " .. getVolume(eMusicVolume)) end
    if line:find("soundvolume =") then print("sound volume = " .. getVolume(eSoundVolume)) end
    if line:find("speechvolume =") then print("speech volume = " .. getVolume(eSpeechVolume)) end
    if line:find("movievolume =") then print("movie volume = " .. getVolume(eMovieVolume)) end
    if line:find("globalvolume =") then print("global volume = " .. getVolume(eGlobalVolume)) end
   end
  end
  fr:close()
  print("successfully retrieved settings from " .. fn)
 else
  print(fn  .. " does not exist. Setting defaults")
  setVolume(eMusicVolume, 70)
  setVolume(eSoundVolume, 75)
  setVolume(eSpeechVolume, 75)
  Values["cfg_res"].String = "Desktop"
  Values["cfg_res_x"].Int = 1920
  Values["cfg_res_y"].Int = 1080
  Conditions["cfg_subs"].Value = true
  Conditions["cfg_speech_timeout"].Value = true
  write_ini() -- creating new config.ini

 end
end

-- * function used to write data to the config.ini file * --
function write_ini()
 local fw = io.open(localAppDir .. fn, "w") -- write to config.ini
 print("-- * --")
 print("writing new settings to " .. fn)

 -- * data file * --
 fw:write("File = " .. df .. "\n")

 -- * window mode * --
 fw:write("#\n")
 fw:write("# Fullscreen = {Yes|No}\n")
 fw:write("# Yes: starts the game in fullscreen\n")
 fw:write("# No: starts the game in a window\n")
 fw:write("Fullscreen = ")
 if Conditions["cfg_fullscreen"].Value then fw:write("Yes\n") else fw:write("No\n") end

 -- * resolution * --
 fw:write("#\n")
 fw:write("# Resolution = {Auto|Desktop|Custom}\n")
 fw:write("# Auto: wide-screen support is activated if a wide-screen display is detected\n")
 fw:write("# Desktop: current desktop resolution is used when game is started in full screen mode\n")
 fw:write("# Custom: enter a custom value eg: Resolution = 1920x1080\n")
 if Conditions["cfg_fullscreen"].Value then fw:write("Resolution = Desktop\n") else fw:write("Resolution = " .. Values["cfg_res"].String .. "\n") end

 -- * subtitles * --
 fw:write("#\n")
 fw:write("# Subtitles = {Yes|No}\n")
 fw:write("# Yes: show subtitles during the game, cut scenes & videos\n")
 fw:write("# No: do not show subtitles during the game, cutscenes or videos\n")
 fw:write("Subtitles = ")
 if Conditions["cfg_subs"].Value then fw:write("Yes\n") else fw:write("No\n") end

 -- * text speed * --
 fw:write("#\n")
 fw:write("# TextSpeed = the speed of the displayed text {0-100} \n")
 fw:write("TextSpeed = " .. game.TextSpeed .. "\n")

 -- * text language * --
 fw:write("#\n")
 fw:write("# TextLanguage = {English|French|German|Spanish}\n")
 fw:write("# this will display subtitles in the specified language\n")
 fw:write("TextLanguage = " .. game.StandardLanguage:getName() .. "\n")

 -- * speech language * --
 fw:write("#\n")
 fw:write("# SpeechLanguage = {English|French|German|Spanish}\n")
 fw:write("# this will play speech files linked to the specified language\n")
 fw:write("# if no speech language is provided then the speech language will default to the standard language\n")
 fw:write("SpeechLanguage = " .. game.SpeechLanguage:getName() .. "\n")

 -- * speech timeout * --
 fw:write("#\n")
 fw:write("# SpeechTimeout = {Yes|No}\n")
 fw:write("# Yes: always wait for mouse click to continue the dialogue\n")
 fw:write("# No: do not wait for mouse click to continue the dialogue\n")
 fw:write("SpeechTimeout = ")
 if Conditions["cfg_speech_timeout"].Value then fw:write("Yes\n") else fw:write("No\n") end

 -- * log level * --
 fw:write("#\n")
 fw:write("# LogLevel = {Info|Warning|Error}\n")
 fw:write("LogLevel = " .. lglvl .. "\n")

 -- * volume settings * --
 fw:write("#\n")
 fw:write("# MusicVolume|SoundVolume|SpeechVolume|MovieVolume|GlobalVolume = int value {0-100}\n")
 fw:write("MusicVolume = " .. getVolume(eMusicVolume) .. "\n")
 fw:write("SoundVolume = " .. getVolume(eSoundVolume) .. "\n")
 fw:write("SpeechVolume = " .. getVolume(eSpeechVolume) .. "\n")
 fw:write("MovieVolume = " .. getVolume(eMovieVolume) .. "\n")
 fw:write("GlobalVolume = " .. getVolume(eGlobalVolume) .. "\n")
 print("new settings successfully written to " .. fn)
 fw:close()
end

 

The main two functions of the above script are:

 

    • read_ini() – used to read data from the config.ini and update your game’s relevant settings at startup. Call it inside an execute script action in your game’s Start Action.
    • write_ini() – used to write data to the config.ini. To use this just create a condition cfg_update (default false) and set it to true any time the player adjusts a setting. Now in your settings screen, create an ‘At end of scene’ action with the following Execute Script action:

 

if Conditions["cfg_update"].Value then 
  Conditions["cfg_update"].Value = false 
  write_ini()
end

 

If for any reason you need to delete the config.ini file at some point you can do so with:

 

os.remove(localAppDir .. "/config.ini")
Yes No Suggest edit
3 of 3 users found this section helpful

Resolution Handling #

Setting the game’s resolution

 

One of the first (and most important!) 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

 

Adjusting the window size

 

For window modes, you may adjust the screen size on the fly with Lua:

 

local ScreenMultiplicator = 6; // let's say we want to make the window 6 times bigger
setWindowSize({x = 320 * ScreenMultiplicator, y = 200 * ScreenMultiplicator})

Pixel Art Games

 

By default, Visionaire uses Linear interpolation for the graphics output which is more suitable for higher resolution games. If you are using pixel art though and want to keep the crispiness, you need to change to Nearest Neighbor interpolation by activating the pixel  effect in game properties:

 

Yes No Suggest edit
4 of 4 users found this section helpful

Text Handling #

Using Values and Strings in Display Texts

 

  • Integer values: <vi=valuename>
  • String values: <vs=valuename>

 

Text Pauses

 

You can control how long a text will be displayed for by using <p> tags after the text as follows:

 

Wait until left mouse button is clicked to continue <p>
Continue after 2500 milliseconds (ms) <p2500ms> 
Continue after 2.5 seconds (s) <p2.5s> or <p2.5>
Wait until linked speech file has finished playing <pa>
Wait until linked speech file has finished playing (with fallback time (in ms) if media file is missing or corrupted <pa2500ms>
Automatic pause <pt> (character count * 130ms * VGameTextSpeed%)

Adjusting Text Speed

 

By default the display time of a text depends on the number of characters. Internally Visionaire waits for 130ms per char. So if the current text has 30 chars (including blanks, etc) it will display for 30 x 130 = 3900 ms. You can adjust this time as follows:

 

game.TextSpeed = 100 -- default value (in %), lowering it will slow text down.

Wait for Click to Skip Text

 

By implementing the textStarted event handler you have a faster way to make all your game’s text skippable only with a click and not depending on any display time:

 

function sText(text)

  if Conditions["manual_skip_text"].Value then -- create the 'manual_skip_text' condition somewhere in your game.
    text.TimeToWait = -1 -- this adjusts the total time (in msec) for showing current text. Setting this to -1 waits indefinitely for a click.
    text.WaitForAudio = false -- it ignored any linked audio file 
  end 

end 

registerEventHandler("textStarted", "sText") -- event handler for begin text

Intercepting and Changing Text on the Fly

 

We can use a hook function to listen for texts at runtime and replacing them (by returning a different text):

 

function textFunc(obj)
  if obj.CurrentText == "abc" then
    return "def"
  end
  return obj.CurrentText
end
registerHookFunction("textText", "textFunc")

 

 

 

Yes No Suggest edit
4 of 4 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

Adding a Scene #

To add a new scene, from the top toolbar:

 

 

Choose ‘Scene’ and enter a name.

 

Add a background by accessing scene’s properties:

 

Yes No Suggest edit
2 of 2 users found this section helpful

Scene Transitions #

There are a couple of ways to change a scene, and they are quite straightforward using action parts.

 

1. Change to a new scene, relocate the character

 

Use the ‘Change scene’ action part. This will position the character to a specific object of another scene, align him as we need and change to this scene:

 

 

2. Change to a new scene of a specific character

 

We can change to a scene of any character we want using the ‘Change to scene of a character’ action part. Changing to current character can be useful also when returning to the game from a menu scene for example.

 

 

3. Show a scene or menu, without any character relocation

 

If we don’t need or want the character to be relocated at the time of scene change, we can just show a scene with the ‘Show scene/menu’ action part. We can relocate him manually later if we need. This action part can also show menus.

 

 

In all above action parts, you can define how the transition will be made:

 

    • Immediately show scene/menu. This will change to the scene/menu without any transition effect.
    • Fade to scene/menu. This will use a transition effect during the change.

 

Change the transition effect

 

For transition effects, the ‘Fade out and fade in’ effect is used by default. 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:

 

 

or with Lua:

 

game.FadeEffect = eShiftUp

 

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
    • Shift up
    • Shift down
    • Tunnel effect
    • Fade with shader

 

Especially for the tunnel effect, you can adjust how it looks with lua:

 

game.FadeCenter = {x=300,y=200} -- The position of the center of the circle when you fade out the scene
game.FadeInCenter = {x=600,y=700} -- The position of the center of the circle when you fade in the scene
game.FadeRadius = 200 -- You can have a nice blur effect around the circle center, define the radius here

Note: the change in the fade effect will remain until you change it again.

You may also check the below tutorial for more info.

 

Resources

 

Name Description Author
Scene Transitions PDF Tutorial on the Scene Transitions, check also the Youtube Video Part W. Kruger
Scene Transitions Project Files Visionaire Files for the tutorial W. Kruger

 

Yes No Suggest edit
0 of 0 users found this section helpful

Way Systems #

Way Systems tell the engine where the character is allowed to walk in the scene and how the scaling works as he moves around. To create a new way system for a scene:

 

 

You can assign a default way system to a scene through its properties.

 

Multiple Way Systems

 

You can use multiple way systems in a scene. This can useful in cases when you the way system of a system is modified, very common for example when doors open to reveal new areas. You can change the currently used way system with the relevant action part:

 

 

Each way system consists of way borders and way points, so let’s define them also.

 

Way borders

 

Way borders define the walkable area in the scene; any character cannot walk outside this area.

 

You define a way border by creating points; you’ll notice that your cursor will change to when you hover over the scene. Make sure you close the way border by moving the cursor over the first way point. Cursor will change to , click and you have your way border. Alternatively, you can close a way border by right clicking while you drag a way border point.