Showing posts with label transition. Show all posts
Showing posts with label transition. 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

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