Create an Account
Forgot your Password?
World of Warcraft
WowRiot
Starcraft 2
Starfeeder
Hellforge
Hellforge
 
Machinima
Myndflame
Left 4 Dead
Left 4 Dead
RazeTheWorld
RazeTheWorld
 
Quake Live
Quake Life
1337pwn
1337pwn
Limit Break
Limit Break
 
Resident Evil
Resident Evil Horror
Gameriot Store
Buy Games!
 
 
 
POST STUFF
close
New Blog Post
Add a Video
Host an Image
Upload a File
by kjado, Level 12
Last updated at July 4, 2009, 9:10 pm
This time on Making the Game, I'll be talking about some of the things occurring behind the scenes of our game-in-progress.  Script handlers for various frame elements allow us to add behavior to them, and objects provide a conceptual middle-ground for us to describe the entities in our game.

Script Handlers and How To Use Them
I mentioned in one of my previous posts that script handlers were one of the forms of event-driven programming present in WoW addons.  Frame elements can have snippets of code set to execute in response to certain events based on what type of frame it is, be it a button, editbox, or a handful of others.  The full list of frame types and their supported script handlers can be found at wowwiki.  If a frame has a script handler set for a specific event, when that event occurs a portion of code will be called and will have access to a few variables that provide more detail about the event.  We'll see an example of this shortly.

So how do we go about setting script handlers for our frames?  There are two ways to do it: define the handlers in the Scripts element of the frame's XML, or to call the frame:SetScript() function.  I'll give an example of both:

 - XML
<Frame name="TestFrame">
  <Scripts>
    <OnLoad>
      message("Hello world!")
    </OnLoad>
  </Scripts>
</Frame>

- Lua
local testFrame = CreateFrame("Frame", "TestFrame", UIParent)
testFrame:SetScript("OnLoad", function() message("Hello world!") end)

Both of these snippets of code will do the same thing, which is pop up a dialog box with the message "Hello world!" when the player first loads into the game (or reloads their interface).  In the XML file you can just toss the script handler code (in Lua) into the Scripts section.  The Lua function frame:SetScript() takes two arguments: the first is a string with the name of the handler to set, and the second is a function to run in response.

The OnLoad handler doesn't provide any additional information via variables (except for a self variable reference to the frame), so let's have a look at one that does, the OnMouseWheel handler:

<Frame name="TestFrame">
  <Size>
    <AbsDimension x="100" y="100"/>
  </Size>
  <Anchors>
    <Anchor point="CENTER"/>
  </Anchors>
  <Scripts>
    <OnMouseWheel>
      if ( arg1 == 1 ) then
        message("Up")
      else
        message("Down")
      end
    </OnMouseWheel>
  </Scripts>
</Frame>

This looks a bit different from the first bit of XML, but we needed to add some visual elements in order to use the mouse with the frame.  (Note that since no backdrop or textures have been added to the frame, nothing will really show up on the screen, though technically there is a 100x100 frame sitting in the middle of the screen now.)  When the player has their mouse over the frame and scrolls the mousewheel up or down, the script handler is called and does some branching based off of a variable named arg1.  For this script handler, arg1 holds the direction that the mousewheel spun (1 for up, -1 for down).  Using this information we can add mousewheel scrolling to list boxes and any number of other things.

For our game, we'll only need to utilize a few of these script handlers, but they will be incredibly useful.  To show and hide informative tooltips for the towers, blessings, and actions, we'll add some OnEnter/OnLeave handlers to the appropriate buttons to update the tooltip.  The buttons will also have OnClick handlers set to perform whatever task they are intended to, such as preparing a tower to be built or earning a blessing.  One interesting thing to note is that I decided to implement the grid of the game map as a group of smaller frames, which can then be used to set OnEnter/OnLeave/OnClick handlers to preview tower placement when the player goes to build a new one.  Additionally, each grid frame has its own texture to display the tower that is currently placed on it.

The most important script handler for us, however, is OnUpdate.  OnUpdate is called every time the player's screen refreshes, and provides a variable named elapsed which stores the amount of time (in seconds) since the last screen was rendered.  This is one half of the all-important game loop, and since we don't really have to do anything for the other half (drawing), this is where everything happens.  Inside the code called by OnUpdate we'll have to take care of all of the game logic: updating enemy positions, using tower abilities, firing projectiles, among other things.  Since elapsed is available to us, we can use it to accurately update our objects based on time instead of the number of screen refreshes, so gameplay should feel consistent between users who might experience different frames-per-second in game.

Making Something Out Of Nothing
First off, Lua is a scripting language, plain and simple.  It's not really meant to be an abstract, high-level development language, and that's fine.  But, it would be nice if we had some way to cleanly define and work with the conceptual game objects we'll have in our game, like the towers and enemies.

Thankfully, we have tables.  If you have programmed in other languages before, there's a good chance you are familiar with arrays.  If not, here's a little bit of an intro.  An array is ordered data structure that can hold items that are of the same type.  So, for instance, a list of numbers, or names (strings), etc.  The items stored in the array are indexed by integers corresponding to their positions in the array.  Some languages also support data structures called associative arrays, which are similar to the first type of array, but instead of indexing elements by integers, a key can be used instead (usually a string).

Tables in Lua are a combination of both the types of arrays just mentioned, in that there is an array portion of the table and an associative array portion.  Making and using tables is pretty straightforward, so let's take a look at a short example:

local myTable = {}

myTable[1] = 100
myTable[2] = "test"
myTable["zero"] = 0

Empty tables can be created with the {} brackets.  Alternatively, new tables populated with data can be created by including the elements within the {} brackets.  One thing to keep in mind if you are coming from other languages is that the array part of tables in Lua starts at 1 instead of 0 in languages like C, Java, and many others.  Indexing elements in tables is very similar to other languages, though, with the use of the [] brackets following the variable name.  The first two lines index the first two elements of the array part of the table and set them to a number and string variables.  The elements of tables in Lua can be dissimilar.  In the last line of the example, the key "zero" is set to the number 0 in the associate array part of the table.  This data can be accessed two ways: the normal way using [] brackets, or with myTable.zero since the key is a string.  Either way works, though if you are accessing the associate array part of the table programmatically (and the key varies depending on a variable), you should stick to using the [] brackets so the variable's contents are interpolated.

It may be surprising at first, but frames in the WoW API are actually implemented as tables in Lua.  These tables store frame-specific data as well as function references that act as member functions for the frame object.  The same can be done for our game objects as well.  The following is the global function we'll be using to create tower objects in our game enviromnment:

function PrimalDefense_CreateTower(towerType, level, tileX, tileY)
    local function Update(self, elapsed)
        self.elapsed = self.elapsed + elapsed
        self:primaryAttack()
    end

    local newTower = {}
    
    newTower.type = towerType
    newTower.level = level
    newTower.posX = ( tileY - 1 ) * 32 + 19
    newTower.posY = -( ( tileX - 1 ) * 32 + 19 )
    newTower.elapsed = 0
    newTower.buffs = {}
    newTower.primaryAttack =
             PrimalDefense_TowerActions["SHOOT_FIRST_TARGET"]
    
    newTower.Update = Update
    
    return newTower
end

Those familiar with programming will recognize this as a form of a factory function.  Inside the function, we create a new table and assign some tower-specific values to keys in the table, then return a reference to the newly-crafted object.  The first thing we do inside the factory function, however, is define a member function that will be used to update the tower's status.  The only data that will really change for a tower is the ability timer, so we update that and then tell the object to try to fire its primary attack.

You'll notice that instead of calling self.primaryAttack() we call self:primaryAttack() instead.  The colon (:) notation for functions is just a bit of syntactic sugar, and although both ways of calling the function are possible, the argument list changes based on which you choose.  For instance:

function myTable.test(self, val)
    message(val)
end

function myTable:test(val)
    message(val)
end

These are both actually the same function, just defined in different ways.  The colon implicitly passes the table to the function as the first argument, eliminating the need to specify it in the argument list.

With our factory function in place, we can now create and store tower objects in our main game code, and in our function for the OnUpdate handler we can loop through and execute the member update function for each of the towers.  As long as returned tables from the factory function are stored in a persistent data structure (such as another table/array), they will stick around and be available for our use until we don't need them anymore, when we can remove them from the table and let the garbage collection system take care of the rest.

Coming Up
While those two topics served as a bit of a foundation for our game programming techniques, next time I talk about programming I'll go into some more detail regarding the implementation of Primal Defense itself.  Hopefully this was informational, and I apologize for not having any new screenshots to share =P
     
6 comments
Atth
Atth Jul 4, 2009 at 10:20 pm
None
None
+1 votes
None
first and always a good read =3
r0kzilla
r0kzilla Jul 4, 2009 at 11:20 pm
None
None
+1 votes
None
Toresh
Toresh Jul 5, 2009 at 12:14 am
None
None
+2 votes
None
Another great post. I started reading a few weeks ago, and loved the last 3 posts. 
Coming from a Java background, these have been helpful.

Thanks
Rhave
Rhave Jul 5, 2009 at 2:48 am
None
None
+1 votes
None
question when the new tower is made, how do you uniquely identify it so that when you pull the status of the tower, you know exactly which tower to pull from array? or was the code above just an example ?
kjado
kjado Jul 5, 2009 at 3:17 am
None
None
+1 votes
None
The function above was straight from the game, but the towers aren't actually stored in a table/array in the main section.  In reality, there is a table that holds all the tiles of the game map, and each tile (which is implemented as a frame) has a member reference for a tower, so with the current implementation it isn't really a necessity to be able to distinguish between different tower objects.  Had they been all stored together, though, some additional information would likely be needed to be kept on each =)  Good catch!
blog vitals
Theorycrafting, addon discussion, and *gasp* lore.
10 Subscribers
comments6    Likes: 12    August 24, 2009, 1:52 pm
comments4    Likes: 12    August 4, 2009, 5:46 am
comments6    Likes: 25    July 4, 2009, 9:10 pm
comments9    Likes: 22    June 29, 2009, 2:21 pm
comments6    Likes: 20    June 23, 2009, 1:37 am
comments5    Likes: 18    June 14, 2009, 3:31 am
comments3    Likes: 14    June 2, 2009, 2:42 pm
comments4    Likes: 11    May 27, 2009, 6:32 pm
Started May 6, 2009
12 Total Entries
THE SPOTLIGHT
Arrested over tip, Hassan terrorist, Chuck, Avatar…
1 of 9
THE IMAGE FEED
226 images uploaded in the last 60 days. Got an image you need hosted?
Copyright ©2007-2009 GameRiot All Rights Reserved.