Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, August 17, 2012

Interlude 11 - Classes in Lua and Codea

   

Interlude 11.1 What is a Class?


In Object Oriented Programming (OOP) a class is a coding construct used to define and create an object. Our original training was in the days of Procedural Programming, so we have some sympathy for those grappling with classes and other OOP paradigms for the first time. One way to think of a class is that it is the blueprint for an object.
  
When you create a new object using a class it is called an instance of that class. A class normally consists of data and functions which are associated with the object, this concept is called encapsulation. The class functions (sometimes called methods) act on the data variables to modify the behaviour of the object or provide information about its state. The purist approach is that only an objects functions can modify its variables. 

There are many benefits to using classes (code reuse, maintainability, modularity, inheritance etc.) but for us, the best thing about them is the mapping of a physical object or concept to a virtual object in your code. This makes it easier to conceptualise, write and understand complicated applications.
   
To be balanced we should point out that there is a camp of OOP haters (this rant by Linus Torvalds against C++ is quite amusing), it can make your code larger than necessary and arguably harder to maintain. Like most things in life moderation is the key. Abstraction for its own sake is pointless.
     

Interlude 11.2 Classes in Lua

   
As the comic at the start of the Interlude suggests, there is no class type in Lua. If that is the case then why the hell are we doing a tutorial on classes? Well it is possible to emulate a class in Lua using tables and because they are so useful the good folk at Two Lives Left have done it for you and it is included in Codea implementation of Lua. If you are really interested in how this is done then you can read the description on the Codea Wiki.
  

Interlude 11.2 Classes in Codea

    
The usual tutorial examples for classes are cars, employee data or animals. Whilst not wishing to anger the coding gods, we thought we would do something a bit more relevant to our next tutorial in the series (our interpretation of the classic SpaceWar! game). For this game we want to have a reusable ship class. The first step is to think about what sort of attributes a ship has which are relevant for us to model. Let's start with its position, speed and screen representation.
   
As mentioned above, Codea comes with a built-in global function called logically enough - class(). You can declare a class just about anywhere (with the usual caveat that if it refers to another class or function then this must have been defined before it in the tab order), but it is usually best to use the "+" tab at the top right of the screen when you are in a project to create your class. Tapping the "+" will bring up a popover with the "Create New Class" button at the top. Tapping this button allows you to enter the name of your new class and when "Done" is then tapped, Codea will create a new tab with your class template code. By convention class names start with a capital and class instances start with a lower case letter. This helps with the readability of your code, as you can immediately tell if you are referring to the class or its instance.
    

Interlude 11.3 The Ship Class

    
OK let's give it a go. Create a new project called SpaceWar! then tap the "+" tab and create a new class called Ship. You should end up with something that looks like Figure 1.
  
Figure 1. Default Class Template in Codea.
   
Codea automatically adds three functions to your class which you will usually need. The init(x) function is often called a constructor in OOP terminology. Whenever you create an instance of a new class this function will be called to set it up. Notice the x? When you create a new class you can pass in parameters to be used in the initialisation. The line self.x = x is assigning the parameter that you pass in (x) to the class variable (self.x). You don't have to do this, in which case your function would look like Ship:init() and you would also delete the line self.x = x in the body of the function. 

The draw() function you would be familiar with from earlier tutorials. Within a class we use it to handle the drawing of your object (if required). As the embedded comment says, Codea won't automatically call this function, you need to explicitly call it from the draw() function in Main. We will show you how to do this shortly.
    
Similarly, the touched() function looks after how your object handles touches. As for draw(), Codea won't call the class touch function automatically, so you need to do it in the Main touch() function. We won't be using touch until later.
   
So we have a ship class but it isn't much use at the moment. To keep track of our ship we want to use screen co-ordinates (x,y), assign a speed and allocate an image to represent the ship. The following code will achieve these objectives. 
      
Ship = class()
   
function Ship:init(x, y)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.speed = 5
    self.image = readImage("Tyrian Remastered:Boss D")
end
    
function Ship:draw()
    -- Codea does not automatically call this method
    -- Draw the ship
   
    sprite(self.image, self.x, self.y)
   
end
   
function Ship:touched(touch)
    -- Codea does not automatically call this method
end
        
We want to initialise our ship located in the middle of the screen so in the setup() function of your Main class you would have:
    
myShip = Ship(WIDTH/2, HEIGHT/2)
  
And then to draw you ship, in the Main draw() function, after the line background(40, 40, 50) add the line:
   
myShip:draw()
  
It is as simple as that. In subsequent tutorials we will look at the concept of inheritance and ways of moving your ship (the earlier Move Ship code in Tutorial 8 illustrates one method).

Sunday, July 1, 2012

Tutorial 5 - Finite State Machines (Update 23/01/16)

Webcomic Courtesy of Ethanol & Entropy

5.1 Introduction to Finite State Machines (FSM).


Just about every game includes some sort of Finite State Machine (FSM). It is the Developers go to structure for keeping track of what state the game is in and can be used to simulate intelligent behaviour. FSM's are popular because they are:

  • Simple to code;
  • Adaptable & flexible;
  • Easy to debug and maintain;
  • Quick; and
  • Easy to understand.
Even if you want to include some of the funkier game AI techniques like fuzzy logic or neural networks, FSM's form a solid foundation for the incorporation of these.


5.2 What is a FSM?


FSM's were originally invented to solve mathematical problems. It is an abstract machine that can be in one of a finite number of states. The machine can only ever be in one state at a time which is called the current state. You need an event to occur to transition from the current state to a new state. A simple example of a FSM is a switch (see Figure 1). It has two states on and off. Transition from one state to another occurs when your finger flicks the switch. Note this is a European switch, in Australia they work the other way around (i.e. down for on and up for off).


Figure 1.


5.3 Implementing a FSM.


There are a number of different approaches to implementing a Finite State Machine. The easiest way is to use a series of if-then statements. We don't have a switch statement in Lua or enumerated types, so we can't use those. 

In our Spacewar example we could add the following in our Main class setup() function. You need to have added the Twinkle class discussed in Interlude 5. This will simulate the game running portion of the game for now.


function setup()

    -- Keep track of Game State

    stateSplash = 0
    stateMenu = 1
    stateRun = 2
    stateWon = 3
    stateLost = 4

    gameState = stateSplash

    -- Create our menu button

    button = Button("    Start    ")
    button.action = function() buttonPressed() end

    -- Create the splash screen

    splashScreen = SplashScreen("Spacewar!", 10)

    -- Create the twinkling star background

    twinkleBackground = Twinkle(100)

end


And then in our draw() class, we could add:


function draw()

    -- Set background to black

    background(0, 0, 0)

    -- Draw the appropriate screen based on gameState

    if gameState == stateSplash then
        splashScreen: draw()
    elseif gameState == stateMenu then
        drawButton()
    elseif gameState == stateRun then
        twinkleBackground: draw()
    end

end


The drawButton() and touched(touch) functions are unchanged from the previous tutorial. Modify buttonPressed so that it looks like this:


function buttonPressed()

    -- If the menu button is pressed we transition to the next state.

    gameState = stateRun

end


Finally in the SplashScreen class you need to modify the fadeAnimationDone() function as follows:


function fadeAnimationDone()

-- Call back function for Fader complete
-- Splash screen done, transition to menu state

gameState = stateMenu
end


And you are done, try it out. Your game is now operating as a Finite State Machine. The problem with this approach is that as your game gets more complex you can end up with spaghetti code, which is ok in the kitchen but not so good on the iPad.

5.4 Alternate Approach


@aciolino over on the Codea Forums uses an alternate approach which we really like. We will let him explain in his own words...


Changing the GAMESTATE variable will immediately change the state of the app to whatever screen you want it to go to, all defined in the GAMESTATES table.

Note that this change is IMMEDIATE, so if you didn't set up some values in the destination screen, you're likely to get frustrated quickly. That's why I have a call to ScreenSplash:init() BEFORE I change the GAMESTATE variable.

Also, the screens that you redirect to WILL get the draw() and touched() calls, unlike the comments that Codea generates when you create a new class. 


--
-- Main.lua
-- 
-- Sample of Cofender's main()

function setup()

    displayMode(FULLSCREEN)
     -- define consts
    GAMESTATE_MENU = 1
    GAMESTATE_PLAYING = 2
    GAMESTATE_SHIPEXPLODE = 3
    GAMESTATE_LEVELCOMPLETE=5
    GAMESTATE_ENDED = 4
    GAMESTATE_SPLASH =6
    GAMESTATE_OPTIONS =7
    GAMESTATE_PAUSED = 8

    GAMESTATES = { ScreenTitle, ScreenGame, ScreenShipExplode, ScreenEnd, 
    ScreenLevelComplete, ScreenSplash, ScreenOptions , ScreenPaused }

    ScreenSplash:init()

    GAMESTATE = GAMESTATE_SPLASH 

end

-- This function gets called once every frame

function draw()
    -- This sets a dark background color 
    background(0, 0, 0, 255) 

    --state machine
    GAMESTATES[GAMESTATE]:draw()
end

function touched(touch)
    --state machine
    GAMESTATES[GAMESTATE]:touched(touch)      
end

--to send keys to proper screen for processing
function keyboard(key)
    GAMESTATES[GAMESTATE]:keyboard(key)      
end

Friday, June 22, 2012

Tutorial 3 - A Simple Button Class (Updated 10/1/16)


Webcomic Courtesy of Ethanol & Entropy

3.0 Creating a Button in Codea


A control that you will use frequently is a button. Now that we have the foundations sorted we can punch out a simple button quite easily. Mostly because a sample button class is provided with Codea. There is a bit of cutting and pasting involved but we will go through each line of the Button() class so you can understand what is what.

Whip back to our old friend the Sounds Plus example project and copy all of the contents of the Button class tab. Back in your Menu project, create a new tab, call the Class Button and paste the code you just copied. Refer to Tutorial 2 if you have forgotten the exact steps.

Your Menu project should now contain 3 tabs: Main, RoundRect and Button. We will have a look at the Button class first. I have inserted a bunch of additional comments (in blue) so you can understand what is happening.

3.1 The Button Class


Button = class()

-- [[ There are no classes in standard Lua however they are handy concepts so Codea includes a global function called class() which provides equivalent functionality. You can read more about Codea classes in the wiki ]]

function Button: init(displayName)

-- [[ The Init function gets called before setup(). This is where you define and initialise your class and its member variables. The class variables are fairly self explanatory but for completeness: displayName: Is the text displayed on your button. The button will scale up and down to fit the text. pos: Defines the x and y - coordinates of the button using a vector. size: Is a vector which contains the width and height of the button, which is set by the display name text, and is used to determine if a button has been hit.  action: Is the function that you want called when the button is tapped. color: Is the color of the button fill. ]]

    -- you can accept and set parameters here

    self.displayName = displayName
    
    self.pos = vec2(0,0)
    self.size = vec2(0,0)
    self.action = nil
    self.color = color(113, 66, 190, 255)

end

function Button:draw()

-- [[ Your main code needs to explicitly call this function to draw the button, it won't happen automatically. We will see how this works when we update the main() class. ]]

    -- Codea does not automatically call this method

    pushStyle()

-- [[ pushStyle() saves the current graphic styles like stroke, width, etc. You can then do your thing and call popStyle at the end to return to this state.]]

    fill(self.color)

-- [[ fill is used initially to set the colour of the button, then the font type and size is set. You could change this in your implementation of the button class if you wish. Click here to see the available fonts. ]]
    
    font("ArialRoundedMTBold")
    fontSize(22)
    
    -- use display name for size

    local w,h = textSize(self.displayName)
    w = w + 20
    h = h + 30
    
-- [[ As stated in the code, displayName is used to size the button and then we use the class we looked at in Tutorial 2 to draw a rounded rectangle. ]]

    roundRect(self.pos.x - w/2,
              self.pos.y - h/2,
              w,h,30)
            
    self.size = vec2(w,h)

-- [[ Note that class variables are designated using the self keyword. e.g. self.size. The next block of code sets the colour of the button text and its position on the button. ]]
            
    textMode(CENTER)
    fill(54, 65, 96, 255)
    text(self.displayName,self.pos.x+2,self.pos.y-2)
    fill(255, 255, 255, 255)
    text(self.displayName,self.pos.x,self.pos.y)
    
-- [[ Return the graphic style to what it was before you entered this function. This is considered polite behaviour for a function because it can be hard to track down if the style is being changed deep within some function and you don't want it to. ]]

    popStyle()

end

function Button:hit(p)

-- [[ This function works out if the last touch (after you lift your finger) was on this button, using the size and pos variables. Returns true if it was and false if it wasn't.  The local keyword defines a local variable. Unlike global variables, local variables have their scope limited to the block where they are declared. A block is the body of a control structure, the body of a function, or a chunk (the file or string with the code where the variable is declared). ]]

    local l = self.pos.x - self.size.x/2
    local r = self.pos.x + self.size.x/2
    local t = self.pos.y + self.size.y/2
    local b = self.pos.y - self.size.y/2

    if p.x > l and p.x < r and
       p.y > b and p.y < t then
        return true
    end
    
    return false
end

function Button:touched(touch)

    -- Codea does not automatically call this method

-- [[ As with the draw() function the touched function is also not called automatically by your code. If you don't call this then you won't know if someone has tapped your button. It reminds me of the old joke, "what do you call a boomerang that doesn't come back?" ..."A stick!" The test, if self.action checks whether you have defined a function to call when the button is tapped. If self.action is nil then nothing will happen.]]

    if touch.state == ENDED and
       self:hit(vec2(touch.x,touch.y)) then
        if self.action then
            self.action()
        end
    end
end


3.2 The Main Class


Now that you are an expert on the Button Class, we can have a look at what is required in your Main Class to instantiate and use a button. It is fairly simple.

-- Use this function to perform your initial setup

function setup()

    print("Button Test Project")
    
-- [[ Create a new button, it wont be visible until you draw it. The init of the button will also set the displayName. You can change this later if you wish by changing the string assigned to button.displayName. The action variable is assigned the function you want to call when the button is tapped. We haven't attempted to be too ambitious with this first attempt.]]
    
    button = Button("Press Me")
    button.action = function() buttonPressed() end
    
end

-- This function gets called once every frame

function draw()

    -- This sets a dark background color 

    background(40, 40, 50)

    -- Do your drawing here, drawButton is defined below.
    
    drawButton()
    
end

function drawButton()

-- [[ Draw the button at some arbitrary spot on the screen and then call the buttons draw() function. You MUST include this step within the Main draw() function. ]]

    button.pos = vec2(400, HEIGHT/2)
    button: draw()

end

function buttonPressed()
    
-- [[ This is where the action happens. Whenever the button is tapped, this function will be called. You can call it whatever you want but it must match the function that you assign to the button.action variable. We aren't doing anything too exciting here but it should illustrate the point. ]]

    print("Button Pressed")
    
end

function touched(touch)

-- [[ Like the button draw() function this is another one that you MUST call for the button to work. It passes the touch detected in the main class to the button class to see if it needs to do anything with it. If the button detects a hit then the action function gets called. ]]
      
    button:touched(touch)
     
end
   
You can download a copy of the files from here.
   

3.3 An Alternative Approach


You now know how to implement a button and assign an event handler for when it gets tapped.

There are a number of other approaches that you can take to solve this problem. Over on the Codea forum Bri_G, Maxiking16 and Reldonas have all contributed sample code to help make your buttons look even sexier. 

3.4 Other Alternatives (Mesh or Sprites)


Vega has come up with a button class which uses meshes to generate the buttons. This class includes buttons in the Apple style, Windows style and customised buttons. And ChrisF has come up with another approach which uses sprites.