Scripting with LUA - Senscape/Dagon GitHub Wiki
Highlights of the language used for scripting, LUA
Using Objects
In LUA there are Classes and there are Objects.
A Class is like a template. The template describes what kind of information can be stored. The Dagon engine has built in a suite of Classes that are useful for writing a game. Each Class serves a different purpose. That is all you need to know about Classes as they are generally not used in a script. But when you want to know EVERYTHING about what you can do with an object, you often must read up on the Class somewhere. For Dagon though, it’s all in the following documentation.
When an Object is created, it uses its Class to describe how it is built. Many objects can be created from the same Class, and each object can hold different values of the same kind of information.
Example:
- One kind of Class in Dagon is called the Audio Class. The Audio Class describes an object that deals with sound.
A function that creates an audio object, for example ‘Audio()’, returns that audio object and it must usually be saved to a variable so that the object can be used, so if ‘meandog’ is a variable, then ‘meandog = Audio()’ creates an Audio object, then assigns it to the variable ‘meandog’. Later 'meandog' is used to do things with that object. - The information in Objects can be variables, constants and/or functions. Those can themselves be objects of various kinds, or in other words, objects can (and usually are) nested.
- The proper name for variables and constants inside an object are called ‘properties’. The proper name for functions inside an object are called ‘methods’.
By design, the properties and methods inside an object are designed to work well with each other, which makes sense. Reading and writing the properties or calling the methods within an object are how one typically treats with that object.
Example:
-
We’ve created an audio object referred to by ‘meandog’. The Class of the audio object allows certain things to be described in properties:
-
The filename of the audio’s sound file...................(‘filename’)
-
The volume of the audio when it’s playing................(‘volume’)
-
Whether the object loops repeatedly when it’s playing....(‘loop’)
-
Whether the object is currently playing or not...........(‘isPlaying’)
-
Also, the Audio Class describes methods for the Audio Object:
-
Start playing the sound............(‘start()’)
-
Stop playing the sound.............(‘stop()’)
-
Get the amount played so far.......('getPercent()')
-
So a sequence of script to create an object and do things with it might look like this:
-
meandog = Audio() ....................{create the Audio object}
-
meandog:filename = “lowgrowl01.oga”....{give it a sound}
-
meandog:volume = 40 ...................{set the initial loudness}
-
meandog:loop = true....................{set the playback to constantly looping}
-
meandog:start()........................{start playing the sound}
-
stillgrowling = meandog:isPlaying......{stillgrowling will equal ‘true’}
-
meandog:volume = 75....................{changes to louder while playing)
-
meandog:stop().........................{sound stops}
-
meandog:filename = “loudsnarl02.oga”...{change sound to something more nasty}
-
meandog:volume = 100...................{maximum loudness}
-
meandog:start()........................{more nasty sound start playing}
-
bigscarydog = Audio()..................{create a second Audio object}
-
bigscarydog:filename = “creepywhine01.oga”.....{add soundfile to second object}
-
bigscarydog:start() {second object starts playing while first is still playing. Since volume and loop weren’t set they must be using the default settings inside the object}
Note that like any function, methods may be designed to take parameters, and often it’s quicker when creating an object to set all the basic parameters up front, IF ALLOWED.
- Examples:
{these are examples only and do not exactly describe the Audio object in Dagon.} - meandog = Audio(“lowgrowl01.oga”, false, 20, STOP)
- meandog:start({volume = 40, loop = true})
The exact parameters and how to describe them is at Command Reference.
Using Tables
Another powerful and common element of LUA is the Table. Unlike the ways of yesteryear, LUA doesn't need different ways of describing different groups of data like structures or arrays. Virtually anything can be done with a table. A table in its simplest form is like an array. When a table is explicitly described, it is always surrounded by brackets. { }
Examples:
- To create an empty table and assign it to the variable ‘Emptylist’:
Emptylist = {} - To create a table and fill it with constant numbers:
Booksizes = {10,5,3,7}- to read one of those values: value = Booksizes[2] results in value = 5.
- to change one of those values: Booksizes[2] = 100
- To create a table and fill it with text string constants:
Booktypes = {‘paperback’, ‘novel’, ‘ebook’} - To create a complex table with with different types:
Books = {Booksizes, Booktypes} - to read a single value: gimme = Books[2][3] will set gimme to the string value 'ebook'. This shows that a table can be a collection of anything, like a Super Array. Tables inside tables give extra dimensions, like a 2-dimensional array (or more), but the so-called 'row's and 'column's can contain different kinds of information AND they don't even have to match in length. Very versatile!
But it gets even better!
- To create an 'associative' table
BookDetails = {[weightinlbs] = 5, [title] = "King James", [withDustJacket] = false}
Unlike the simple tables earlier, each location has a 'key' = 'value' entry.
The key is used to describe the location in the table, and the 'value' is the value at that location.
Because each location in the table has a name rather than a number, it can be retrieved from the table using the name.
Don't get confused, but those keys and values can be any type of variable (or constant) and they don't even have to match each other. Unlike the rest of programming, that equals sign is used only to associate the pair, not assign the value to the key like one might assume.
To read a value: gimme = BookDetails.title
To change a value: BookDetails.title = "Werner Herzog's Interpretation"
To add a new pair to the table: BookDetails.tearstains = true ... adds a new [tearstains] = true pair
To remove a key and it's value from the table: BookDetails.weightinlbs = nil
BTW, ALL tables are associative, but when we create a table like {'a','b','c'}, these are all values automatically assigned to automatically-created keys with the names 1,2,3, etc. It makes using tables like they are arrays much simpler. You can still grab a value from an associative table by the table[x] notation, which just counts key/value pairs x times and gets the value at that location. But that could get very confusing. And of course associative and simple tables can mixed it up!
This is only the tip of the iceberg with respect to tables.
The full scope is way beyond this intro but tables are used throughout Dagon to:
-
Pass a list of options to a function
i.e. Audio({loop = true, vol = 0}).....loop is a key, and its value is the boolean constant true
-in LUA, this is two values being passed. Because the table is an associative one, you can just pick what keys you want from the table and assign the allowed values for that particular key. You can pick 0 or more pairs to send. Any keys not assigned from the documented table will take on a default value defined inside the object when it was created. -
Describe a limited set of states
Bookstates = {open, closed, opening, closing}
Directions = {N,S,E,W} -
Describe an (associative) set of options
basketball options = {[inflated] = true, [used] = false, [clean] = true}
That is all for now, I'm tabling this primer until it's reviewed. :)