Showing posts with label sample. Show all posts
Showing posts with label sample. Show all posts

Tuesday, July 31, 2012

Tutorial 11 - Physics 101

   Webcomic Courtesy of Ethanol & Entropy

11.1 Dropping Things



We are constantly amazed by the capability of Codea. An example of this is the integration of the Box2D physics engine. The talented folks at Two Lives Left have made incorporating physics into your App absurdly easy.

The included Physics Lab example project provides a good overview of the techniques available. However, if you are starting out, sometimes it isn't obvious how you can integrate similar functionality into your program. This tutorial will show you which bits you need to include in your project and how you can attach a sprite to a physics object.

11.2 The Setup



In our Minesweeper game we wanted to add a bit of bling to the Menu screen. To this end we thought about dropping some mines from the top of the screen. Initially we had them bouncing off the ground but this didn't seem like a sensible thing to do with a mine so we removed the ground. We have left the code for the ground in the example below in case you need it. In your Main class, we start off by reading the sprite image into the img variable. You want to do this in setup() to ensure you only read the sprite into memory once, doing it in draw() can cause your App to crash due to running out of memory.
  
The next step is to create an instance of the PhysicsDebugDraw() class which we copied from the Physics Lab example project (and modified a bit). We will cover this class in section 11.4 below.
  
We then assign the sprite image we read to the associated spriteImage parameter in PhysicsDebugDraw() and set staticVisible to false. The only static physics object we create is the ground so setting this to false means that the ground will be invisible (but there nonetheless).
  
Finally we create the physics objects, the ground (createGround), a box (createBox), a circle (createCircle) and a random sized polygon (createRandPoly). The interesting one is the circle which we will attach our sprite to. Note that the radius of the circle is the same size (32 pixels) as half the width of the sprite (64 pixels). To make this more general you could use img.width/2 in place of the 32 (assuming your sprite looks roughly circular).



11.3 Physics Functions



We have also extracted the following physic object creation functions from the Physics Lab example project:
  • createCircle(x,y,r)
  • createBox(x,y,w,h)
  • createGround() - note you could change the dimensions of this by altering the physics.body polygon.
  • createRandPoly(x,y) - creates a random polygon at screen co-ordinates (x,y) with between 3 and 10 sides
  • cleanup() - will delete all of the physic objects that you added to the PhysicsDebugDraw rendering class. In Minesweeper we call this after creating 50 objects to ensure that we don't run out of memory. Remember that if you call this you will need to re-create any physics objects that you want to model.



11.4 The Engine Room - PhysicsDebugDraw Class



This class renders the physics objects that you have added to it. We have made two minor modifications to the class. We added the staticVisible flag to allow you to choose whether your static objects were visible or not. Note that static bodies don't collide with other static bodies and are immovable, so they are usually used to represent the ground. 

The other thing we added was the spriteImage parameter. If this is not nil then we draw the sprite image instead of a circle. And that's all there is to it. In future tutorials we will examine some of the other capabilities enabled by the physics engine.


.  




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


Friday, June 29, 2012

Interlude 4 - A Rounded Border Class (Updated 17/01/16)


Interlude 4.1 Yes it is a bit of a Hack...


For our splash screen Tutorial we wanted to include a nice rounded border. To that end the following extends the roundRect() function that we have used in previous tutorials (to create a button). There are much more elegant ways to achieve this (e.g. using a mesh) but this has the advantage of simplicity. Once we have covered meshes we will rewrite this class. Another alternative would be to extend the roundRect() function to include a variable which determines if the roundRect is filled or not.


Interlude 4.2 The Rounded Border Class


This class relies on the roundRect() function, so you must include that to use RoundBorder(). The concept is very simple. We just draw two rounded rectangles, one inside the other. The inner rectangle is smaller by a factor of borderWidth. The larger rectangle is drawn using the borderColour and the inner using the fillColour.



RoundBorder = class()

function RoundBorder:init(x, y, w, h, borderWidth, borderColour, fillColour)

    -- you can accept and set parameters here
    -- Set dimensions of the outer "border" round rectangle

    self.x = x
    self.y = y
    self.w = w
    self.h = h
    self.r = 30

    self.borderWidth = borderWidth
    self.borderColour = borderColour
    self.fillColour = fillColour
    
    -- Set dimensions of the inner "background" round rectangle

    inX = self.x + self.borderWidth
    inY = self.y + self.borderWidth
    inW = self.w - 2 * self.borderWidth
    inH = self.h - 2 * self.borderWidth
end

function RoundBorder:draw()
    -- Codea does not automatically call this method
    -- Do the right thing and save the graphic context
    
    pushStyle()
    
    -- Start by drawing the outer Rounded Rectangle, this will become the border.
    
    fill(self.borderColour)
    roundRect(self.x, self.y, self.w, self.h, self.r)
    
    -- Then draw the inner rectangle using the fill colour
    
    fill(self.fillColour)
    roundRect(inX, inY, inW, inH, self.r)
    
    -- Return the graphic context to the way it was when entering this function
    
    popStyle()
end

Interlude 3 - A Fader Class (Updated 17/01/16)

Interlude 3.1 Transition Effects


This Interlude was originally part of Tutorial 4 but we split it out because it is useful from a stand alone perspective and Tutorial 4 was getting too long.

There will be times when your App needs to transition from one screen to another and effects are useful in letting the user know what is happening. The following is one approach to what transition to use and when.
  1. Fade: The content is the same but users change their view of the content (for example, switching between day and week view in a calendar or switching between viewing a list of images and viewing the thumbnails of the same images).
  2. Slide: Users move to an item at the same level in the navigation hierarchy.
  3. Zoom: Users move to an item at a different level in the navigation hierarchy (for example, from a parent item to a child item or a child item to a parent item). Users create a new item, send an item, or save an item.
iOS has a bunch of built in transition effects but unfortunately (to our knowledge) they are not currently available in Codea. We will be using a fade transition in the Splash Screen tutorial, so let's have a look at one way of achieving this.


Interlude 3.2 A Fade Transition Effect


Vega over on the Codea forums has once again done the hard work for us. He produced a class which can fade in or out a screen. We have simplified the code to just fade out a screen but you can see the original class at the link above. Create a new tab in your project and paste in the following code. We will show you how to use it in Tutorial 4.


Fader = class()

function Fader:init(fadeSpeed)

--[[ fadeSpeed determines how quickly the screen fades. 1 is the lowest speed available and will give the slowest fade effect. The bigger the number the faster the fade. The self.fading variable is used to detect whether the class is in the middle of fading something and self.alpha is used to determine the transparency of the rectangle covering the screen. An alpha of zero is transparent, and it can go up to 255 which is solid. ]]

    self.fading = false
    self.alpha = 0
    
    if fadeSpeed > 0 then
        self.fadeSpeed = fadeSpeed --raise this number to fade faster
    else
        self.fadeSpeed = 1
    end
end

function Fader:fade(func)

--[[ func is the function that this class will call once the fade transition is complete (assuming it exists and isn't NIL. The Fader: fade() function is called to start the fading transition. ]]

    self.fading = true
    if func ~= nil then 
        self.func = func 
    else
        print("Warning:: Fader call back method is NIL.")
    end
end

function Fader:draw()

-- If it is time to fade then...

    if self.fading then

-- [[ Do the right thing and save the current screen settings, we will return these at the end using popStyle(). No smooth and no stroke are used to ensure we get an acceptable frame rate. Without these two statements the animation will appear too slow, particularly on an iPad 1. ]]

        pushStyle()                      
        noSmooth()                      
        noStroke()

-- [[ fill is set to black and to the current alpha. Initially alpha will be zero. i.e. transparent and get gradually more solid. As Vega mentions in the comment below, if you want to fade to some other colour then change this fill statement. ]]

        fill(0, 0, 0, self.alpha)
        
        --change that color if you want to fade to a color other than black
        
-- [[ The basic approach is to create a rectangle in the fill colour which covers the entire screen. For our fade out example, the rectangle is initially transparent and gets more solid each draw cycle by the fadeSpeed. Remember the draw() function gets called 60 times a second if possible. ]]

        rect(0,0,WIDTH,HEIGHT)
        popStyle()
        self.alpha = self.alpha + self.fadeSpeed
        
-- [[ The maximum alpha value is 255. This indicates a solid colour and when we reach it the fade is complete. So at this stage self.fading becomes false and the transition end call back function is called (if defined). ]]

        if self.alpha >= 255 then 
            self.alpha = 255 
            self.fading = false --fade complete
            if self.func ~= nil then self.func() end -- its all black, so switch the frame
        end
    end
end