[ LiB ] | ![]() ![]() |
Game engines are tools that help program games. In Lua's case, some of these engines are open-source and some are not; some of them are aimed towards beginners and some towards advanced programmers. Some of these engines are established and complete, while others are still in raw alpha or a quiet beta. The range of engines out there is clear evidence of the language's popularity.
Arkhart is an original fantasy role-playing game that uses a unique engine called the Ark engine. The Ark engine and Arkhart itself are built upon lua and SDL. Ark provides tools, a 3D client, and lua scripting facilities to those who want to try their hand at 3D programming Lua-style. The Arkhart home page can be found at http://arkhart.nekeme.net/en/.
The Arkhart code was originally built with JavaScript and Mozilla's jslib, but it grew so large that the authors migrated to the current SDL platform. The Ark engine itself has a module for lua scriptables, and in particular the animation files (.anm) are defined with the lua module. The game AI is handled within its arkhart.lua file, which initializes through the lua AI library. Areas in the game also appear to be defined by lua files (quest.lua files to be exact).
Arkhart is published under the gnu General Public License. The Arkhart design team is currently looking for developers and authors in both English and French.
ClanLib is a multi-platform game development libraryperhaps one of the most popular libraries for amateur game designers today. The idea behind ClanLib is to take care of all the hard-to-develop deep functionality like sound mixing, setting up direct draw, and read-ing image files. ClanLib provides a way of dealing with sound, graphics, and networking.
ClanLib is licensed under the GNU Library General Public License and uses lua for extending itself and for scripting. It can also be extended and scripted with Ruby, and is discussed in a bit more length in Chapter 11 of this book.
Enigma is a "nearly complete" puzzle game inspired by Atari's Oxyd and Amiga's Rock'n'Roll. Enigma is free software, with the executables and source distributed under the General Public License; it can be downloaded at the creator's Website, http://www.nongnu.org/enigma/.
Version .70 is also included on the CD in the Chapter 8 file section. Currently, executables for both Windows and Macintosh are included with the latest release, although Enigma should be playable on Posix operating systems with a bit of tweaking.
Enigma has been developed by volunteers and has a few community sites that offer levels and encouragement to new users and level designers. The game is engineered using Lua, SDL, and Oxydlib, which is a C++ library. lua holds the distinction of being the primary language for coding different levels. Enigma is an excellent example of a cross C++/Lua project, and also a good example of how to tie the ability to script levels into a product; for these reasons, I'm going to spend some time focusing on how it works in this section.
The Enigma world is a 2D area in which the player travels in the guise of a rolling black ball (see Figure 8.1). The first step in creating a level in Enigma is to create a map of the world for the player to exist on:
create_world(10,10)
This creates a 10x10 block world map. Once the map has been created, each point on the map can be accessed like a grid. The upper-left corner is always (0,0) and, in this case, the map's lower-right corner is (9,9), as you are counting from 0.
Enigma has a number of different stone tiles (prefixed by st-), icons (prefixed by ix-), items (prefixed by it-), floor tiles (prefixed by fl-), and two players (ac-blackball and ac-whiteball), although player two is currently unimplemented in the engine. These can be used to populate the world that the player travels in. Many of the standard tiles and game pieces are listed in Tables 8.1 through 8.5, although it is also possible to create your own. The Xs used in the object names indicate wildcards, where there are multiple similar tiles (for instance, there are several st-oneway_X tiles, a few examples being st-oneway_white-s, st-oneway_black-s, and st-oneway_white-n).
Object | Description |
---|---|
ac-blackball | Player piece |
ac-whiteball | Second player piece (currently unimplemented) |
Object | Description |
---|---|
fl-abyss | Abyss floor style |
fl-bluegray | Two color combo tile |
fl-bluegreen | Two color combo tile |
fl-brick | Orange brick style floor |
fl-bridge | Bridge tile can be open or closed |
fl-dunes | Sand tile |
fl-gradient | Fading tile set |
fl-gray | Gray tiles |
fl-hay | Straw texture |
fl-himalaya | Blue snowy tile |
fl-inverse | Inverse of fl-normal |
fl-leaves | Green forest tile |
fl-marble | Golden stone |
fl-metal | Metallic tiles with different rivets |
fl-normal | Metallic tile with four corner rivets |
fl-plank | Wood floor, planks are cross stitched |
fl-rough | Granite-looking |
fl-sahara | Desert tile |
fl-samba | Stone tile segmented into four pieces |
fl-sand | Desert tile |
fl-space | Black with multi-colored stars |
fl-stone | Generic stone floor |
fl-tigris | Light marble looking floor |
fl-water | Water floor style |
fl-wood | Wood floor, four even strips per tile |
fl-woven | Escher-like black and white weave |
Object | Description |
---|---|
ic-actor | Player icon |
ic-arrow | Mouse pointer |
ic-bottom | Directional arrow |
ic-down | Directional arrow |
ic-floor | Section of 3D grid |
ic-stone | Picture of 3D block |
ic-top | Directional arrow |
ic-up | Directional arrow |
Object | Description |
---|---|
it-blackbomb | Exploding bomb |
it-brush | Paintbrush |
it-coin | Money piece |
it-crack | Crumbling segment |
it-document | Scroll |
it-dynamite | Stick of dynamite |
it-extralife | Black ball (player piece) |
it-floppy | Floppy disk |
it-hammer | Hammer |
it-hill | Tile bubble simulates a hill |
it-hollow | Concave tile simulates a depression or hollow |
it-key | Key |
it-laserX | Different item tiles for laser items |
it-magicwand | A magic wand |
it-magnet-off | Magnet with no animation |
it-magnet-on | Magnet with animation |
it-pipe | Pipe segments |
it-seed | Small seed bits |
it-shogund-X | A Shogun dot, in small, medium, and large sizes |
it-spade | Shovel |
it-spring1 | Uncompressed spring |
it-spring2 | Compressed spring |
it-surprise | Gift package with a question mark over it |
it-sword | Sword |
it-tinyhill | Smaller hill |
it-tinyhollow | Smaller hollow |
it-trigger | Metallic trigger grate |
it-umbrella | Umbrella |
it-wormhole | Animated spinning wormhole |
it-yanying | Reversed yin-yang symbol |
Object | Description |
---|---|
st-black | Different stones with black designs |
st-block | Standard gray stone block |
st-bluegray | Blue and gray fading stone |
st-bolder | Stones with different directional arrows |
st-break | Breaking stone animation |
st-brick | Brick wall |
st-brownie | Brown earthen wall |
st-coinslot | Wall with slot for coin |
st-death | Stone with skull and crossbones |
st-death-munch | Skull and crossbones animation |
st-doorX | Different stone doors |
st-fakeoxyd=blink_X | Different blinking stones / oxyd pieces |
st-floppy1 | Stone for accepting it-floppy items |
st-floppy2 | Stone with it-floppy inserted |
st-glass | Stone with white glass design |
st-grate1 | Closed grate |
st-grate2 | Open grate |
st-greenbrown | Earthen green-brown stone |
st-key1 | Keyhole with no key |
st-key2 | Keyhole with key |
st-laser-X | Different stone tiles for lasers |
st-magic | Stones with a keyboard look and numbers on them |
st-marble | Generic marble stone tile |
st-metal | Generic metal stone tile |
st-mirror-movable | Movable mirror tile |
st-mirror-static | Static mirror tile |
st-mirrortempl_X | Different tiles for mirrors |
st-oneway_X | Different stones with directional arrows |
st-oxydX | Oxyd stone (many different game object stones) |
st-plain | Generic plain stone wall |
st-puzzle | Different pipe tiles |
st-rockX | Several differently colored rock tiles |
st-rubberband | Rubber band tile |
st-scissors | Open scissor stone |
st-scissors-snip | Closed scissor stone |
st-shogunX | Several Shogun stone tiles |
st-stoneimpulse | Impulse stone animation |
st-stoneimpulse-hollow | Hollow impulse stone animation |
st-swap | Broken circle |
st-switchX | Different stoplight stones |
st-thief | Thief stone animation |
st-timer | Stone that triggers timed events, animated |
st-timeroff | Triggered stone timer, no animation |
st-white | Different white stone tiles |
st-wood | Stone tile with wood design |
st-woven | Escher like white weave design |
st-yellow | Yellow stone tile |
st-yinyang1 | Yin-yang stone tile design |
There are a number of functions for creating levels; these are listed and described in Table 8.6.
Function | Purpose | Arguments |
---|---|---|
AddRubberBand | Connects actors and stones that are then pulled together with given strength | Actor, object, strength, length |
create_world | Sets base map | Width and height |
def_stone | Defines st-stone | Stone name, sound |
def_floor | Defines fl-floor | Floor name, friction, and mouse factor |
draw_checker- board_floor | Draws floor alternating between two tiles | floor1, floor2, location (x,y), size (height,width), attributes |
draw_border | Adds a border to the level | Given stone (optional: location in x,y,z coordinates and height + width) |
draw_floor | Draws given fl-floor | Floor name, x and y coordinates and increments, and attributes |
draw_items | Draws given it-item | Item name, x and y coordinates and increments, and attributes |
draw_stones | Draws given st-stone | Stone name, x and y coordinates and increments, and attributes |
fill_floor | Fills area with particular st-floor | Floor name, attributes, x and y coordinates |
fill_items | Fills area with given item | Item, coordinates (x,y,z), size (height) |
fill_stones | Fills area with given stone | Stone, coordinates(x,y,z), size (height) |
GetAttrib | Returns current attribute value | Object, attribute name |
make_object | Creates an object on the map, used internally by other functions | name and attributes |
set_actor | Creates a moveable object (actor) | Name, x and y coordinates, attributes |
set_attrib | Sets an object's attribute | The object, value and a key |
set_attribs | Sets several attributes at once | Object, attributes |
setDefaultAttribs | Used when placing many objects with same attributes | Object name, attribute |
set_floor | Sets given to fl-floor | Floor name, position (x,y), attributes |
set_item | Sets given to it-item | Item name, position (x,y), attributes |
set_stone | Sets given to st-stone | Floor name, position (x,y), attributes |
set_stones | Sets given to st-stone, but takes multiple position arguments | Stone name, positions (x,y), attributes |
There are also a few standard preset variables in Enigma, the most common being the following:
level_width level_height oxyyd_default_flavor EAST WEST SOUTH NORTH TRUE FALSE
After using create_world to begin an Enigma level, the next step is usually to create a frame of stones as a border around the map using the draw_border command. To set a border to the st-woodtile, do this:
draw_border("st-wood")
That's pretty simple. Now to fill the floor. By feeding draw_checkerboard_floor with the upper-left corner of the fill (as x and y coordinates), the map height and width (which are defined in constants already), and the two floor tiles, the floor can be filled in with alternating desert tiles:
fill_floor("fl-sahara","fl-sand",0,0, level_width, level_height)
Now that there is a filled map, you can use set_stone functions to create objects on the map. The set_stonefunction needs to know the type of stone and coordinates on the map and must be given a unique name (which is given as an attribute in curly braces):
set_stone("st-grate", 4,7, {name="My_Stone"})
The trick to solving a level is finding the matching onyx stones. To set these, you could also use set_stone:
set_stone("st-onyx", 1,1, {name="My_oxyd"})
But luckily the Enigma designers made it even easier. To save a bit of typing, use the oxyd command:
oxyd(1,1) oxyd(2,2) oxyd_shuffle()
These commands populate four game pieces, and then oxyd_shuffle permutes the colors on the oxyd stones within the landscape. After creating the map and the game pieces, the final step is to create the player on the map using set_actor using the same general conventions. The player attribute should always be player=0 for the purposes of the current engine code; 5,5are the starting x,y coordinates, and ac-blackball is the player piece:
set_actor("ac-blackball", 5,5, {player=0})
The Enigma source code (also included in the Enigma file folder on the CD) comes with a documents folder that includes more detailed instructions for level design, as well as many level examples (over 100) for the budding builder. The source itself is a great example of using lua in combination with SDL.
Gime is a two-dimensional game development platform primarily used for fast prototyping. Gime uses SDL as the graphics system, and has an API that is scriptable with Lua. Gime also comes with a GUI system for creating windows and dialog boxes. Gime is written in c and is basically a glue language layer between SDL and Lua. It is currently only in prerelease (alpha) and is available at its homepage under the GNU Public License, http://www.gime.org/.
The Gime API actually has two important lua parts: a LuaGUI library and a LuaUtil library. The LuaGUI library is capable of handling different typefaces and images. Its typface command supports both BDF and TF fonts, as well as different styles and sizes of text. Image processing is done with a wrapper to several SDL functions and allows Gime, through an image command, to create colored surfaces for text with standard opaque and alpha and colorkey settings. The GUI also supports drawing routines for filling and updating surfaces, events processing for returning information on keyboard presses and mouse movements, and a few miscellaneous functions for tracking frames, timing, and debugging.
The LuaUtil library is used for file manipulation, string manipulation, bitwise operations, and creating cache tables, which Gime uses to store value types (tables) and weak references. Gime currently requires lua 4.0, SDL 1.2 or higher, SDL_image, SDL_ttf, freetype 2.0, and SDL_mixerfor music.
The HZ Engine is a development project by David Jeske, who wanted to re-create Herzog Zwei, a classic Sega Genesis game released in 1990 by Technosoft. Herzog Zwei was one of the first real-time strategy games and a precursor to popular titles like Command and Conquer, Total Annihilation, and Age of Empires.
Since its creation, HZ has grown into a rough platform and a nearly full real-time strategy game engine. The original version was built for Windows, but David Jeske has ported the latest to run on Linux/Xwindows. Features include
A sprite and tile engine
2D hardware blit support on Win32 (which makes it a very fast engine)
8- or 16-bit color
Third-person RTS-style view
lua scripting
HZ uses an older version of lua (3.1) and c as its primary driver. Since many of the game's features are based on the embedded Lua, you can interactively query for information about the game using the lua console. The backtick (`) key will bring up a lua console while the game is being played, and you can actually script and write new code from the text console. In its current implementation, you can, by using the backtick, toggle between the game screen and the prompt that accepts Lua.
Besides being able to script events live and experiment with the lua console while playing the game, you can completely define sprite objects using Lua. This includes everything from UI to behavior to physics.
Browsing through the source of the game (which is also available on the project Website), you can see that the engine initiates an init.lua file during the game startup. The lua.init file loads up the other necessary lua files (using the dofile command from Lua's basic function libraryrefer to Chapter 5 for more).
Sprite initiation is one of the things lua controls in the HZ Engine. Visually, the sprites are defined within the visrep.lua file, where you can find the code that creates the sample bases and tanks in HX. David Jenke also includes a sample sprites.lua file with examples of how to create the visual representation. A sprite that only uses one image would look like this:
SimpleSprite = {"image.bmp"}
A more complicated image with several images to indicate an animation or different traveling directions would include those images and an index:
ComplexSprite = { { "image1.bmp" }, { "image2.bmp" }, { "image3.bmp"}, { "image4.bmp" }; IndexedBy = "CSprite" }
The IndexedBy line tells the HZ Engine what object variable holds the array (table) of images. The game engine reads these values to determine which to draw (the default is the first image). You can choose one of the other images by setting the image_frame in the code.
The sprite logic, as well as the sprite images, are defined with Lua. The engine runs in frames, and in each frame sprites are redrawn, key presses are listened for, and sprite collisions are detected.
NOTE
CAUTION
In the existing code files, these image declarations are followed by a number of zeroes. The zeroes were for functionality that was never implemented, and they are no longer relevant or necessary, but they may cause confusion because of the obvious difference between the existing code base and the code samples.
Each sprite also has a doTick() method that is called at each iteration of the engine. The doTick method can be used to decide which image to show and set the object properties for. These properties can be anything you can dream up in Lua, but Jenke has reserved some functions in c so that the engine runs at an optimal speed. These functions are highlighted in Table 8.7.
Function | Purpose |
---|---|
C_obj_delete(objnum); | Removes a sprite |
C_obj_viewFollow(objnum); | Main camera will follow this sprite |
C_obj_getVelocity(objnum); | Gets the velocity of a sprite |
C_obj_setVelocity(objnum,vx,vy); | Sets the velocity of a sprite |
C_obj_getPos(objnum); | Gets the position (x,y) of a sprite |
C_obj_setPos(objnum,x,y); | Sets the position (x,y) of a sprite |
C_obj_setLayer(objnum,layer_number); | Sets the graphic layer of a sprite |
These functions take in objnum as their first parameter and x,y coordinates to follow. For instance, here's how to get an object position:
Co_obj_getPos(self.objnum);
and here's how to set the position:
Co_obj_setPos(self.objnum, 100, 80);
Having the C++ engine do the range checking and math greatly speeds up the HZ Engine. C++ is also used to handle collisions. Each sprite in HZ has a ge_collision() method. The point of a collision given by x and y parameters and the object that is hit are provided by a whoIhit parameter, which is a lua script object.
The keyDown and keyUp event methods detect which keys are being held down. Key methods vary between platforms, making it difficult to design cross-platform, but they should suffice for game events. The inputEvent is used for taking in a name or typing strings from a player. More HZ documentation, the binaries, and source code can be found at David Jenke's Website and HZ project page, at http://pulp.fiction.net/~jeske/Projects/HZ.
Lixoo is a small, 2D, mouse-driven adventure game engine designed for conversation and character-based computer games. Lixoo consists of both the driving graphics engine and also a number of tools for users to build their games with. The main use of lua in Lixoo is as an IDE with modules for creating rooms, characters, music, and animation.
Currently, Lixoo is under development and works only on OS X and Linux. It was originally written with ZeroForce (a small c library) but has since moved to C++. Lixoo's project page can be found on Sourceforge at http://lixoo.sourceforge.net/cgi-bin/cgilua/content.html?section=files.
Lune Mud is a text-based, multiuser dungeon that uses a modified lua interpreter. lua provides the functionality for sockets, time, and directory listings. Lune Mud runs on linux and Win32 platforms and was written by Jason Clow.
Lune Mud is in early development but is playable. It is licensed under the gpl and can be found at Sourceforge, at http://lune.sourceforge.net.
An adventure-game project based on the classic Sierra Quest games, MADProject is an opensource, cross-platform, script-driven game engine, and, yes, lua is the script that drives it. In its current iteration (as of this writing) MAD runs only on DOS and Windows, but the community is working on porting to Macintosh and Posix systems as well.
The MADProject was founded by Rick Springer. More recent development has been undertaken by project leader Nunzio Hayslip and lead programmer Javier Gonzalez, and Posix porting is being tackled by Christopher Reichenbach. MAD features include the following:
Sprite animation
Pathfinding
An in-house GUI
Music and sound effects (MIDI, WAV, and MP3)
A Lua-based scripting interface
Windows machines must have a DLL file (alleg41.dll) placed on their path or within their systems folders in order to run the MAD sources and binaries. The engine comes with an example game called Lambazzo, whose code is the basis for the code in this section.
MAD leverages a number of other community resources besides Lua, in particular the allegro, alfont, almp3, and zlib libraries. It comes equipped with an interpreter and several utilities, all within the tools directory of the MAD source tree. Besides Lua, MAD also uses its own proprietary file format (*.mad), MAD animation files (*.anm), image files (*.img), and graphical scen files (*.scn).
The official homepage for MAD is http://mad-project.sourceforge.net. There is also a Sourceforge project page, at http://sourceforge.net/projects/mad-project/.
MAD accepts and uses full-force Lua. lua is used to set variables and tables, perform loops, operate math, and set control structures. The latest version of MAD (of this writing) is 1.9 and is included in the Chapter 8 section on the CD.
MAD relies on a number of specific files. It searches the computer's primary archive for stdmad.lua and main.lua, the first two scripts it needs to run. Another important file is mad.cfg, which is used to determine the primary file archive and what screen size to set the display to. The mad.cfg file has the standard format of a Windows .ini file. You can also prompt mad.cfg to run in safevideo mode. Another important file is stdmad.lua, which can be hacked to alter or add custom actions and cursors to MAD.
MAD files (*.mad) can be created with the MAD File archive Manager (Mfile). Mfile can compile many game resources into a single compressed data file. Mfile is used to build MAD archives and compress the files MAD will use. The command line is used to run Mfile, and Table 8.8 lists a few of Mfile's runtime flags.
Switch | Use | Example |
---|---|---|
< | Use a script to build a MAD file | mfile n MyFile.mad < MyScript.in |
n | Create a new archive | mfile MyFile.mad |
None | Open an archive | mfile MyFile.mad |
The MAD Scene Generator (Scengen) takes as input a background image, a mask image, and a wasc image, and puts them all together to create a scene. Scengen.exe combines these three images (normally bit-map layers) into one format, a .scn format, that the MAD engine can read and use. This is done via command all on one line, naming the scene (MyScene) and then feeding the three bitmaps:
secnegen.exe MyScene.scn background.bmp mask.bmp wasc.bmp
After you create scenes you can view them with the MAD Scene Viewer, Sceneview. Sceneview can also be loaded with alternate resolutions by designating them on the command line. For instance, to load a scene at 640x480, do this:
scenview.exe MyScene.scn 640 480
The F10 key can be used to write bitmaps in scenview.exe into the current directory.
MAD's animation Generator (anmgen) creates the animation file types (.anm) MAD uses. To create an animation file, you need to give anmgen the animation-creation script file (.asr) and the generated animation file (.anm) on the command line:
anmgen.exe MyScript.asr MyAnimation.anm
Animation script files have two sections separated by three percentage symbols: %%%. The first section lists all of the frames filenames to be used in the sub-animations:
walking1.bmp walking2.bmp walking3.bmp %%%
The second section lists all of the frame filenames that are used in the sub-animations. First, the sub-animation is named, then, in parentheses, the time to display each of the frames is given:
walking(10)
A comma can be used to designate flip flags, with a 0 indicating no flipping, a 8-n-1 designating a vertical flip, a 2 designating a horizontal flip, and a 3 designating a vertical and a horizontal flip:
/* no flipping*/ walking(10, 0) /*Vertical Flipping*/ walking(10, 1) /*Horizontal Flipping*/ walking(10, 2) /*Both Horizontal and Vertical Flipping*/ walking(10, 3)
After the flip frame is designated, the frame numbers are listed, separated by a space:
walking(10) 0 8-n-1 2
There is also an anmview.exe utility for viewing animation files. It loads up the animation in a viewer; then the spacebar can be pressed to play the current sub-animation. The arrow keys can be used to change the currently displayed frame.
Imgconv is an image d-converter that converts .bmps to MAD's image format, .img. It can convert a BMP file to a MAD image file or vice versa.
NOTE
MAD runs in 320x420 video mode with high resolution (16, 24, or 32bpp) by default.
Some video cards no longer support the classic 320x240 in 16/24/32 bit modes, and you may receive errors (something like "You need a direct x compatible video card") when trying to run MAD games. There is a safevideo command switch, mad.exe safevideo, that you can run to get around this issue.
MAD has an API that performs various system and engine tasks and sends information to the kernel. The functions are listed in Table 8.9.
Scenes are the background of a MAD game. Each scene is composed of three bitmaps: a 24-bit background, an 8-bit mask, and an 8-bit walk/scale. See Figure 8.2 for a sample MAD game scene.
Function | Purpose |
---|---|
GetKey() | Returns code of the last key pressed |
GetKeyState() | Returns state of key constant passed to it |
GetKeyWait() | Returns code of the last key pressed, waits if nothing has been pressed |
GetMouseBtn() | Returns 8-n-1 if given mouse button is pressed down, 0 if it's not pressed down |
GetMouseX() | Gets X position of the mouse pointer in pixels from top left corner of the screen |
GetMouseY() | Gets Y position of the mouse pointer in pixels from top left corner of the screen |
GetTickCount() | Returns time in milliseconds since MAD has started |
LoadGlobals() | Used to load global variables or tables from a specified file |
RunScript() | Used to have interpreter run through and add any functions or variables from a given script into the global environment |
SaveGlobals() | Saves global variables or tables to a specified file |
SetGUIArchive() | |
SetMadSpeed() | Specifies the update speed in milliseconds; speed value of 8-n-1 is maximum speed |
SetMasterVolume() | Used to set digital, MIDI, or MP3 volume from 0 (quiet) to 255 (loud) |
SetObjectArchive() | |
SetSceneArchive() | |
SetScreenFX() | Specifies an FX filter to apply to a screen after the sprites are drawn |
SetSoundArchive() |
Create a scene with the following steps:
Assign a name (and initial memory) to the new scene.
Assign a particular script for the scene to run.
Load the actual scene file into RAM.
Start the scene running.
Step 8-n-1 is accomplished using the NewScene command:
My_Scene = NewScene()
The SetScript command is used to accomplish Step 2:
My_Scene:SetScript("My_Script.lua")
Loading the scene file into RAM, Step 3, is done with the Load command:
My_Scene:Load("My_Scene_File.scn")
And then, finally, you run the scene. In this example, running the scene causes My_Scene_File.scn to be drawn and My_Script.lua to start executing:
My_Scene:Run()
A game will likely be composed of a number of different scenes; use the Run() function to jump from one scene to another.
There are a couple of other scene functions for dealing with loading and unloading scenes from memory. These include
SetFileName.Sets a scenes filename without loading it into memory.
Unload.Frees a scene's bitmaps from memory.
IsLoaded().Checks whether or not the bitmaps for a function have been loaded into RAM.
As I mentioned, every MAD scene is composed of three bitmaps. The first is the background bitmap. The background bit-map is the actual imagery used for the background, the illustration that sets the scene; it must be 24-bit.
The Mask scene is the second bitmap, an 8-bit bit-map that is used to designate objects the player can walk behind on a background scene. Build a scene by drawing solid gray masks of the objects and then drawing a rectangle around the objects. If the rectangles of two different masks intersect, then a different shade of gray must be used so that MAD can make a designation between the two objects. These rectangles can be created in scenegen.exe by right-clicking. The scenegen.exe right-click menu also grants access to a few drawing tools, including Pencil, Paintbucket, and Undo, with a right-click. The rectangle command actually writes the text you'll need for the mask to a file. When drawing these rectangles, be sure to start at the top-left and move to the bottom-right; otherwise, the script will give out negative numbers.
There is some scripting involved with the mask, as well. Each object's rectangle must be defined with a NewMaskObj() command, so that the engine understands the size of the objects and whether other objects are drawn in front of or behind them.
The WaSc layer is the third and final bit-map layer that makes up a scene file. WaSc is short for Walk Scale, and this bit-map designates which areas of the screen the player can walk in. Areas of this mask that are painted with an index of 0 are designated as not walkable by the player.
The WaSc is also an 8-bit bitmap. In addition to designating unwalkable areas, it can also set the scale of objects drawn at given points in the scene. Depending on the background drawing, you can set the distance scale of the sprites; this is also accomplished with the index value. An index of 50 draws the objects at 50 percent, or half their original size, while an index of 100 draws the sprites at their original size.
The point in a scene that determines where a sprite is to be drawn is always the middle bottom of the sprite. This is because this is where the feet of most characters in MAD would be in a drawn sprite.
Anything that a player can interact with in MAD is considered an object of some sort. The primary indicators of an object are that they move and that they are independent of their background. The steps for creating an object in MAD are as follows:
allocate memory for a new object.
Load any animations the object will use.
Set the object into a scene.
Set any object attributes, flags, or graphic filters.
Show the object.
Step 8-n-1 is accomplished with the NewObj command:
My_Object = NewObj()
This step has to done first before any other commands can be run on an object. Objects on the move are likely to use animations of some sort, so there is a LoadAnimation command that will load MAD animation files (*.anm) and set the animation facing and looping:
My_Object:LoadAnimation("MyAnimation.anm","My_facing", 0)
This loads up the MAD animation, sets the animation facing to My_facing (which is an attribute set within the animation), and sets the looping to 0. The SetScene function places the object within a scene at a certain position using (x,y) coordinates:
My_Object:SetScene(My_Scene, 10, 200)
There are a handful of attributes that may or may not be necessary for a given object; SetSize specifies the height and width of an object and SetSpeed specifies the horizontal and vertical speed of an object. Object flags are also commonly used by the engine. These flags are listed in Table 8.10.
Flag | Purpose |
---|---|
OBJFLAG_8WAYANIM | Tells MAD that the object contains eight sub-animations for directional movement |
OB JFLAG_ISCHARACTER | Sets object as a "character" |
OBJFLAG_ISEGO | Sets object as a player-controlled character |
OBJFLAG_ISEGOAND8WAYANIM | Sets object as both controlled character and containing eight sub-animations |
OBJFLAG_NOSCALE | Tells MAD to not rescale grap to fit the scene's wasc |
OBJFLAG_DRAWASBKG | Draws object as part of the background pass, before other objects |
OBJFLAG_DRAWASFRG | Draws object as part of the foreground, after other objects are drawn |
Graphic filters are set with the SetGFXFilter command and generally use a flag and a color (red, green, blue, or alpha) as input to create an effect when drawing an object on the screen. The following flags are defined within the stdmad.lua file:
GFXFILTER_TINT. Tints the color of an object
GFXFILTER_BLEND. Blends the object with its background
These flags work as expected. For example, let's say you want to have a few flags and manually set the speed and size of an object:
My_Object:SetSize(10,10) My_Object:SetSpeed(1,1) My_Object:SetFlags(OBJFLAG_ISCHARACTER + OBJFLAG_8WAYANIM) My_Object:SetGFXFilter(GFXFILTER_BLEND)
The last step in creating a MAD object is to actually show it. All objects by default in MAD start out invisible. You use Show to make them appear and Hide to make them disappear:
MyObject:Show() My_Object:Hide()
You can run a kill command to destroy or remove an object. Doing so will de-allocate memory applied to an object:
My_Object:Kill()
A number of MAD graphic functions just for objects exist; they are listed in Table 8.11.
Functions | Purpose |
---|---|
GetAnimFrame() | Returns current position of the sub-animation |
GetAnimState | Returns 0 if animation is stopped, and a 8-n-1 if animation is running |
LoadAnimation() | Loads a MAD animation into the object |
LoadImage() | Loads a MAD image into the object |
PauseAnim() | Pauses the current animation |
ResumeAnim() | Resumes the current animation (after pausing) |
SwitchAnim() | Changes current sub-animation and loop parameter |
You can set an object's position on the scene and move an object around by using the SetPosition command and giving MAD the (x,y) coordinates:
MyObject:SetPosition(1,5)
It isn't actually necessary to use SetPosition when first creating an object because SetScene will place the object into the scene. When an object needs to move, and move in an animated way, it is usually best to use MAD's built-in path-finding. Mad actually has a number of functions for creating mobile objects within its scene; these are listed in Table 8.12.
Function | Purpose |
---|---|
GetDistance | Calculates distance between two objects in pixels |
GetMaskDistance | Calculates distance between an object and a mask object |
GetPosition | Returns current (x,y) coordinates |
GetPositionChange | Returns the change in position of the object since the last frame |
GetSpeed | Returns speed of the object per frame |
SetPosition | Sets object position to given coordinates |
SetPositionTL | As above, except uses top-left positioning |
SetSpeed | Returns horizontal and vertical speed of the object per frame |
WalkTo | Object will walk to given coordinates. Object will move around any not walkable areas of the scene |
By default, each function (except where noted) uses x and y as the coordinates within the scene. By default, MAD places an object by its middle-bottom position, the idea being that it is easier to drop a character onto a flat (2D) floor if you're using a middle-bottom position. The functions that use top-left (TL) positioning are the exceptions to this MAD rule.
Certain object actions can be bound to script functions. This is done using a BindAction command and a number of object action flags. These flags correspond to cursors within the MAD GUI and are listed in Table 8.13.
Flag | Cursor | Purpose |
---|---|---|
OBJACTION_ARROW | ARROW | Calls function when arrow cursor is used |
OBJACTION_BUSY | BUSY | Calls function when busy cursor is used |
OBJACTION_CURITEM | CURITEM | Calls function when the currently selected inventory item cursor is used |
OBJACTION_CUSTOM | CUSTOM | MAD has space for custom, programmer defined cursors |
OBJACTION_DROP | DROP | Calls function when drop cursor is used |
OBJACTION_HELP | HELP | Calls function when help cursor is used |
OBJACTION_EGOWALKOVER | N/A | Calls function when EGO object walks over |
OBJACTION_LOOK | LOOK | Calls function when the look cursor is used |
OBJACTION_TALK | TALK | Calls function when the talk cursor is used |
OBJACTION_TARGET | TARGET | Calls function when target cursor is used |
OBJACTION_UPDATE | N/A | Calls function with every frame update |
OBJACTION_USE | USE | Calls function when the use cursor is used |
OBJACTION_WALK | WALK | Calls function when walk cursor is used |
While MAD uses standard objects to handle sprites and characters that actually move around the screen, it uses Mask objects for immovable background pieces and decorations. Mask objects are considered the second type of object in MAD, but Masks are stationary, and their graphics are taken from the scene files and mask layer. However, the code for manipulating Mask objects is nearly identical to the code for manipulating objects themselves.
Mask objects are set up just like standard objects, but since they are based on a mask and the background layer of a scene file, not all object functions are available to them. The functions that are available, and the functions that are unique to masks, are listed in Table 8.14.
Function | Purpose |
---|---|
BindAction() | As object function |
GetPosition | As object function |
Kill() | As object function |
Hide() | As object function |
NewMaskObj() | Creates a new Mask object with given scene, (x,y) coordinates, width height, and color index |
SetFlags() | Sets Mask flags |
Show() | As object function |
There is also a single Maskflag, MASKOBJFLAG_NODRAW, that will set masks to appear as part of the background but not be drawn.
The main player in MAD, otherwise known as Ego, has a number of functions with which to handle information and its display, but is otherwise just another MAD object. Ego is set with the flag OBJFLAG_ISCHARACTER, and must have a number of additional animations loaded with the following sub-animations:
eaststill eastwalk northstill northwalk southstill southwalk weststill westwalk
If the character is also set with OBJFLAG_8WAYANIM, it contains the following additional walking animations:
nestill newalk nwstill nwwalk sestill sewalk swstill swwalk
MAD comes with a built-in customizable GUI system that allows designers to
Alter the mouse cursors
Set fonts
Create buttons and bars
Create pop-up windows and boxes
Customize the GUI frame or skin
These commands are outlined in Table 8.15. There are a few UI boxes that are hard-coded into the engine. These include the basic menu, the choice box, and hello world message box.
Acceptable fonts for MAD include the following:
CFF
CID-keyed Type 8-n-1 fonts
OpenType (TrueType and CFF)
SFNT-based bit-map fonts
TrueType
Type 1
Windows FNT
X11 PCF
Function | Purpose | Notes |
---|---|---|
AddFloatingInput() | Creates a floating input box | |
AddFloatingText() | Creates and returns floating text object | |
Button_BindAction() | Binds a given function to the button | |
Button_Hide() | ||
Button_LoadAnim() | Loads an animation into the specified button | |
Button_LoadBmp() | Loads image file into specified button | Must be MAD image format |
Button_SetFlags() | Sets the button flags | |
Button_SetText() | Specifies the label of a button | |
Button_Show() | ||
ChoiceBox() | Displays question on screen with two choices | Hardcoded, can be positioned, stops game |
GetCursor() | Returns cursor_state | |
LoadCursor() | Specifies the mouse cursor animation | |
MenuBox() | Displays question on screen with several choices | Hardcoded, can be positioned, stops game |
MoveFloating- InputBox() | Moves given floating input box to given (x,y) coordinates | |
MoveFloatingText() | Moves floating text object to given (x,y) coordinates | |
MsgBox() | Window that displays messages on screen | Hardcoded, can be positioned, stops game |
NewButton() | ||
NewButtonBar() | Creates a bar that holds GUI buttons | |
RemoveFloating- ImnputBox() | Removes given floating input box | |
RemoveFloatingText() | Removes given floating text object | |
SetCursor() | Sets selected cursor state | States are listed in Table 8.16 |
SetCursorCycling() | Enables or disables right-clicking through cursors | |
SetCursorFocus() | Sets the cursor graphic focus point | Focus point is the (x,y) point in the mouse graphic that the screen considers "clicked" |
SetObjectUpdate- InGuiBoxd() | Turns GUI background animations on or off | |
SetSystemFont() | Loads a font file to be used as game text | Acceptable font formats follow |
SetTextButton- Outlines() | Turns text button outlines on and off |
Here are steps for creating a GUI button bar:
Create the button bar using MyButtonBar = NewButtonBar(10, 1, width, height). You must include x and y coordinates, width, and height.
Set any optional options, including a bar images and rgb values.
Add buttons to the button bar using MyButtonBar:NewButton(width, height, ox, oy). The width, height, and x, y offset are required.
Add any optional button arguments, such as a bound function.
Specify the button label with MyButtonBar:Button_SetText(MyButton, :"label").
Show the button bar on the screen with MyButtonBar:Button_Show(MyButton).
The MAD mouse pointer within the GUI has a number of states that can be set. This allows the player to perform a number of different actions. There are a few built-in mouse pointer states, as well as room for a number of custom states, each of which returns a different number. These possible cursor states are outlined in Table 8.16.
State | Number Returned |
---|---|
CURSOR_ARROW | 0 |
CURSOR_BUSY | 1 |
CURSOR_LOOK | 2 |
CURSOR_WALK | 3 |
CURSOR_TALK | 4 |
CURSOR_USE | 5 |
CURSOR_CURITEM | 6 |
CURSOR_TARGET | 7 |
CURSOR_DROP | 8 |
CURSOR_HELP | 9 |
CURSOR_CUSTOM1 | 10 through 42 |
The keyboard is managed in a similar way to the MAD engine, with each state returning a specific number. These numbers start with KEY_A = 1, KEY_B = 2, and so on. The standard GUI skin can also be used to create custom GUI boxes, which can possess animations and custom graphics. These graphics are also referenced by numbertop window border = 1, bottom window border = 2, and so on. For a complete listing of these GUI features, check out the documentation that comes with MAD and is also included on this book's CD.
MAD can load and play .wav, .voc, .mid, and .mp3 files for sound effects and music. To play sounds or effects in MAD, follow these steps:
Initialize the sound object.
Load the sound file.
Play the sound file.
Delete the sound file when it's done.
Step 8-n-1 is accomplished with a simple declaration, NewSound(), which loads a new sound structure into memory:
My_Sound = NewSound()
After the sound is in memory, you can use LoadWave or LoadMp3 to load a particular sound file:
My_Sound:LoadWav("My_Wav_File.wav")
Then play the sound using Play:
My_Sound:Play(0)
Playtakes input on how many times to loop the sound, in this case a big 0.
Finally, delete the sound using DeleteSound():
DeleteSound(My_Sound)
Playing a music loop is an almost identical process. The NewMusic command is used instead of the NewSound command, and .mid files replace .wav files, although MP3s can also be used with NewMusic:
My_Sound = NewMusic() My_Sound:LoadMidi("My_Wav_File.mid") My_Sound:Play(0) DeleteSound(My_Sound)
The MAD engine handles spells that the player casts and the items that he uses in a nearly identical way. Each is associated with an ID number, and the actions performed by spells or items are left for the programmer to script. The spells and inventory items are handled the same way. The ShowInventory and ShowSpells commands take in the following parameters:
x and y coordinates (x,y)
Back window texture (MyTexture.img)
Total size of the window (window_width, window_height)
x and y coordinates for the item box, where all inventory items are drawn in (itembox_width, itembox_height)
Any item box offset (itembox_ox, itembox_oy)
Icon size (itemicon_width, itemicon_height)
The Inventory window in game can be toggled on and off using the HideInventory command. Items within the Inventory box can be either bitmaps or animations. Inventory items are added to the window using AddItemToInv. AddItemToInv also takes in a number of parameters:
MyItem.img, which is the bit-map filename to use.
MyItem.anm, which is the animation filename to use.
Item Name is the name of the item.
Weight is how much the unit weighs in game units.
Quantity is how many units of the item stack up in the slot.
Description Message is the message that appears when the item is examined.
Finally, there are a number of functions available for MAD items and spells. These are outlined in Table 8.17.
Function | Purpose |
---|---|
f_use_item | Global function to call when the item is used |
f_combine_item | Name of function to call when the item gets used |
RemoveItemFromInventory() | Removes items |
SetCurInvItem() | Specifies the currently selected item |
GetCurInvItem | Retrieves currently selected item |
GetCurInvItemID() | Retrieves the currently selected item IDs |
AddSpellToBook() | Adds spell to spellbook |
RemoveFrom SpellBook() | Removes a spell from the spellbook |
GetCurSpell() | Returns currently used spell |
GetCurSpellID | Returns current spell ID |
This makes MAD very customizable; spells and inventory items can launch any of the code already mentioned, as well as operate familiar lua constructs.
[ LiB ] | ![]() ![]() |