Friday, June 29, 2012

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

6 comments:

  1. Hey David! Thanks for the awesome tutorials! I have learned so much already!! I am having a problem implementing this example. I keep getting "attempt to index local 'self' (a nil value)". I know it has something to do with the self.fading bool but I don't know what. Any ideas?

    And is there someplace that explains pushStyle() popStyle()? They don't make a lot of sense to me. :(
    Thanks!!!

    ReplyDelete
    Replies
    1. Hi Josh,

      Good to hear that the tutes are coming in handy. It is difficult for me to debug your code without more information. It sounds like the self.fading bool hasn't been defined. You can download a copy of the Fader class from: https://www.dropbox.com/s/get4ah7vbww0n53/Fader.lua

      You can read all about pushStyle() and popStyle() at: http://twolivesleft.com/Codea/Reference/#functions/index/graphics

      Basically they just save the current graphics style (pushStyle), you can then do what you want with strokes and fills, etc. and when you are done popStyle will return the program to the previous settings. It is a good idea to use these in your classes so you don't have to remember what you have changed and change it back (otherwise it could effect what you are drawing elsewhere).

      Feel free to ask more questions if you get stuck.

      Cheers,

      David

      Delete
    2. Ok I finally figured it out, I had a crazy syntax error. I was using Vega's version to test. I put myFader.fade(changelevel), instead of Fader:fade(changelevel) Coming from my tiny knowledge C# and Java I just automatically want to use "this.whatever" This : colon thing will take a little getting used to. Thanks again for the help! On to the next Tutorial.

      Delete
    3. Good to hear. Codea doesn't have the most robust debugging tools so some errors are tricky to track down. I came from C# as well so I know what you mean, stick with Lua though, it is a surprisingly elegant language. I'm learning C++ at the moment.

      Delete
    4. C++ is good an all but coming from c# you may feel like your back peddling a little. I happen to like c++ because of pointers and other features. But that just me coming from stuff like basic and C. OOP is so much better. I didn't like java because I really liked the pointers in c++. They have it in c# too But I haven't gotten used to it as of yet. I'm not a real fan of c# yet I guess though that's because of some of the tutorials I have read were really not very good. Like this one I read was almost completely abstractions, no real code was really implemented, just one abstraction after the next. It was really frustrating.

      Delete
    5. Most of the c based languages seem to be fundamentally pretty similar, which I guess makes sense since they share a family tree. I'm learning c++ because a LOT of games are coded in this, and that is an area I'm interested in. One of the good things about c# was the XNA game framework that Microsoft provided. I'm also a big fan of languages with garbage collection, thank goodness that Objective C has introduced ARC (while not garbage collecting it does take most of the pain out of the alloc-retain-release cycle).

      Lua I like because it has some different programming paradigms and a very simple syntax. A good language to start learning on I think.

      Delete