반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


지난번에 이어 animation chain 소스를 분석해 보겠습니다.

지난번 글을 올린지 1주일이 지났나보네요.


지난번 main.lua 에서는 화면에 나오는 빨간 공 4개와 흰공 한개를 배치하는 로직이었습니다.

animationchain.lua 에서는 이 흰공을 4개의 빨간공을 따라서 움직이게 하는 코드가 있을 겁니다.


main.lua 의 마지막 줄에 이 작업을 하기 위해 animationchain.lua 에 있는 함수를 이렇게 call 했습니다.


animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()


c 가 바로 흰공이었고 stops 에는 빨간공들의 위치값들이 있습니다.


animationchain.lua 의 소스는 아래와 같습니다.


local M={}
animationchain=M

local transition=transition
local setmetatable=setmetatable
local type=type
local error=error

setfenv(1,M)

local function start(anim,options,onStart,onComplete)
    return function()
        if options.delete then
            options.onComplete=function(obj)
                obj:removeSelf()
                if onComplete then
                    onComplete()
                end
            end
        else
            options.onComplete=onComplete
        end
        anim()
        if onStart then
            onStart()
        end
    end
end

-- args
-- exec - is the current function to execute. It is assumed to be a function that runs a Corona SDK transition
-- options - options for the animation (see Corona SDK). These are assumed to be the same closed over by the exec call - chainFunctions relies on being able to manipulate them for "onComplete" and "whenDone" to work
--         # Additional feature: if options.delete==true the subject of the animation will be deleted (obj:removeSelf() called) when the animation completes
-- runParent (optional) - run the previous function in the chain. It takes a single function as an argument. chainFunction creates this function itself
-- noanim (optional) - true if exec does not represent a function executing a Corona SDK transition. If true, the only valid call to the chain is "start"
function chainFunctions(exec,options,runParent,noanim)
    local t={}

    local mt={
        __index=function(t,k)
            local run=function(execChildAnim)
                local doIt
                -- wrap child animation in relation to previous call
                local onStart,onComplete
                if k=="onStart" or k=="whenStart" then
                    onStart=execChildAnim
                elseif k=="onComplete" or k=="whenDone" then
                    onComplete=execChildAnim
                end
               
                doIt=start(exec,options,onStart,onComplete)
               
                if runParent then
                    runParent(doIt)
                else
                    doIt()
                end
            end

            return function(...)
                if k=="start" then
                    return run()
                end
                if noanim then
                    error("animationchain: passing in pure functions must terminate the chain. Only call start after passing a single function into the chain")
                end
                if #arg==1 and type(arg[1])=="function" then
                    -- just a function has been passed in.
                    return chainFunctions(arg[1],{},run,true)
                end
                   
                return anim(arg[1],arg[2],run)
            end
        end
    }

    setmetatable(t,mt)
    return t

end

function anim(obj,options,runParent)
    return chainFunctions(function () return transition.to(obj,options) end, options,runParent)
end

return M


여기서 어느 부분이 제일 먼저 실행 될까요?


이 파일에는 크게 세개의 함수가 있습니다. 맨 처음에 start() 함수가 있구요. 두번째에 chainFunctions() 그리고 세번째로 anim() 함수가 있습니다.


start 함수가 맨 처음에 있고 이름도 start 이니까 이게 제일 먼저 실행 될까요?

아닙니다. 사실은 start() 함수는 이 세개중에 제일 나중에 실행 됩니다.


함수는 running time 중에 누군가가 call 해 주지 않으면 실행되지 않습니다.

마치 옛날 왕의 여자들처럼 나라를 run 하시는 왕이 call 하지 않으면 평생 독수공방해야 되듯이요.


제일 처음 실행되는 함수는 anim() 입니다. 왜냐하면 main.lua 의 맨 마지막 단계에서 이 함수를 call 했기 때문이죠.


이 anim() 함수는 무슨 행동을 할까요?


chainFunctions() 함수를 return 합니다. 즉 chainFunctions() 함수가 실행 되는 거죠.

여기서 파라미터로 function () return transition.to(obj,options) end 와 options, 그리고 runParent가 pass 됩니다.


이 파라미터들이 어디서 온건지 알아볼까요?




그냥 설명하면 길어질 것 같아서 위와 같이 정리해 봤습니다.

c 는 흰공이고 stops[1] 은 빨간공의 좌표 입니다.

빨간공은 따로 파라미터로 넘겨 주지 않습니다. 왜냐하면 흰공만 움직일 거니까요. chainFunctions() 에서 필요한건 빨간공의 좌표값뿐입니다.


우선 main.lua 에서 이 c(흰공) 과 stop[1] 첫번째 빨간공의 좌표를 넘겨 줍니다.

이걸 animationchain.lua 의 anim(obj,options,runParent) 함수가 받죠. 

여기서 obj 는 첫번째 파라미터로서 흰공 c를 말하고 options는 빨간공의 좌표 입니다. 그리고 세번째 좌표 runParent는 main.lua 에서 전달하지는 않았습니다.

이건 나중에 살펴 보겠습니다.


anim() 함수 안에서는 chainFunctions()를 콜하면서 3개의 파라미터를 전달하죠?

그런데 첫번째 파라미터는 함수를 전달해 줍니다.

transition.to(obj,options) 라는 함수 입니다.

transition.to()함수는 corona sdk 에서 제공되는 함수인데 애니메이션 표현할 때 아주 많이 사용합니다.

transition() 함수 API 를 보시려면 여기로 가셔서 참고하세요.


이 transition.to(obj.options)를 해석하자면 obj를 options 까지 움직인다는 의미 입니다. 즉 흰공을 stops[1] 까지 움직이는 거죠.


한번 소스 코드를 바꿔볼까요?


main.lua 에서

animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()를 없애시고 animationchain.anim(c.stops[1])을 넣어 보세요.


그리고 animationchain.lau 의 anim() 함수 안에 

return chainFunctions(function () return transition.to(obj,options) end, options,runParent) 를 없애시고

transition.to(obj.options)를 넣어 보세요.


그러면 흰공이 가운데에서 왼쪽 빨간 점으로 움직일 겁니다.


main.lua 에서 animationchain.anim(c.stops[2]) 를 넣어 보세요. 

그러면 흰공이 곧바로 왼쪽 위에 있는 빨간공으로 움직이죠?


이렇게 해 보시면 transition.to() 함수의 기능을 확실히 아실 수 있을 겁니다.


일단 오늘은 animationchain.lua 파일에 있는 3가지 함수 중에 main.lua 에서 call 되서 가장 먼저 실행되는 anim(obj.options,runParent) 함수에 대해서 분석해 봤습니다.


이제 이 anim() 함수 안에서 chainFunctions()를 호출 하는 것을 확인 했습니다.

이때 3개의 파라미터가 전달 되는데 첫번째 파라미터는 흰공이 2번 빨간 공까지 transition 한다는 함수이고 두번째 파라미터는 options로서 이건 main.lua에서 부터 전달 된 빨간 공의 좌표 입니다.


runParent는 아직 정체를 알 수는 없습니다.


아마 이 소스의 핵심 부분인 chainFunctions()를 분석하면 알 수 있을 겁니다.


오늘은 여기까지만 하고요.


다음에 chainFunctions()를 분석해 보겠습니다.

반응형

Comment