Scripting
From OrbEdit Wiki
Contents |
Scripting Overview
|
| Orb uses a programming language called Lua for its scripting. Scripting allows you to control your game through the Orb API without ever having to touch or recompile the actual source code of the engine. You can quickly make a change to a script and see the results immediately, often without even restarting your game. Scripts allow you to define the behavior of every object in your game, from how a monster reacts when you hit him with a fireball, to the way a menu bounces open when you press the menu key. Don't be intimidated by Lua! After a few quick tutorials, you will be rocking out. |
A script is any piece of Lua that, when run, does something. Some examples of scripts are:
- Lua string
-- Print the string "Hello Cleveland!" to the console print("Hello Cleveland!");
- Lua function
-- Moves the given Sprite 100 pixels to the right function MoveSpriteRight(sprite) sprite:move(100, 0); end
- Lua file
-- Scripts/Util/ReleaseShapes.lua -- Releases all Shapes from the World orb.getElements("//Shape"):release();
Orb uses a single Lua interpreter through which all scripts pass. This creates a common environment between all scripts, so every global functions and variables you declare will be available everywhere. Orb uses a modified C++ binding library called Lunar to externalize methods to Lua.
API Organization
Orb's API is made up of a set of methods and functions that can be used for anything from giving a Sprite a new texture, to getting the mass of a Body, to remembering your player's inventory when the game shuts down.
- This wiki makes the normal distinction between methods and functions. Methods belong to a class and functions do not.
Orb Libraries
In addition to the default set of libraries that come with Lua (such as the math, io, and table libraries), Orb provides 2 of its own function libraries named orb and orbx. The orb library is primarily for manipulating the World, and has functions that allow you to manage Layers, query sets of Elements, and write Elements to files. The orbx library is for extra utility functions, for things such as getting the elapsed time to resolving directory names. To call a function within either of these libraries, you must precede the function name with orb. or orbx., for example:
-- Call Orb's addLayer() function, passing in a new Layer orb.addLayer(Layer:new());
As you write new functions for your game, it's up to you whether you want to put them into the orb library, another library that you create, or no library at all. Libraries do offer an extra layer of organization for large projects.
- The complete list of functions that Orb provides is available in the API Reference.
Orb Classes
Each class within Orb has a set of methods that you can call. All methods are invoked with the normal Lua method-invoke operator ":". For example:
-- Instantiate a new Body and add a Circle to it local myBody = Body:new(); myBody:addChild(Circle:new());
Since many of a class's methods are getter/setter methods, Orb offers some syntactic sugar for calling these methods, using the "." syntax that is used for Lua tables. For example, Sprites have a getRotation() and setRotation() method, used to get and set the angular rotation of the Sprite. As a shortcut for calling these methods you can do the following:
-- Instantiate a new Sprite local mySprite = Sprite:new(); -- Set the Sprite's rotation to 100, then print out the new value -- This is the usual way of doing things, using getRotation() and setRotation() mySprite:setRotation(100); print(mySprite:getRotation()); -- Prints "100" -- Now do this again, using the shortcut syntax mySprite.Rotation = 42; print(mySprite.Rotation); -- Prints "42"
Any getter/setter method can be called this way; simply remove the "get" or "set" from the method name and use a "." instead of a ":". This syntax encourages the "property" paradigm found in newer languages like C# rather than the older "getter/setter" paradigm found in C++ and Java.
Dynamic Properties
Under the covers, Orb objects are nothing more than Lua tables. This allows you to make up arbitrary properties (known as dynamic properties) for your objects and get and set them through the same "." syntax described above. Make sure you choose a property name for which no getter/setter method exists, otherwise that getter/setter method will be invoked. For example:
-- Instantiate a new Circle and set a dynamic property called "flavor" on it local myCircle = Circle:new(); myCircle.flavor= "Grape"; print(myCircle.flavor); -- Prints "Grape"
The only difference between a dynamic property (one you make up) and a regular property (one that comes with Orb) is that a regular property has some internal meaning, such as the position on the screen which to render an object. Dynamic properties have no effect on the game other than the way your scripts use them. Think of them as a way to quickly set various flags on your objects and retrieve them elsewhere.
- Dynamic properties can store any type of data, however, be careful with userdata! Orb objects are not subject to the Lua garbage collector (they are collected by Orb internally), so make sure your dynamic properties are not deleted before the objects that point to them.
Multi-Operations
One of the most important functions in the orb library is orb.getElements(). This function allows you to query the World for different sets of Elements using XPath statements.
- XPath is simply a way to find a certain element within an XML document using a path-like notation like you would use to find a file in your filesystem. Don't worry if you're not familiar with XPath at this time, it is covered in much more detail in the API Reference.
For example, if you wish to find all Elements with the name "Apple", you could call:
-- Get a table that contains all Elements with their Name property set to "Apple" local apples = orb.getElements("//*[@Name='Apple']");
This will return to you a special Lua table containing all Elements which met your query. At this point, you can treat this table like all others. You can iterate through it, remove or add new things to it, or call methods on its elements. However, the thing that makes this table special is its ability to propagate all calls made on it to each of its elements. Consider the following:
-- Get a table that contains all Elements with their Name property set to "Apple" local apples = orb.getElements("//*[@Name='Apple']"); -- Release all those Elements the traditional way... for i,v in ipairs(apples) do v:release(); end -- ...or take advantage of the returned multi-operation table and do it in a single line apples:release();
This syntax allows you to quickly apply large operations to large sets of Elements. By choosing the right XPath query, you can quickly zero-in on exactly the right set of Elements and then modify all their properties at once with very few keystrokes.
- All Elements have a
:getChildren()method which behaves the same way asorb.getElements(). Use the multi-operation syntax to your advantage!
Calling Scripts
Scripts are invoked from 4 different places in Orb:
- Startup Script: When your game first starts, its startup script is executed. All initialization you need to do should be put in this file, such as loading Registries, preloading textures, or defining constants. You should also also load your game's first Level in this script, such as a title screen or logo.
- Every OrbEdit Project comes with a default startup script with directions for use inside it.
- Events: When an Event is fired, the script associated with it will be executed. This script will likely be a file in the Events directory, but can also just be a simple Lua string.
- Callbacks: Many methods in the API offer a callback feature that will alert you through a callback function when they have completed.
- Keypresses: Every time a key is pressed, the associated function in the active Input Handler is called.
Scripts can be run from OrbEdit too:
- Project Explorer View and QuickScripts View: Clicking the Execute
button after selecting a script will execute that script.
- Console View: Typing any Lua command into the command line and pressing Enter will execute that command.
