Friday, July 20, 2012

Interlude 10 - Formatting Text in Columns


We will have one last Interlude before we return to Part 2 of the MineSweeper tutorial. One of the areas of functionality that we wanted to add to the game was keeping track of high scores. The code to save and retrieve this was relatively straight forward (and we will cover it in the tutorial) but printing the results in neat columns turned out to be harder than expected.

After struggling with this for a few days we resorted to the Codea forums and dave1707 pointed out our problem. We will get to this shortly, but first some background.

Using the string.format() function, %w.ts will format a fixed column of width w, truncated at t characters for string s. This will be right justified. If you use the left justify flag, %-w.ts the string will be left justified. So in the code below %-10.10s will print "Easy" left justified in a column 10 characters wide and it shouldn't be truncated. The escape character \t will produce a tab between columns.

The truncation field (.t) is optional. If you don't include this (e.g. %10s), then the column width field works as a minimum. In this instance if you had a string which was longer than w then the additional characters would be printed and the columns won't line up.

More generally, the string.format() function uses the same format identifiers as the c printf function. The identifier field needs to be in the following order.

%FlagsMinimum field widthPeriodPrecision. Maximum field widthArgument type
RequiredOptionalOptionalOptionalOptionalRequired

The Flags available are:

   -      Left justify.
   0      Field is padded with 0's instead of blanks.
   +      Sign of number always O/P.
   blank  Positive values begin with a blank.
   #      Various uses:
   %#o (Octal) 0 prefix inserted.
   %#x (Hex)   0x prefix added to non-zero values.
   %#X (Hex)   0X prefix added to non-zero values.
   %#e         Always show the decimal point.
   %#E         Always show the decimal point.
   %#f         Always show the decimal point.
   %#g         Always show the decimal point trailing 
               zeros not removed.
   %#G         Always show the decimal point trailing
               zeros not removed.

Note that the flags must follow the % and where it makes sense you can use more than one flag. Finally the available format identifiers are:

%d %i         Decimal signed integer. 
%o              Octal integer. 
%x %X       Hex integer. 
%u              Unsigned integer. 
%c              Character. 
%s              String. 
%f               double 
%e %E      double. 
%g %G      produces either f, e or d type output depending on the argument.
%q              treats double quotes, newline, embedded zeros and back slash as escaped

BUT there is a trick. As dave1707 so helpfully pointed out, this column formatting trick only works for fixed width fonts (i.e fonts where each character is the same width). Most fonts are proportional and won't be formatted as you would expect using the above technique.

In Codea, there are currently two fixed width fonts available: Inconsolata and the various flavours of Courier.

The following test stub indicates how you can use this to provide the output shown in the image at the top of the Interlude.

function setup()
   displayMode(FULLSCREEN)
end

function draw()

   background(0)

   font("Courier-Bold")
   fill(0,0,255)
   fontSize(72)
   textAlign(CENTER)

   text("High Scores", WIDTH/2, HEIGHT/2 + 220)

   fill(255)
   fontSize(24)

   local str

   str = string.format("%-10.10s\t%-10.10s\t%10d", "Easy", "Player 1", 1000)
   text(str, WIDTH/2, HEIGHT/2 + 40)
   str = string.format("%-10.10s\t%-10.10s\t%10d", "Medium", "Player 2", 2000)
   text(str, WIDTH/2, HEIGHT/2)
   str = string.format("%-10.10s\t%-10.10s\t%10d", "Hard", "Player 3", 3000)
   text(str, WIDTH/2, HEIGHT/2 - 40)

end 

Thursday, July 19, 2012

Interlude 9 - Control Object Movement with Buttons (Updated 6/4/16)



Interlude 9.1 Introduction


One of the most useful design patterns in game design is being able to move an object on the screen using buttons (up, down, left and right).


Interlude 9.2 Solution 1 - One Tap per Move


Our first solution will move an object on the screen by a defined amount (shipSpeed) each time a button is tapped. We have defined the shipSpeed variable as a parameter so that you can tweak the distance each tap moves the ship. Once again we have used @Vega's Mesh Button class for the four directional buttons. Note that this code only works properly with a landscape orientation.

Let's have a look at the main class first.

--# Main

-- Use this function to perform your initial setup

function setup()

   -- This block of code is optional. We just include it in 
   -- every project so that we have a method of version control.

   version = 1.0

   saveProjectInfo("Description", "Move Object Demonstration")
   saveProjectInfo("Author", "Reefwing Software")
   saveProjectInfo("Date", "11th July 2012")
   saveProjectInfo("Version", version)

   print("MoveShip v"..version.."\n")

   -- Initialise the co-ordinates of your "Ship"
   -- These will be updated by the action methods 
   -- associated with each directional button.

   shipPosition = vec2(WIDTH/2, HEIGHT/2)

   -- This slider parameter will control the ship "speed"
   -- The larger the number the further the ship will 
   -- move with each button tap.
   --
   -- The format of this function is: 
   -- parameter("name", min value, max value, init value)

   parameter("shipSpeed", 1, 10, 4)

   -- Define the four Buttons used to move the ship
   -- They wont be visible until you draw() them.
   -- Note that 50 pixels is the minimum height for the default
   -- button font size.

   local mButtonSize = vec2(100, 50)
   local mLocX = WIDTH - 250
   local mLocY = 100

   leftButton = Button("Left", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)
   leftButton.action = function() leftButtonTapped() end

   mLocX = mLocX + 150
   rightButton = Button("Right", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)
   rightButton.action = function() rightButtonTapped() end

   mLocX = mLocX - 75
   mLocY = mLocY + 60
   upButton = Button("Up", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)
   upButton.action = function() upButtonTapped() end

   mLocY = mLocY - 120
   downButton = Button("Down", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)
   downButton.action = function() downButtonTapped() end

   -- Assign the colours that you want to use in your game.

   blackColour = color(0,0,0)

end

-- And now for the draw() function which is quite simple:
--
-- This function gets called once every frame
-- Codea will attempt to call draw() 60 times per second, it
-- can be much less than this if you have a lot going on in your code.

function draw()

   -- This sets a black background color 

   background(blackColour)

   -- Do your drawing here
   -- Draw your ship at the current co-ordinates stored in shipPosition

   sprite("Tyrian Remastered:Boss D", shipPosition.x, shipPosition.y)

   -- Draw the four directional buttons

   leftButton:draw()
   rightButton:draw()
   upButton:draw()
   downButton:draw()

end

-- Most of the action happens in the button call back functions...
--
-- Button action methods

function leftButtonTapped()

   -- Update ship position as long as the ship isnt off the screen.
   -- math.max() returns the maximum value of the arguments, so
   -- if shipPosition < 0 it will set it to 0.

   shipPosition.x = math.max(shipPosition.x - shipSpeed, 0)

end

function rightButtonTapped()

   -- Update ship position as long as the ship isnt off the screen.
   -- math.min() returns the minimum value of the arguments, so
   -- if shipPosition > WIDTH it will set it to WIDTH.

   shipPosition.x = math.min(shipPosition.x + shipSpeed, WIDTH)

end

function upButtonTapped()
   shipPosition.y = math.min(shipPosition.y + shipSpeed, HEIGHT)
end

function downButtonTapped()
   shipPosition.y = math.max(shipPosition.y - shipSpeed, 0)
end

-- Handle screen touches

-- Note that you need to pass any touches through
-- to your button touch handlers.

function touched(touch)
   leftButton:touched(touch)
   rightButton:touched(touch)
   upButton:touched(touch)
   downButton:touched(touch)
end


Interlude 9.3 Solution 2 - Tap and Hold Continuous Move


In some cases you want your object to move for as long as you hold down the directional button. This turns out to be an easy change due to the functionality built into the Button class. We can detect whether a user is holding down a button by querying its state and seeing if it is "pressing". In this instance you don't need the button action methods (leftButtonTapped, rightButtonTapped, etc) so you can delete them if you aren't using them for something else.

The new draw() function is shown below. While a directional button is being held down its position will be updated by shipSpeed once per frame (roughly 60 times per second).

You can download the entire moveShipCode here.

function draw()

   -- This sets a black background color 

   background(blackColour)

   -- Do your drawing here
   -- Draw your ship at the current co-ordinates stored in shipPosition

   if leftButton.state == "pressing" then
       shipPosition.x = math.max(shipPosition.x - shipSpeed, 0)
   elseif rightButton.state == "pressing" then
       shipPosition.x = math.min(shipPosition.x + shipSpeed, WIDTH)
   elseif upButton.state == "pressing" then
       shipPosition.y = math.min(shipPosition.y + shipSpeed, HEIGHT)
   elseif downButton.state == "pressing" then
       shipPosition.y = math.max(shipPosition.y - shipSpeed, 0)
   end

   sprite("Tyrian Remastered:Boss D", shipPosition.x, shipPosition.y)

   -- Draw the four directional buttons

   leftButton:draw()
   rightButton:draw()
   upButton:draw()
   downButton:draw()

end

Interlude 9.4 Solution 3 - Adding Flames and Direction




This final version adds sprites to represent the ship engine flames (as shown above) and will point the ship in the right direction using rotation which is based on the directional buttons. You can download the complete program including the Button class.

--# Main
-- Use this function to perform your initial setup

function setup()

  -- This block of code is optional. We just include it in 
  -- every project so that we have a method of version control.
  --
  -- Version 3.0 adds rocket flames and points the ship in the
  -- direction of movement.

  version = 3.0

  saveProjectInfo("Description", "Move Object Demonstration")
  saveProjectInfo("Author", "Reefwing Software")
  saveProjectInfo("Date", "11th July 2012")
  saveProjectInfo("Version", version)

  print("MoveShip v"..version.."\n")

  -- Initialise the co-ordinates of your "Ship"
  -- These will be updated in the draw() function to allow for 
  -- continuous pressing of the directional buttons.

  shipPosition = vec2(WIDTH/2, HEIGHT/2)

  -- The ship sprite used faces down. Initially we want it facing up so 
  -- we need to rotate the sprite 180 degrees when we draw() it. For those new to rotation,
  -- note that there are 360 degrees in a circle, 180 degrees is half a circle.
  -- We will then use this variable to rotate the ship so that it is
  -- facing in the right direction when the up, down, left and right
  -- buttons are tapped.

  rotationDegrees = 180

  -- This slider parameter will control the ship "speed"
  -- The larger the number the further the ship will 
  -- move with each button tap.
  --
  -- The format of this function is: 
  -- parameter("name", min value, max value, init value)

  parameter("shipSpeed", 1, 10, 4)

  -- Define the four Buttons used to move the ship
  -- They wont be visible until you draw() them.
  -- Note that 50 pixels is the minimum height for the default
  -- button font size.

  local mButtonSize = vec2(100, 50)
  local mLocX = WIDTH - 250
  local mLocY = 100

  leftButton = Button("Left", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)

  mLocX = mLocX + 150
  rightButton = Button("Right", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)

  mLocX = mLocX - 75
  mLocY = mLocY + 60
  upButton = Button("Up", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)

  mLocY = mLocY - 120
  downButton = Button("Down", vec2(mLocX, mLocY), mButtonSize.x, mButtonSize.y)

  -- Assign the colours that you want to use in your game.

  blackColour = color(0,0,0)

end

-- This function gets called once every frame
-- Codea will attempt to call draw() 60 times per second, it
-- can be much less than this if you have a lot going on in your code.

function draw()

  -- This sets a black background color 

  background(blackColour)

  -- Do your drawing here
  -- Draw your ship at the current co-ordinates stored in shipPosition
  --
  -- pushMatrix() saves any transformations (rotate, translate or scale) that have been made.
  -- popMatrix() returns to these saved transformations.
  -- If you are going to perform transformations it is a good idea to encapsulate your code
  -- with these so that you don't have unexpected effects elsewhere.

  pushMatrix()

  local buttonDown = false

  if leftButton.state == "pressing" then
      shipPosition.x = math.max(shipPosition.x - shipSpeed, 0)
      buttonDown = true
      rotationDegrees = 270
  elseif rightButton.state == "pressing" then
      shipPosition.x = math.min(shipPosition.x + shipSpeed, WIDTH)
      buttonDown = true
      rotationDegrees = 90
  elseif upButton.state == "pressing" then
      shipPosition.y = math.min(shipPosition.y + shipSpeed, HEIGHT)
      buttonDown = true
      rotationDegrees = 180
  elseif downButton.state == "pressing" then
      shipPosition.y = math.max(shipPosition.y - shipSpeed, 0)
      buttonDown = true
      rotationDegrees = 0
  end

  translate(shipPosition.x, shipPosition.y)
  rotate(rotationDegrees)
  sprite("Tyrian Remastered:Boss D", 0, 0)
  if buttonDown then
      -- draw the engine flames
      sprite("Tyrian Remastered:Flame 1", 17, 100)
      sprite("Tyrian Remastered:Flame 1", -19, 100)
  end

  popMatrix()

  -- Draw the four directional buttons

  leftButton:draw()
  rightButton:draw()
  upButton:draw()
  downButton:draw()

end

-- Handle screen touches
-- Note that you need to pass any touches through
-- to your button touch handlers.

function touched(touch)
  leftButton:touched(touch)
  rightButton:touched(touch)
  upButton:touched(touch)
  downButton:touched(touch)
end

Friday, July 13, 2012

Interlude 8 - A Simpler Starfield (Updated 23/01/16)

Webcomic Courtesy of Ethanol & Entropy

We have been using the Twinkle class written by Ipad41001 to produce our star-field effect in MineSweeper, and a very fine class it is. However it is a touch computationally expensive if there is a bit else going on at the same time.

On the "hard" difficulty using our first generation iPad, the frame rate per second is around 14-15 using the Twinkle class. This doesn't effect gameplay but the twinkles are a bit slow.

If your game is more frame rate critical or you just want a different look then you could use the following function instead of this class. Using this star field effect gives us an extra 4-5 frames per second.

In your Main class, you will need:

-- Main

-- A variable to hold the number of stars to display on the screen,
-- the smaller the number of stars the quicker this function will run.
-- Note that this is a local variable and only available in the Main Class

local NUMSTARS = 50

-- In the setup function you need to initialise the table 
-- which will hold your stars

function setup()
    
    -- define black colour to make our code more readable

    blackColour = color(0, 0, 0)

    -- Initialise the stars table which contains the x and y screen co-ordinates
    -- for each star. These are set to a random position between 1 and the screen
    -- height and width.

    stars = {}
    for i = 1, NUMSTARS do
        stars[i] = {x = math.random(WIDTH), y = math.random(HEIGHT)}
    end

end

Add the following function to draw the star field.

function drawStarField()

    -- Star Field function courtesy of Javier Moral
    -- from his Fireworks example

    for i = 1, NUMSTARS do

        -- Set the fill colour to white and a random transparency, 
        -- this is half of the twinkle effect.

        fill(255, 255, 255, math.random(255))

        -- Each star is represented by a small rectangle. 
        -- The random x and y co-ordinate of
        -- the star was initialised in the setup() function, 
        -- so the stars don't move. The width 
        -- and height of each rectangle is set to a random integer 
        -- between 1 and 3 each frame.
        -- Codea will try and call draw() 60 times per second.

        rect(stars[i].x, stars[i].y, math.random(3), math.random(3))

    end

end

and then call it in the draw() function:

function draw()

    -- Set the background colour to black

    background(blackColour)

    -- Call the star field function

    drawStarField()

end

Thursday, July 12, 2012

Interlude 7 - Recursion & Closures in Lua (Updated 23/01/16)

Webcomic Courtesy of Ethanol & Entropy

Interlude 7.1 Preamble


Before part 2 of the MineSweeper tutorial, we need to go over two concepts which you may not have come across before, namely recursion and closures. Writing recursive code is a fairly common technique but Lua is the first language that we have come across that uses closures.


Interlude 7.2 Recursion


Recursion in programming is using a function to call itself to solve a problem. The example given in every lecture on computer science is calculating the factorial of a number. We can't think of a better example so let's go with that.

What is a factorial? Well we are glad you asked. The factorial of an integer n greater than 0 (designated by n!) is the product of all positive integers less than or equal to n. So factorial five is:

5! = 5 x 4 x 3 x 2 x 1 = 120

Note that factorial zero is defined as 1. The iterative solution to a factorial function, could look something like this:


-- Given a number 'n' calculate its factorial the iterative way

function factorial(n)

    if n == 0
        return 1

    local temp = 1

    for i = 1, n do
        temp = temp * i
    end

    return temp

end


And the recursive version:


-- Given a number 'n' calculate its factorial the recursive way

function factorial(n)

  if n == 0 then
      return 1
  else
      return n * factorial(n - 1)
  end

end


The recursive version will be marginally slower, it is a bit shorter to code, and it is a bit simpler and closer to the mathematical definition of recursion. For very large values of n, the recursive function will crash due to a stack overflow. Every time a recursive call is made, the function clones itself and pushes the previous function onto the stack. You can only do this so many times before running out of memory.

There are two rules for using recursion:
  1. If you use recursion then you must always have a base case which stops your code from calling itself forever. This won't happen of course, instead your program will crash with a stack overflow when it runs out of memory. The base case for the factorial function is n == 0.
  2. Your function must also make progress towards your base case or you will be caught in infinite recursion and crash. In the factorial example, each recursive call decrements n, so eventually it will get to the base case of zero.
The advantage of a recursive solution is its simplicity and elegance, the disadvantage can be the speed and the amount of memory used if the depth of recursion is large.

The MineSweeper game uses recursion to reveal the neighbouring cells if you tap a cell with no neighbouring mines. Have a look at the revealCell() function in the Main class.


Interlude 7.3 Tail Recursion



@gunnar_z had the following to add on the topic of recursion: 

"Lua supports something called tail recursion, or tail calls. The idea is that if the calling function does not actually do anything else but return to its caller after the called function has returned, the call is basically replaced by a jump and the current stack frame is reused. That is, the call needs to have the form "return fun(args)". With a bit of thinking, this can be made to work with a lot of recursive problems. For your example (factorial), it might look like this:

function fact(n, s)

    s = s or 1
    if n == 0 then
        return s
    else
        return fact(n-1, s*n)
    end

end

Recursion is a bit slower than iteration for trivial problems, but that is hardly noticable. For non-trivial problems (for example a recursive vs. iterative implementation of a quicksort or a tree traversal algorithm), this difference in speed shrinks rapidly, as you (may) need a stack for them anyway, and it may even be faster to implicitly use the stack provided by the language runtime through recursion than to simulate your own."


Interlude 7.4 Closures


When a function is enclosed in another function, then it has access to all the local variables of that function. This is called lexical scoping and the external local variable is called an "upvalue". 

To understand how this is useful, consider if we wanted to create a calculator application. This has a number of digit buttons that we display on the screen.


function digitButton (digit) 
    return Button{ label = digit, action = function () add_to_display(digit) end } 
end


In this example, we assume that Button is a class that creates new buttons; label is the button label; and action is the callback function to be called when the button is pressed. (It is actually a closure, because it accesses the upvalue digit.)

In our MineSweeper game, the inNeighbourCells() function uses closures to access the cell index upvalues and count the number of mines in neighbouring cells.

Another use for closures is to produce an iterator.


function makeIterator()

    local n = 0

    function iterator()
        n = n + 1
        return n
    end

    return iterator

end

-- Make two different iterator's

iterator_a = makeIterator()
iterator_b = makeIterator() 

print(iterator_a())         -- Will print 1
print(iterator_a())         -- Will print 2
print(iterator_b())         -- Will print 1
print(iterator_a())         -- Will print 3
print(iterator_b())         -- Will print 2


Once again we have a function within a function. makeIterator() is a constructor of iterator()'s and every time iterator() gets called it can see the upValue n and increments it.

@gunnar_z contributed the following additional information on closures:

"Closures are created whenever a function is created in a lexical block, not only within functions. When a function is created in a do .. end block, or even within a loop, it creates a closure. Also, all functions created within a file (or a tab in the codea world) are closures existing in the lexical context of that file (or tab). Btw. some time ago the scoping of the 

for i=1,n do ... end

construct was changed to create a new scope for every iteration. Thus, the following:

t={}

for i=1,10 do
    t[i] = function() print(i) end

end

will create a table with 10 functions, each one printing the value of i during its iteration."

Tuesday, July 10, 2012

Tutorial 6 - MineSweeper Part 1 (Updated 23/01/16)


6.1 Game Design


To further illustrate the many uses of Finite State Machines (FSM) we will deconstruct a simple game called MineSweeper. This game will illustrate a bunch of new concepts including recursive coding and closures as well as using a lot of the code that we developed in early tutorials.

Our MineSweeper code uses no less than three state machines to keep track of what is happening. The main state machine is illustrated above. This is a pretty standard pattern for most games. The goal was to produce the entire game using just an iPad. 

The aim of MineSweeper is to clear the minefield represented by a square grid without tapping a mine. When the splash screen fades away you will be presented with a menu of three buttons: Easy, Medium and Hard which you can use to select the game difficulty and launch the game. 



Game difficulty is tracked using a state machine and is used when the New button is tapped on the game screen to ensure we launch another game at the same difficulty level as the current game. The variables effected by difficulty are shown in the following table.


Game Difficulty
Easy Medium Hard
Number of Mines 10 15 40
Grid Width 8 12 16
Grid Height 8 12 16


Once you select the game difficulty by tapping on the appropriate button, you will be presented by the main game screen. The blue grid represents the minefield. The number on the left above the minefield is the number of cells left to clear. The number on the right is the elapsed time in seconds (approximately). The game timer will start as soon as you tap a minefield cell. Winning, losing or tapping the New or Menu buttons will stop the game timer.

The button in the top right will initially have "Show" as its button text. This indicates that you are in Show mode when you tap the grid. Show mode will reveal the cell contents. This will either be blank, a number or a mine. If it is a mine then the game is over. If the cell is blank it means that there are no mines in the neighbouring cells (each cell can have up to eight neighbours depending on its grid position). If the cell contains a number, this represents the number of mines in adjacent cells. You can use these numbers to deduce where the mines are located. If you determine that a cell contains a mine you can flag it by using Flag mode. You enter Flag mode by tapping the Show Button. When in Flag mode this button text will change to "Flag". Tapping it again will return it to Show mode. Tapping any unrevealed cell while in Flag mode will place a flag icon on that cell. This icon can be toggled on and off by tapping the same cell in Flag mode.

If you tap a blank cell in Show mode, the game will also reveal any other adjacent blank cells. This can reveal quite large areas depending on the mine disposition.

You don't have to use flags to indicate suspected mine locations if you don't want to. The game is harder if you don't use flags.

The game ends if you tap a mine (lose) or if you reveal all of the cells without mines (win).


6.2 Download the Code


If you just want to run MineSweeper and play the game then the easiest approach is to download the entire code in one file and paste it into the Main tab of a new project. If you are more interested in reusing the classes and understanding how it works then you are better off downloading the individual classes and pasting them into separate tabs. The order of the tabs can be important, have a look at this article on inherited classes if you want to know why.

We suggest that you use the same tab order as our project. The classes you need can be downloaded using the following links. Use these names for your tabs/class.

1. Main
2. Cell
3. Button
4. RoundBorder
5. SplashScreen
6. Fader
7. Twinkle
8. IconImages

We have already discussed a number of these classes (RoundBorder, SplashScreen, Fader and Twinkle) in previous tutorials so we won't be covering them here. We had previously been using the Button class provided with the Codea sample project "Sounds Plus", but we found this class took too much tweaking to make the various buttons look right. Consequently, we are now using the mesh button class developed by Vega. We tweaked this a little bit, adding callback functionality and push/popStyle to preserve the various graphic variables.

The following tutorial will delve into the MineSweeper Main and Cell classes, which is where most of the action is, but we did want to touch on developing the images.

6.3 Pixel Images in Spritely



The sprite images used to represent the table cells were done in Spritely, the pixel image editor provided with Codea. This was fun but you probably wouldn't want to do a lot of images with it. Drawing every sprite, pixel by pixel using your finger is an exercise in patience. A side effect of this approach is that the MineSweeper code is over 5,000 lines long. Most of this is Spritely images. Each 32x32 pixel image takes over 1,000 lines of code to define it. Now Spritely automatically generates this for you but you need to draw the images first. To make life easy we have included all the code (including images) which you can download from dropbox.


For future games we probably won't use Spritely images. The largest sprite that you can produce is 32x32 pixels. This is just big enough for my little fingers to tap reliably but I imagine some folks could have difficulty. We would have preferred to make the sprites a touch bigger for MineSweeper. The advantage of this method is that all the game assets are in one file which makes it easy to distribute, however this is offset by the 32 pixel size constraint and the long files required to represent each image. On my first generation iPad, editing the IconImages class (which contains the 4 sprites) was very slow and crashed frequently. If you are going to use Spritely, a separate tab for each image is probably the way to go and don't forget to back up your code. The easiest way to backup is to tap and hold on your project icon in the project explorer screen of Codea and then tap copy. We then paste and email the resulting file, clean it up in TextWrangler and finally save it in DropBox.

But this does demonstrate that the iPad is moving from a content consumption device to a content generation device. How amazing is it to be able to code and produce graphics on this fantastic tablet?

Stay tuned for part 2 of the MineSweeper Tutorial...


Thursday, July 5, 2012

Interlude 6 - Lua Tables (Updated 23/01/16)

Interlude 6.0 Acknowledgements


Many thanks to the good folks over at the Codea Forum for their comments and advice regarding Lua tables. I have updated this Interlude based on their input. In particular, thank you to Andrew_Stacey,gunnar_z and emsi.

Interlude 6.1 The Table Data Structure


The table in Lua is a fascinating object, not least because it is the only data structure in Lua. It is very flexible and very powerful and if you are used to array, dictionary and matrix data structures in other languages, it can be tricky to get your head around initially. We need tables for the next tutorial so it seems a good time to take a quick detour to understand how they can be implemented.

A table is a collection of key-value pairs. Keys and values can be any type other than nil. A key is often called an index to a table. Like global variables, table fields evaluate to nil if they are not initialized. Also like global variables, you can assign nil to a table field to delete it. Because tables can contain data and functions they can also be used to implement an object.

Tables have no fixed size in Lua and you can dynamically add as many elements to a table as you like (memory permitting).

Something that wasn't clear to us initially was that tables can be thought of consisting of two parts: the array part and the hash part. If you use integer keys in the range 1 to n, then these entries will be stored in the array part. All other elements get stuck in the hash part. While you don't need to understand this to use tables, it does explain some of the practices outlined below. For those who would like a bit more detail, emsi pointed out an article on optimising Lua code which has an interesting section on tables.

Interlude 6.2 Creating Tables - the array part


You create a table in Lua using the construction expression. The simplest version of this is:


mTable = {}        -- At this stage both the array and hash parts of the table are empty.

If you just want a one dimensional array data structure use integers as the key and start at 1.

for i = 1, 100 do
    mTable[i] = i
end

This data will be placed in the array part of mTable, which as we will demonstrate below brings with it some useful benefits.

As Andrew_Stacey rightly pointed out, when you create a table with no keys, as in

mTable = {"a","b"}

then the keys start at 1 and increment so this is the same as

mTable = {1 = "a", 2 = "b"}

It is traditional in Lua to commence table indexes at 1, rather than 0 as found in the c based languages. See Interlude 6.4 for why you should follow this convention.



Interlude 6.3 Creating Tables - the hash part


The hash part of the table is used if your key is anything but a non zero integer. For example:


mTable = {["One"] = "Number 1"}
mTable["Two"] = "Number 2"
mTable.Three = "Number 3"

You can mix index types in the one table, but you will then start using the hash part of the table. For example:

mTable["x"] = 99 is perfectly valid addition to the array example in Interlude 6.2. Note that mTable[1] and mTable["1"] are not the same but equally valid members of mTable. When you are starting out, this can cause subtle bugs if you aren't careful.

Lua also allows dot notation which is an alternate syntactic structure that some people prefer (and some hate!). 

mTable.x = 99 is equivalent to mTable["x"] = 99.

gunnar_z provides theses additional examples:

"Table keys that are valid identifiers may always be accessed using dot notation, regardless of how they were initialized. So, if you do any of these:


a = {} 
a.x = 1

a = {} 
a['x'] = 1

idx = 'x' 
a = {} 
a[idx] = 1 

a = { ['x'] = 1 } 

idx = 'x' 
a = { [idx] = 1 } a = { x = 1 }

a.x always equals a['x'], both are 1 in this case."



Interlude 6.4 Iterating over Your Table - ipairs and pairs


Lua includes a handy function called ipairs to iterate over the array part of your table. The ipairs() iterator iterates, in numeric order, all elements with positive integer keys, from 1 until the first nonexistant or nil-valued key is encountered. Consequently, ipairs will not return an element with a key of 0. This is a good reason to start your arrays at an index of 1. You use ipairs in the following fashion:


for key, value in ipairs(mTable) do
    print("Array index: " .. key .. "and value: " ..value)
end

This statement will loop in order through each key-value pair in mTable, assigning the key and value to the loop variables. This structure is often called an ipairs loop. If you aren't going to use one of the loop variables it is traditional to name it with an underscore (_). You will see this in a number of the example projects included with Codea.

If you mix in non-integer keys (e.g. strings) in your table, then ipairs will simply ignore these. 
What about if you want to iterate over your whole table, irrespective of whether elements are in the array or hash part? In this case you need to use pairs(). This iterator is guaranteed to iterate over every key of every kind as long as it has a non-nil value. However, it doesn't iterate in any particular order.

Andrew_Stacey and gunnar_z suggest that "when using tables as arrays, with sequential numeric indices, you should be using ipairs instead of pairs. This will ensure that you only get the key-value pairs with numeric keys, and also they will be ordered. pairs will return all key-value pairs, and an order on the keys, even the numeric ones, is not guaranteed."


Interlude 6.5 Array Length


Another approach to iterating through the array portion of your table is to use the # (length) operator.


mArray = {}

print (#mArray)

Will return 0.


mArray = {"a"}

print (#mArray)

Will return 1.


mArray = {"a", "b"}

print (#mArray)

Will return 2 - and you are probably starting to get the idea. Note that arrays with gaps don't work with the length operator as it uses nil to detect the end of the array. For tables without gaps, you can iterate through them as follows:


for i = 1, #mArray do
    print(mArray[i])
end

gunnar_z's description of the length operator was so good that we thought we would reproduce it here:

"Basically, what # returns is not the length of the table or the index of the last element, but the numeric index of an element such that, for a given table T, T[#T] ~= nil and T[#T+1] == nil. With the sole exception of a table with no numeric keys, in which case the above condition does not hold for the returned value of 0. But, for a table
T = { [1] = 1, [3] = 2, [5] = 3 }
the value of #T may be any of 1, 3 or 5."

Interlude 6.6 Enter the Matrix - Two (and more) Dimensional Arrays


It is often handy to use a two dimensional array or Matrix to represent a grid for your game. In fact we will be using this construct in the next tutorial. The easiest way to do this is to have an array of an array (or a table of a table to be strictly correct). That is, each element of your one dimensional array is another array.


-- create a 2D matrix with N rows and M columns, 
-- each element initialised to 0.

mMatrix = {}
    for i = 1, N do 
        mMatrix[i] = {}                             -- create a new row 
        for j = 1, M do 
            mMatrix[i][j] = 0 
        end
    end
end

To create additional dimensions you just nest additional arrays.




Interlude 6.7 Dictionary like Structures  - back to hash


You can use the table constructor {} to assign different types of keys to values. For example, say we wanted a data structure which associates Capital Cities with States, we could do something like:


CapitalOfState = {["NSW"] = "Sydney",
["VIC"] = "Melbourne",
["QLD"] = "Brisbane",
["SA"] = "Adelaide",
["WA"] = "Perth",
["TAS"] = "Hobart"}

Note that ACT and NT are not States but Territories! We mentioned key-value pairs earlier. In this example we are associating the key "NSW" with the value "Sydney". To retrieve a value for a particular key you would use CapitalOfState["NSW"] which will return "Sydney".

If your keys are valid identifiers (i.e. one word using letters and no symbols) you can construct your table without using the [] and "". It would then look like:


CapitalOfState = {NSW = "Sydney",
VIC = "Melbourne",
QLD = "Brisbane",
SA = "Adelaide",
WA = "Perth",
TAS = "Hobart"}

As noted earlier, table keys that are valid identifiers may be accessed using dot notation  instead of square brackets and quotes:

CapitalOfState.NSW will return "Sydney".

This concludes our detour down Lua tables, next we will look at how we use these data structures in anger.