Game Engines

[ LiB ]

Game Engines

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

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

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

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:

Figure 8.1. The Enigma world

graphic/08fig01.gif


 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 Tiles and Game Pieces

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 ).

Table 8.1. Enigma Players

Object

Description

ac-blackball

Player piece

ac-whiteball

Second player piece (currently unimplemented)


Table 8.2. Enigma Floor Tiles

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


Table 8.3. Enigma Icons

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


Table 8.4. Enigma Items

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


Table 8.5. Enigma Stone Tiles

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


Creating Enigma Levels

There are a number of functions for creating levels; these are listed and described in Table 8.6.

Table 8.6. Enigma Level Design Functions

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-wood tile, 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_stone function 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,5 are 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

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_mixer for music.

HZ Engine

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.

Table 8.7. HZ Engine's C Functions for Lua Sprites

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

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.

The Lune Mud Server

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.

The MADProject

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 Tools

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.

Table 8.8. Mfile Commands and Switches

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 bitmap 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 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 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 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 320 x 420 video mode with high resolution (16, 24, or 32bpp) by default.

Some video cards no longer support the classic 320 x 240 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 API

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.

MAD Scenes

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.

Figure 8.2. A sample scene from MAD

graphic/08fig02.gif


Table 8.9. MAD API Functions

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 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()

Sets the filename for an archive to store game files

SetMadSpeed()

Specifies the update speed in milliseconds; speed value of 1 is maximum speed

SetMasterVolume()

Used to set digital, MIDI, or MP3 volume from 0 (quiet) to 255 (loud)

SetObjectArchive()

Sets the filename for an archive to store game files

SetSceneArchive()

Sets the filename for an archive to store game files

SetScreenFX()

Specifies an FX filter to apply to a screen after the sprites are drawn

SetSoundArchive()

Sets the filename for an archive to store game files


Create a scene with the following steps:

  1. Assign a name (and initial memory) to the new scene.

  2. Assign a particular script for the scene to run.

  3. Load the actual scene file into RAM.

  4. Start the scene running.

Step 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 bitmap 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 bitmap 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 bitmap layer that makes up a scene file. WaSc is short for Walk Scale, and this bitmap 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.

MAD Objects

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 :

  1. Allocate memory for a new object.

  2. Load any animations the object will use.

  3. Set the object into a scene.

  4. Set any object attributes, flags, or graphic filters.

  5. Show the object.

Step 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.

Table 8.10. MAD Object Flags

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.

Table 8.11. Object Graphics

Functions

Purpose

GetAnimFrame()

Returns current position of the sub-animation

GetAnimState

Returns 0 if animation is stopped , and a 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


Path-Finding

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.

Table 8.12. MAD Path-Finding Functions

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.

Interacting with Objects

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.

Table 8.13. Object Action Flags

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


Masks

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.

Table 8.14. Mask Object Functions

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 Mask flag, MASKOBJFLAG_NODRAW , that will set masks to appear as part of the background but not be drawn.

Ego

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 

The MAD GUI

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 1 fonts

OpenType (TrueType and CFF)

SFNT-based bitmap fonts

TrueType

Type 1

Windows FNT

X11 PCF

Table 8.15. MAD GUI Functions

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()

Hides a button bar and all of its buttons

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()

Shows a button bar and all its buttons

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()

Creates a button inside of a button bar

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:

  1. Create the button bar using MyButtonBar = NewButtonBar(10, 1, width, height) . You must include x and y coordinates, width, and height.

  2. Set any optional options, including a bar images and rgb values.

  3. Add buttons to the button bar using MyButtonBar:NewButton(width, height, ox, oy). The width, height, and x, y offset are required.

  4. Add any optional button arguments, such as a bound function.

  5. Specify the button label with MyButtonBar:Button_SetText(MyButton, :"label") .

  6. 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.

Table 8.16. Possible Cursor States

State

Number Returned

CURSOR_ARROW

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 Sounds

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:

  1. Initialize the sound object.

  2. Load the sound file.

  3. Play the sound file.

  4. Delete the sound file when it's done.

Step 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) 

Play takes 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) 

Items and Spells

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 bitmap 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.

Table 8.17. MAD Item and Spell Functions

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 ]


Game Programming with Pyton, Lua and Ruby
Game Programming with Pyton, Lua and Ruby
ISBN: N/A
EAN: N/A
Year: 2005
Pages: 133

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net