Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Transition animation class issue with nil value

edited March 30 in Questions Posts: 23

I've been trying to create a class to handle basic transition animations between different scenes/states in my apps, as I found myself re-writing the same bit of code multiple times for each individual animation. My goal is to simply recreate an image of the current screens assets using setContext() and then sprite that image to slide in and out of the different scenes as I normally have.

The code seemed to function just fine outside of the class, but I'm having a hard time getting things working the same from within. I end up with a nil value in the class draw that has me slightly confused. Any help would be greatly appreciated.

My full project is way too big to post, so I've created a simple version of my issue…


--# Main function setup() SCENE_MENU = 1 SCENE_INFO = 2 cScene = 1 transAni = Anima(WIDTH,HEIGHT,vec2(WIDTH/2,HEIGHT/2),vec2(-WIDTH/2,HEIGHT/2), SCENE_MENU,SCENE_INFO) transAni.asset = function() testPage() end transAni.action = function() testAnimateDone() end parameter.watch("transAni.img") parameter.watch("transAni.posA") parameter.watch("transAni.active") parameter.watch("transAni.strtA.x") end function draw() background(40, 40, 50) if transAni.active == false then testPage() end transAni:draw() end function testPage() pushStyle() fill(255, 255, 255, 255) sprite("Cargo Bot:Opening Background",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) text("MENU",WIDTH/2,HEIGHT/1.2) text("tap screen to start transition animation",WIDTH/2,HEIGHT/2) popStyle() end function testAnimateDone() print("Transition Animation Complete") cScene = SCENE_INFO end function touched(touch) if touch.state == ENDED then transAni:createImg() transAni:imgAnimate() end end --# Anima Anima = class() function Anima:init(cellW,cellH,posA,posB,sceneA,sceneB) self.cellW = cellW -- img width for setContext self.cellH = cellH -- img height for setContext self.img = nil self.posA = posA -- 1st position of image self.posB = posB -- 2nd position of image self.sceneA = sceneA self.sceneB = sceneB self.asset = asset -- the create function of the page to mock self.action = nil -- function after animation completes(switch scenes) self.active = false -- check for animation currently running end function Anima:draw() --if an image exists then start the animation if self.strtA then -- sprite(self.img,self.posA.x,self.posA.y) -- just spriting the image works when uncommented sprite(self.img,self.strtA.x,self.strtA.y,self.strtA.size) --draw animation (nil value?) end end -- -- Create an image for animating function Anima:createImg() self.img = image(self.cellW,self.cellH) setContext( self.img ) self.asset() setContext() print("Image Creation Complete") return self.img end -- -- if animation isnt already active, activate animation function Anima:imgAnimate() if not self.active then --if animation isnt active self.active = true --activate animation print("active =",transAni.active) self:imgPath() --follow proper path end end -- -- Create a tween path for the image to follow function Anima:imgPath() self.strtA = {self.posA.x, self.posA.y, size = self.cellW} --starting pointA self.strtB = {self.posB.x, self.posB.y, size = self.cellW} --starting pointB self.twnA = {self.posA.x, self.posA.y, size = self.cellW} --1st point in path self.twnB = {self.posB.x, self.posB.y, size = self.cellW} --2nd point in path if cScene == self.sceneB then print("open/slide in image") tween.path(.3, self.strtB, {self.twnB,self.twnA},{loop=tween.loop.once},self:imgAnimateDone()) --Slide in elseif cScene == self.sceneA then print("slide out image") tween.path(.5, self.strtA, {self.twnA,self.twnB},{loop=tween.loop.once},self:imgAnimateDone()) --slide out end end -- -- this runs after the image completes the path function Anima:imgAnimateDone() self.active = false --animation deactivate self.action() end

Comments

  • dave1707dave1707 Mod
    Posts: 5,686

    To start, the strtA should be self.strtA. After changing it to self.strtA, it doesn't look like it's being set to anything before being used in Anima:draw.

  • Posts: 23

    @dave1707 Thanks for your speedy response. I didn't realize I missed adding the “self” to the “strtA” in my draw function when I had copied them over to make my example to post here. Classic silly mistake on my part. I have made the “self” changes to my code above.

    As for the strtA not being set before use in draw. Shouldn't my “if” statement stop it from running before it's first created in Anima:imgPath?

    Simply for testing purposes, even after setting strtA value on the line directly before I call it in Anima:draw, I still get the same error. Self.strtA always shows as nil, but why? I'm pretty sure I'm doing everything in the exact same order that I was before moving things inside the class. I'm guessing it's another silly mistake I'm making somewhere, as I'm fairly new to creating classes.

  • dave1707dave1707 Mod
    Posts: 5,686

    @Circuit Try this. When you create self.strtA in Anima:imgPath, you're not creating the table with keys for the first 2 entries like you do for size. So you need to use the [1] and [2] to get the values.

    function Anima:draw()
        --if an image exists then start the animation 
        if self.strtA~=nil then   
            sprite(self.img,self.strtA[1],self.strtA[2],self.strtA.size)  
        end
    end
    
  • dave1707dave1707 Mod
    edited March 30 Posts: 5,686

    @Circuit Here's a stripped down version of some transition code I have. Keep tapping the screen for the next transition.

    EDIT: Modified the original code posted to not require code changes if more transition screens are added to the spr table.

    displayMode(FULLSCREEN)
    
    function setup()
        done=false
        offset=1
        slide=true
        sp=vec2(WIDTH/2,HEIGHT/2)
        fill(255)
    
        img1=image(WIDTH,HEIGHT)
        setContext(img1)
        sprite("Cargo Bot:Opening Background",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
        text("MENU",WIDTH/2,HEIGHT/1.2)
        text("tap screen to start transition animation",WIDTH/2,HEIGHT/2)
        setContext()  
    
        spr={img1,"Cargo Bot:Startup Screen","Cargo Bot:Starry Background",
                "Cargo Bot:Codea Icon","Cargo Bot:Toolbox","Cargo Bot:About Info Panel"}
    end
    
    function draw()
        background(40, 40, 50)
        transitionScreens()
    end
    
    function transitionScreens()
        if offset<=#spr then
            sprite(spr[offset],sp.x,sp.y)
        end
        if offset+1<=#spr then
            sprite(spr[offset+1],sp.x+WIDTH,sp.y)
        end
        if done then
            text("no more transition screens\n     tap to restart",WIDTH/2,HEIGHT/2)
        end
    end
    
    function touched(t) 
        if t.state==BEGAN then
            if done then    -- restart, or set flag to run whatever you want
                done=false
                offset=1
                slide=true
            elseif slide then
                slide=false
                sp={x=WIDTH/2,y=HEIGHT/2}
                tween(2,sp,{x=-WIDTH/2,y=HEIGHT/2},{},check)
            end
        end
    end
    
    function check()
        offset=offset+1  
        slide=true
        sp=vec2(WIDTH/2,HEIGHT/2)
        if offset>#spr then
            done=true
        end
    end
    
  • edited March 30 Posts: 23

    @dave1707 I can't believe I overlooked that, It's always something so simple that I miss. I was just reading about it too in one of ignatz table tutorials. Oh, the hours I have waisted trying to figure it out on my own.

    There is one other strange difference I'm noticing now that I placed these functions within a class.

    Before class:
    At the end of my tween path I would call a function imgAnimateDone like so…

    tween.path(.5, strtA, {twnA,twnB},{loop=tween.loop.once},imgAnimateDone)
    

    After migration to my class:
    When I call the equivilant function using the self: prefix self:imgAnimateDone, I am unable to run my project without adding the () after it like so…

     tween.path(5, self.strtA, {self.twnA,self.twnB},{loop=tween.loop.once},self:imgAnimateDone())
    

    But I noticed that this causes the function to run immediately instead of waiting for the tween.path to complete. Is there another way to do this? It's critical that this function only runs after my tween is done.

    Also, thanks for the transition example. I really like seeing all the different approaches to similar tasks. I've learned tons through your posts on many different subjects, and truly appreciate your efforts.

  • Posts: 1,969

    You need to enclose it in a closure, like this:

    tween.path(5, self.strtA, {self.twnA,self.twnB},{loop=tween.loop.once}, function() self:imgAnimateDone() end )

  • dave1707dave1707 Mod
    Posts: 5,686

    @Circuit I modified my above code to not require any code changes if more screens are added to the spr table. Also, anyone could use the above code if they want to show different images and wait for a touch to show the next image.

  • edited March 30 Posts: 23

    @yojimbo2000 thanks for the fix, I think that was the final piece to my puzzle. Well, this one anyhow. I'm sure my next head scratcher is just around the corner ; )

  • Posts: 23

    @dave1707 @yojimbo2000 Again, thank you both for all the help, as you have saved me hours of confusion with creating classes. I always try to figure these things out on my own, it just takes me a lot longer to get from point A to point B (pun intended). I can only hope to eventually be as Codea competent as the both of you.

  • dave1707dave1707 Mod
    Posts: 5,686

    @Circuit I'm coming up on 5 years of playing with Codea. There's still a lot about Codea/Lua I don't know which keeps me interested. I also have about 45 years of programming experience and I still learn new things every now and then.

  • Posts: 23

    @dave1707 Well, your many years of coding experience definitely shine through in Codea. I always enjoy reading your input on different topics, as you have a very logical approach to problem solving. I'm still fairly green to the entire programming thing in general, Codea/Lua being the only thing I've tried to learn. As a noob, I can really appreciate having such knowlegable people to turn to when I'm feeling a little lost. It has made learning the language seem much more manageable and a lot less daunting.

Sign In or Register to comment.