Showing posts with label class. Show all posts
Showing posts with label class. 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 29, 2012

Tutorial 10 - A Simple Dial Class


10.1 Your Personality and a Little Maths


This tutorial is based on some code that we ported from our iPhone App Personality Profile. In this App you use a dial to answer a number of questions and a profile is provided based on your selection. We used a dial because we wanted a touch friendly solution and this seemed like an intuitive approach. The App is FREE on iTunes so download it and compare the functionality of the Objective C version to our Lua implementation. The embedded video above gives you an idea of how it works but the effect is better understood when used on your iDevice.


The trick to working out how to move the dial is a mathematical one. In essence you need to convert the cartesian co-ordinates of your finger on the screen to equivalent polar co-ordinates.

It is about now that you realise that those maths lessons way back weren't completely useless and perhaps you should have paid more attention. Don't panic, all you need to know is that it is possible to convert from a point (x, y) to polar co-ordinates which consist of an angle and a distance. The angle tells you how much to rotate the dial and you can use the distance portion to work out whether a point is within a circle which is handy for detecting if a tap was on the dial.

To make life easy we created a function which does all the hard work. We have reproduced it below but note that you also  need the math.hypot() function which isn't available in the Codea version of Lua. Both of these functions (and more) are contained in the Math tab of RSLibrary.

We have made use of the new Codea dependency functionality so if you download the entire tutorial code in one file, then you also need to download RSLibrary and link it as a dependency to DialDemo. See Tutorial 9 if you want to understand dependencies better or see what is in RSLibrary. For this tute you only need the Math and Button tabs but you might as well grab the whole thing.

As an aside, a handy trick which we use in the math.polar function is to assign a default value to a parameter using "or". This works because nil evaluates to false in Lua. See the code below to understand how you can use this to overload functions.



10.2 The Main Class

   
In this instance the Main class is just there to demonstrate the Dial Class. Both Landscape and Portrait orientations are supported using the orientationChanged() function.


      

10.3 The Dial Class


The Dial Class is where the magic happens. We only have a licence to use the knob and dial images in our App, so you are going to have to draw or obtain your own version. Strictly speaking you only need a knob image (the bit that moves). The class should handle any differences in size to our sprites.


   

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

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.

Monday, June 18, 2012

Tutorial 2 - Creating a Rounded Rectangle (Updated 2/9/15)


Webcomic Courtesy of Ethanol & Entropy

Version Information


This tutorial has been updated for Codea version 2.3.1(47). You can check your version of Codea by tapping on the Two Lives Left logo in the bottom middle of the Codea start screen (Tutorial 1, Figure 1).

2.0 Drawing a Rounded Rectangle


Ok so our aim in these tutorials is to create code and classes that can be reused. We are working up to a standard menu class which can be used in your programs. But we need to build some foundations first, and the good people at Two Lives Left have provided most of the sample code we need. Curious?

Now menus need buttons and buttons need a rounded rectangle, so let's start there. Open up the Codea example program called Sounds Plus (Figure 7 - you will need to scroll down a bit) by tapping on it. 


Figure 7. Tap on Sounds Plus Example

One of the tabs in this project is called RoundRect, which is exactly what we need. Tap on this tab. We want to copy this entire class and use it in our new Menu project. To do this, tap and hold on any of the text in this class to bring up the Selection pop up, then tap on Select All, and then Copy. Dismiss the keyboard and then tap the back button (<) in the top left corner.

Back at the Codea launch page, tap on Add New Project and call it Menu (or whatever else you want). You will have one class called Main which you would have seen in Tutorial 1. Tap on the + in the top right corner and then tap on Create New Class (Figure 8). 


Figure 8. Create a New Class.

Call the new class RoundRect and then tap done. This will generate three boiler plate functions (init, draw and touched) which we don't need. Tap and hold on any of the text in the class, Select All and tap the delete key on the keyboard. Tap and hold on the empty screen to bring up the Paste pop up and tap that. Make sure you don't tap Cut to remove the old text otherwise you will overwrite the code you copied and will paste back what you just tried to delete.

You should now have the RoundRect class (Figure 9) which you copied from the Sounds Plus example code. 

Figure 9. RoundRect Class

Let's have a bit of a look at the rounded rectangle class. I have inserted comments in green to help you understand what is happening.

The roundRect function has 5 variables. These are: roundRect(x, y, w, h, r)

x - the x co-ordinate of the lower left corner of the rounded rectangle
y - the y co-ordinate of the lower left corner of the rounded rectangle

w - width of the rounded rectangle
h - height of the rounded rectangle

r - radius of the corners

function roundRect(x,y,w,h,r)

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

    pushStyle()

-- [[ insetPos and insetSize contain the co-ordinates for the internal "fill" rectangle. InsetPos.x = x, insetPos.y = y, insetSize.x = w and insetSize.y = h. In effect this creates a rectangle that is smaller than a factor of "r" within the rectangle co-ordinates specified in roundRect. ]]
    
    insetPos = vec2(x+r,y+r)
    insetSize = vec2(w-2*r,h-2*r)
    
-- Copy fill into stroke

-- [[ Since Codea 1.3 you can retrieve the style information from all style functions by calling them without arguments. This way you only have to set the fill style once as you would for the normal rectangle function. You can read all about how this rounded rectangle function evolved on the Codea Forums.]]

    local red,green,blue,a = fill()
    stroke(red,green,blue,a)
    
-- [[noSmooth() will disable smooth (unaliased) line drawing. It is useful for drawing thin lines. This initial rectangle is used to fill in the centre of your rounded rectangle, it has the usual 90 degree corners. Four lines are then drawn around this to give the rounded corner look. You can see this yourself by commenting out the 4 lines drawn below. ]]

    noSmooth()
    rectMode(CORNER)
    rect(insetPos.x,insetPos.y,insetSize.x,insetSize.y)
    
    if r > 0 then

-- [[ You have to use smooth() if you want to use the ROUND option for lineCapMode. Four lines are now drawn around the filler rectangle. One on each edge. Because the lines have rounded ends when you overlap them it makes the corners look rounded, albeit a bit like a ball if you get the proportions wrong. Each of the lines are twice the width of the corner radius. ]]

        smooth()
        lineCapMode(ROUND)
        strokeWidth(r*2)

        line(insetPos.x, insetPos.y, 
             insetPos.x + insetSize.x, insetPos.y)
        line(insetPos.x, insetPos.y,
             insetPos.x, insetPos.y + insetSize.y)
        line(insetPos.x, insetPos.y + insetSize.y,
             insetPos.x + insetSize.x, insetPos.y + insetSize.y)
        line(insetPos.x + insetSize.x, insetPos.y,
             insetPos.x + insetSize.x, insetPos.y + insetSize.y)            
    end

    popStyle()

end

So let's take our copied class for a spin. On my iPad AIR, the dimensions of the drawing screen is:

Width - 749 pixels
Height - 768 pixels

Sidebar: You can find out your screen dimensions by adding the following two lines to the Hello World project that you created in Tutorial 1. Stick these in the setup() function (Figure 10).


Figure 10. Determine the WIDTH & HEIGHT of your screen.

print("Screen Width: "..WIDTH)

print("Screen Height: "..HEIGHT)

One of the fab things about Lua is its ability to simply concatenate a string and a number using .. as shown in the print statement above. There is no need to convert the number to a string, it happens automagically.

Sidebar Update: As Hillary mentions in the comment below the iPad 3 has the same screen dimensions in the STANDARD display mode as the iPad 1 and 2. I should have mentioned that Codea lets you set one of three display modes using the function displayMode() - obvious huh. The three display modes available are:

1. STANDARD;
2. FULLSCREEN; and
3. FULLSCREEN_NO_BUTTONS (which hides the back, pause and play buttons).

In FULLSCREEN landscape mode the iPad 1 & 2 has screen dimensions of:

Height: 768 pixels
Width: 1024 pixels

You can check this out yourself by sticking displayMode(FULLSCREEN) in the setup() function of the Hello World project that we did in Tutorial 1 and using text() in the draw() function to display the HEIGHT and WIDTH constants - note the output from print() is not visible in FULLSCREEN mode.

The iPad 3 has double the resolution of the earlier versions, i.e. in FULLSCREEN landscape mode -

Height: 1536 pixels
Width: 2048 pixels 


In Interlude 13 we will discuss this subject in a lot more depth, skip ahead and have a read if you are interested.


Tap on the Main tab in your Menu class and below the comment -- Do your drawing here add the following line of code. Note that the variables chosen aren't anything special, we are just trying to draw the rectangle near the centre of the screen. Try modifying the variables yourself to see the effect. See Figure 11.

roundRect(WIDTH/2 - 150, HEIGHT/2, 300, 20, 30)


Figure 11. Using the RoundRect Function.

Run the program and you should end up with a gray rounded rectangle on your drawing screen (Figure 12). In the next tutorial we will turn this rectangle into a button.

Figure 12. A Rectangle with rounded corners!

Happy Coding.

SURPRISE SPECIAL BONUS SECTION:

Well not really that special - I should have mentioned that Codea is designed for fast prototyping and comes with some groovy functions to assist with this, namely parameter.

parameter.number(name, min, max) will populate your run screen with a visual slider which adjusts the value of the global variable called name between the min and max values specified, starting at the initial value. The difference between parameter.number and parameter.integer is that parameter.number gives you a float variable while parameter.integer will give you an integer. You usually stick these in the setup() function of your Main class.

Figure 13. RoundRect with Parameters.

There are a couple of example projects provided with Codea which illustrate the use of parameters but let's give them a spin on our rounded rectangle class. Update the Main class in our menu project to look like the following (Figure 13).

function setup()

    print("Rounded Rectangle Fast Prototype")
    
    -- [[parameter.number provides a float parameter(name, min, max, initial, callback). Don't worry about callback at the moment, we will use this later to respond to changes in the parameter.]]

    parameter.number("x", 0, WIDTH, WIDTH/2 - 150)
    parameter.number("y", 0, HEIGHT,  HEIGHT/2) 
    parameter.number("w", 0, WIDTH, 300)
    parameter.number("h", 0, HEIGHT, 21)
    parameter.number("r", 0,  200,  30)

end

-- This function gets called once every frame

function draw()

    -- This sets a dark background color 
    background(40, 40, 50)

    -- Do your drawing here
    
    roundRect(x, y, w, h, r)
    
end

Now run the program and note how moving the sliders changes the variables which effect your rounded rectangle. You can see how easily you could play with this to get exactly the shape you were after. You could then note down the variables required to reproduce that shape in your code. You will need to scroll up the parameter list to see r (Figure 14).


Figure 14. RoundRect with Parameters.


2.1 An Alternative Approach


@Jordan has come up with an alternative approach to drawing rounded rectangles using an ellipse for the corners. His code is available over at the Codea Forums.