Showing posts with label menu. Show all posts
Showing posts with label menu. Show all posts

Friday, June 29, 2012

Tutorial 4 - A Splash Screen (Updated 17/01/16)

Webcomic Courtesy of Ethanol & Entropy

4.1 Should you do a Splash Screen?


Personally we like adding a splash screen to our Apps. However before starting todays tutorial we should point out Apple's position on this. Quoting from the iOS Human Interface Guidelines:

"Avoid using your launch image as an opportunity to provide:
  • An “application entry experience,” such as a splash screen
  • An About window
  • Branding elements, unless they are a static part of your application’s first screen
Because users are likely to switch among applications frequently, you should make every effort to cut launch time to a minimum, and you should design a launch image that downplays the experience rather than drawing attention to it."
So for all the reasons that Apple don't like a splash screen, we do. There are some lines with Apple that you can't cross and will get you rejected from the App store. This isn't one of those, We have 8 Apps in iTunes and they all have splash screens. So read up on the subject and make your own decision.
Note that even if you decide to toe the Apple line, you can use this class in less controversial instances (eg a win / lose screen or credits).

4.2 Classes You Need to Splash


Most of the classes that we will add are not strictly required to make a splash but when writing a real world App you will probably have something similar so we have included them. There is not a lot of new code required, it is more a case of stitching together what we have already covered. You will need:
If you have been following along then most of these classes will already be in your Menu project. The code for Fader and RoundBorder are shown in Interludes 3 and 4 below. The two classes we need to cover here are the changes to Main and SplashScreen.

4.3 The Main Class


Okay, let's have a look at the revised Main class first.



-- Use this function to perform your initial setup

function setup()
    
    print("Menu & Splash Screen Demo")
    
-- [[ saveProjectInfo("key", "value") allows you to assign metadate to your App. It currently supports the Description and Author keys. The value that you assign to the Description will appear under your App in the Project Browser screen. This block of code is optional but good practise. ]]

    saveProjectInfo("Description", "Menu & Splash Screen Demonstration Code.")
    saveProjectInfo("Author", "Reefwing Software")
    saveProjectInfo("Version", "1.0")
    
    -- [[ The next block of code is also optional. It will keep an eye on our Frames Per Second (FPS) as the App runs. ]]
    
    FPS = 0
    watch("FPS")
    
    timeInterval = 0
    frameCount = 0
    
    -- [[ create a new button which will represent our App menu, it wont be visible until after the splash screen fades away. ]]
    
    button = Button("  Easy Levels  ")
    button.action = function() buttonPressed() end
    
    -- [[ Create the splash screen. The variables passed to the SplashScreen class are text to display and the fading speed of the flash screen. The larger the fading speed the faster it fades. One is the minimum speed. ]]
    
    splashScreen = SplashScreen("Splash Screen Demo", 1)
    
end

-- This function gets called once every frame

function draw()

    -- This sets a black background color 
    
    background(0, 0, 0)

    -- Do your drawing here
    
-- [[ This block of code is optional. It calculates and displays every second the Frames Per Second (FPS) rate that our App is drawing at. ]]

    frameCount = frameCount + 1
    timeInterval = timeInterval + DeltaTime
    
    if timeInterval > 1 then
        FPS = math.round(frameCount / timeInterval)
        timeInterval = 0
        frameCount = 0
    end
    
    -- [[ Draw Splash Screen and when it has finished fading (splashScreen.shown = true) the menu button(s). ]]
    
    if splashScreen.shown == true then
        drawButton()
    else
        splashScreen: draw()
    end
            
end

-- [[ Button related functions - described in earlier tutorials. ]]

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

function buttonPressed()
    
    print("Button Pressed")
    
end

function touched(touch)
    
    button:touched(touch)
    
end

-- [[ This function was written by Vega and is used in the FPS calculation. It can be deleted if you are not including the FPS code. ]]

function math.round(num)
    return math.floor(num + 0.5)
end

4.4 The SplashScreen Class


You can tailor this class to include whatever you want to show on your splash screen. We picked some obvious things like text and a logo. To add a bit more pizzaz we added a rounded border.


SplashScreen = class()

function SplashScreen:init(splashText, fadeSpeed, logoURL)
    
    -- you can accept and set parameters here

-- [[ Those sharp eyed may notice that we only passed in two parameters from our Main class to this class. Consequently Lua will set logoURL to nil. We did this to demonstrate this point. For the tutorial we have hard coded the logo loaded but we will show you in the code below where you can change this. Hopefully most of the variables below are self explanatory. ]]
    
    self.splashText = splashText
    self.fadeSpeed = fadeSpeed
    self.logoURL = logoURL
    self.shown = false

-- [[ We created some colour name variables to make the code more readable. Andrew Stacey has produced a mammoth list of colour names, included in the Roller Coaster example App which comes with Codea. The class is appropriately called ColourNames. You could copy this into your projects if you want to use the names that he has defined. It is overkill for our purposes. ]]
    
    blackColour = color(0, 0, 0)
    redColour = color(255, 0, 46, 255)
    blueColour = color(0, 188, 255, 255)

-- [[ Start by initialising our splash screen border. This class is described in Interlude 4. ]]
    
    splashBorder = RoundBorder(10, 10, WIDTH - 10, HEIGHT - 10, 1, blueColour, blackColour)
    
    -- init Fader
    -- the larger the fade speed the quicker the fade
    
    fader = Fader(fadeSpeed)
    
    if fader.fading == false then
        fader: fade(fadeAnimationDone)
    end
    
-- [[ The next bit of code comes from Simeon's Image IO example project which is included with Codea. In particular the parts related to downloading an image and displaying it. In your App you would more likely use a locally stored image so that it would be displayed regardless of whether you have an internet connection. ]]

     -- Start the logo request, didGetLogo is our callback function
    
    logo = nil
    
-- [[ The next line of code is from the original example and will download the Two Lives Left logo. In a blatant example of self promotion we have replaced this with the Reefwing Software logo. Feel free to insert your own logo URL here. Note depending on the size of the logo used you may have to tweak where it is drawn. To make this class more general and remove the hard coded logo, you can replace this text with self.logoURL. Just make sure you add this variable in the Main class when you initialise the splash screen. didGetLogo is called when the http request finishes. ]]

    --http.request( "http://twolivesleft.com/logo.png", didGetLogo )
    
    http.request( "http://www.reefwing.com.au/Reefwing_Software/Home_files/reefwing-logo-%28black-on-white%29.png", didGetLogo )
    
end

function SplashScreen:draw()
    
    -- Codea does not automatically call this method
    
    pushStyle()
    
-- [[ Set the background black and define the splash text. We haven't drawn it yet. ]]

    background(blackColour)
    font("Arial-BoldMT")
    fill(blueColour)
    fontSize(72)
    textWrapWidth(300)
    textAlign(CENTER)
    
    local w,h = textSize(self.splashText)
    
    -- Detect if the splash screen has started fading.

    if fader.fading == true then
        
-- [[ Start by drawing the border. The order that you draw is important. Drawing this last would make the text and logo hidden. ]]

        splashBorder: draw()
        
        -- Draw the logo we downloaded (when it's ready!)
        
        if logo ~= nil then
            sprite( logo, WIDTH - logo.width/2 - 20, logo.height)
        end
        
        -- Finally draw the text.

        text(self.splashText, WIDTH/2, HEIGHT/2)
        
        fader: draw()
    else
        self.shown = true
    end
    
    popStyle()
end

function fadeAnimationDone()
    
    -- Call back function for Fader complete
    
    print("Splash Screen Fade Complete")
    
end

-- [[ The next bit of code also comes from Simeon's Image IO example project which is included with Codea. ]]

function didGetLogo( theLogo, status, headers )
    print( "Response Status: " .. status )
    
    -- Store logo in our global variable
    logo = theLogo
    
    -- Check if the status is OK (200)
    if status == 200 then
        print( "Downloaded logo OK" )
        print( " Image dimensions: " .. 
                    logo.width .. "x" .. logo.height )
    else
        print( "Error downloading logo" )
    end
end

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.