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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
코로나 SDK 는 어도브 플래시 (adobe flash)  회사 다니던 사람이 나와서 만든 툴이예요.

아래 링크를 클릭하시면 코로나 SDK를 개발한 Carlos가 자신들이 고생하면서 성장한 얘기에 대해 기술해 놨습니다.
최근 adobe 사에서도 기존의 Flex를 확장해서 모바일 앱 개발 툴을 만든다고 하던데 ..
우리의 Carlos가 이 글을 통해서 adobe (어도비) 사와의 경쟁에서도 자신있다라고 쓰고 있네요.
http://blog.anscamobile.com/2011/10/thoughts-on-flash/

코로나의 강력한 Physics Engine은 Box2D를 사용해서 구현한거고.. 이것에 대해서는 우리가 이미 살펴 봤습니다.

그러면 이제 코로나의 Animation and Motion 기능은 어떤가 한번 살펴 보죠.

이 애니메이션 기능도 아주 강력합니다. 플래시 개발하던 사람이 개발했으니까 당연하겠죠?
우선 Transitions (통과, 이동)에 대해 보겠습니다.
이 Transition Library는 여러분들에게 단 한줄로 쉽게 애니메이션을 만들 수 있게 해 줍니다.
단지 alpha 프로퍼티를 이용해서 객체를 천천히 사라지게 할 수도 있습니다.
transition.to 메소드로 껏을 할 수 있는데요.
한번 보죠.
local square = display.newRect( 0, 0, 100, 100 )
square:setFillColor( 255,255,255 )
 
local w,h = display.contentWidth, display.contentHeight
 
local square = display.newRect( 0, 0, 100, 100 )
square:setFillColor( 255,255,255 )
 
local w,h = display.contentWidth, display.contentHeight
 
-- (1) move square to bottom right corner; subtract half side-length
--     b/c the local origin is at the square's center; fade out square
transition.to( square, { time=1500, alpha=0, x=(w-50), y=(h-50) } )
 
-- (2) fade square back in after 2.5 seconds
transition.to( square, { time=500, delay=2500, alpha=1.0 } )

위 소스를 main.lua로 저장하고 이를 시뮬레이터에서 실행 합니다.
첫줄은 사각형을 그리고 다음에 흰색으로 채웁니다.
w,h 변수에 contentWidth와 contentHeight 값을 넣구요.
그 다음에 두번째 사각형을 그리고 흰색으로 채웁니다.

그리고 transition.to로 이 사각형을 대각선으로 움직입니다.
(이때 사각형은 두번째 지정한 사각형이 됩니다.)
이때 alpha값은 0으로 놨으니까 점점 투명해 지겠죠?

그리고 두번째로 transition.to를 적용했는데요.
이것은 점차 투명도가 없어지는 겁니다.
그러니까 0이었던 alpha 값이 정해진 time과 delay에 맞춰 점차 1로 변하게 됩니다.

실행하면 아래와 같은 화면이 나옵니다.


사각형 하나는 좌상단에 그대로 있고 또 다른 사각형이 좌상단에서 우하단으로 점점 흐려지면서 움직입니다.
다 움직이고 난 후 이 사각형은 점차 뚜렷해 집니다. (delay를 사용했기 때문이죠)

아주 간단한 코드로 애니메이션을 만들었죠?

syntax (신택스)는 아래와 같습니다.
transition.to( target, params )
이 params에 time, alpha, x, y, delay 등이 들어간 겁니다.
정확하게 아래의 파라미터들이 사용가능합니다.
params.time : 밀리세컨드 단위로 동작이 일어나는 시간을 나타냅니다. 디폴트는 500(0.5초) 입니다.
params.transition : 디폴트는 easing.linear 입니다. 이 Easing 에 대해서는 잠시 후 다룰 겁니다.
params.delay : 동작 (코로나에서는 이것을 tween이라고 표현합니다.) 이 시작될 때까지의 시간입니다. 이 시간만큼 기다렸다가 실행 됩니다.
params.delta : boolean값으로 디폴트는 nil로 false를 말합니다.
params.onStart : tween이 시작 되기 직전에 불려집니다. 리스너가 이를 캣치 해서 어떤 동작을 작동 시킬 수 있습니다.
params.onComplete : tween이 끝난 직후 불려집니다. 리스너가 이를 캣치 해서 어떤 동작을 작동 시킬 수 있습니다.

transition.form(target,params)는 transition.to와 비슷한 역할을 합니다. 단지 시작하는 프로퍼티 값이 params table에 특정 지어지고 final값들은 target prior에 상응하는 값을 가진다고 돼 있는데.. 저도 잘 이해가 안 되네요.

아래코드를 보세요.
local rect = display.newRect(  0, 0, 100, 100 )
rect:setFillColor(255,255,255)
 
local tMax =1000+system.getTimer()
local function fadeOut(event)
  local t = event.time
  if t < tMax then
    rect.alpha = 1 - t/tMax
  else
    rect.alpha = 0
    -- done, so remove listener
    Runtime:removeEventListener("enterFrame", fadeOut )
  end
end
 
-- Add listener to begin animation
Runtime:addEventListener( "enterFrame", fadeOut )

사각형을 만들고 흰색으로 채우고
tMax에 현재시각보다 1초 더 많은 시각을 대입하고
fadeOut 함수에는 점차 alpha값을 주는 로직으로 돼 있습니다.
리스너는 Runtime리스너로 enterFrame시 fadeOut을 실행하도록 돼 있구요.
이 리스너는 함수 안에서 alpha 값이 0이 되면서 remove 됩니다.

이와 똑같은 기능을 아래와 같이 단 3줄로 할 수 있습니다.

local rect = display.newRect( 0, 0, 100, 100 )
rect:setFillColor(255,255,255)
 
transition.to(rect, {time=1000, alpha=0})

이제 transition.to의 간편함을 알겠네요.

이외에 아래 기능들이 있습니다.
transition.cancel( tween )    Cancels the tween.
transition.dissolve( src, dst, duration, delayDuration )

이제 아까 살펴 보기로 했던 Easing을 볼까요?

easing library는 transition library에 의해 사용되는 interpolation 함수들의 collection 입니다.
아래와 같은 종류들이 있구요.

easing.linear( t, tMax, start, delta )
easing.inQuad( t, tMax, start, delta )
easing.outQuad( t, tMax, start, delta )
easing.inOutQuad( t, tMax, start, delta )
easing.inExpo( t, tMax, start, delta )
easing.outExpo( t, tMax, start, delta )
easing.inOutExpo( t, tMax, start, delta )

start와 final 값을 만들기 위해 여러분만의 easing 함수를 만들 수도 있습니다.
함수안의 인수들은 다음과 같습니다.
t : transition이 시작된 이후부터 진행된 시간
tMax : transition의 duration
start : 시작 값
delta : 변화 값 (final value = start + delta)

무비클립 (Movieclips)

여러장의 이미지들을 테이블에 넣고 이를 순차적으로 보여주면서 애니메이션 효과를 내는 것이 무비크립입니다.
저는 두 물체가 부딪혔을 때 폭발하는 애니메이션을 이 무비클립으로 효과를 줬었습니다.
플래시 하시는 분들은 플래시에서 구현한 애니메이션을 코로나로 표현할 때 유용할 것 같습니다.
이 movieclip library에 대해 자세히 살펴 보겠습니다.
이 기능을 이용하려면 movieclip.lua 파일이 있어야 합니다.

위 파일을 다운 받으시면 됩니다.
한 400줄 되는 코드인데요. 각자 이 코드를 분석해 보시면 아마 많은 도움이 되실 겁니다.

우선 이 파일을 쓰려면 require()문을 써야합니다.
local movieclip = require("movieclip")
자 그럼 하나 만들어 볼까요?

이 그림들을 이용할 겁니다.

저도 이 그림들을 어떤 샘플 파일에서 받은 것 같은데요.

이름은 explode1.png ~ explode9.png 로 합니다.



local movieclip = require("movieclip")

function bombAni()
    bombAnim = movieclip.newAnim{"images/explode1.png", "images/explode2.png", "images/explode3.png", "images/explode4.png", "images/explode5.png",
    "images/explode6.png","images/explode7.png", "images/explode8.png", "images/explode9.png"};
    bombAnim.x = 200;
    bombAnim.y = 200;

    bombAnim:play{ startFrame=1, endFrame=9, loop=5, remove=true }
end

bombAni()


이 코드를 main.lua 파일에 넣고 실행 합니다.


첫번째 줄은 movieclip 파일을 require 하는 부분입니다.


그 다음 bombAni() 함수가 애니메이션 효과를 주는 부분 입니다.


movieclip.newAnim{} 에다가 사용할 그림들을 다 넣습니다.

그리고 이 값들을 bombAnim이라는 변수에 넣습니다.


bombAnim.x , y 좌표를 줍니다. (폭발하는 위치가 됩니다.)


그리고 bombAnim:play{} 로 애니메이션을 실행 시킵니다.


startFrame은 첫번째 그림부터 한다는 것이고 9번째 그림에서 끝나게 됩니다.

그리고 이 폭발 장면은 5번 반복하게 되고 폭발 장면이 끝난 후에는 remove 됩니다.



이 코드를 실행 시키면 폭발하는 장면이 그럴 듯 하게 나옵니다.

remove 파라미터를 false로 하면 마지막 이미지가 없어지지 않고 계속 남아 있습니다. 디폴트는 false입니다.

그리고 loop 부분을 넣지 않으면 디폴트 값으로 0이 들어가는데요. 이 경우 무한정으로 루프가 반복됩니다.

그리고 startFrame과 endFrame을 적당히 정해주면 중간 이미지부터 시작하거나 끝낼 수 있습니다.


object:reverse() 애니메이션이 거꾸로 실행 됩니다.

play와 똑 같이 파라미터를 넣으시면 됩니다.

object:reverse{startFrame=1, endFrame=9, loop=5, remove=true}


object:nextFrame() : 다음 이미지로 애니메이션이 넘어갑니다.

object:previousFrame() : 이전 이미지로 넘어갑니다. 그리고 정지합니다.

object:stop() :  애니메이션을 현재 프레임에서 정지합니다.

object:stopAtFrame(frame) : 지정한 이미지에서 애니메이션이 정지합니다.


bombAnim:stopAtFrame(2)
bombAnim:play()
 
bombAnim:stopAtFrame(1)
bombAnim:reverse()


이 코드를 추가해 보세요. 뭔가 바뀌었나요? 전 잘 모르겠는데.......

이부분도 많이 시도해 봐야 겠어요.


object:setLabels(labels)

객체에 라벨을 매깁니다.

myAnim:setLabels{ firstLabel=1, anotherLabel=3 }


object:setDrag 이 값이 true가 되면 드래그 할 수 있습니다. 그리고 드래그 범위를 지정하려면 bounds 파라미터를 사용할 수 있습니다.

myAnim:setDrag{ drag=true, limitX=false, limitY=false, onPress=myPressFunction, onDrag=myDragFunction,
                onRelease=myReleaseFunction, bounds={ 10, 10, 200, 50 }}


눌려졌을 경우 myPressFunction 이 실행되고 드래그 될 경우는 myDragFunction이 실행되고 release 됐을 경우는 myReleaseFunction이 실행됩니다.

Drag의 범위는 10,10,200,50 이 되구요.


이 기능으로 아주 다양한 표현을 할 수 있겠는데요...

이 기능을 없애려면 단순하게 myAnim:setDrag{drag=false}를 하시면 됩니다.


이 transition library를 사용하지 않고 애니메이션을 구현해야 할 때가 있습니다.

제 탁구 앱 (Multi Player Ping Pong) 에서 공이 튀는 부분도 프로그램으로 그냥 했거든요.


볼이 벽면에 계속 튀는 코드를 보겠습니다.


local xdirection,ydirection = 1,1
local xpos,ypos = display.contentWidth*0.5,display.contentHeight*0.5
local circle = display.newCircle( xpos, ypos, 20 );
circle:setFillColor(255,0,0,255);
 
local function animate(event)
        xpos = xpos + ( 2.8 * xdirection );
        ypos = ypos + ( 2.2 * ydirection );
 
        if (xpos > display.contentWidth - 20 or xpos < 20) then
                xdirection = xdirection * -1;
        end
        if (ypos > display.contentHeight - 20 or ypos < 20) then
                ydirection = ydirection * -1;
        end
 
        circle:translate( xpos - circle.x, ypos - circle.y)
end
 
Runtime:addEventListener( "enterFrame", animate );


이렇게 하면 저 빨간 공이 움직이면서 벽에 계속 튕깁니다.

제 앱의 경우는 각 벽면들과 공도 객체로 만들어서 addBody를 한 다음에 bounce를 주었습니다.

이렇게 프로그램으로 애니메이션을 하려면 enterFrame 으로 리스너를 달아야 합니다.

그리고 제가 했던 방법으로 하면 Ball에 addBody를 하고 Ball:setLinearVelocity()를 주어도 됩니다.


여기서는 enterFrame을 이용하는 방법을 좀 더 보도록 하죠.


위에 있는 소스는 enterFrame의 Frame-base로 코딩을 한 것입니다.

이 frame rate은 config.lua에서 세팅해 주죠? 그래서 이 세팅 값에 따라 속도가 느려지루도 빨라질 수도 있습니다.


이것을 방지하기 위해서 time-base로 코딩을 해도 됩니다.

만약에 일정한 움직임에 딱 맞는 sound효과를 주려면 위에 Frame base보다는 아래에 있는 time base가 더 낫겠네요.


local xdirection,ydirection = 1,1
local xpos,ypos = display.contentWidth*0.5,display.contentHeight*0.5
local circle = display.newCircle( xpos, ypos, 20 );
circle:setFillColor(255,0,0,255);
 
local tPrevious = system.getTimer()
local function animate(event)
        local tDelta = event.time - tPrevious
        tPrevious = event.time
        xpos = xpos + ( 0.084*xdirection*tDelta );
        ypos = ypos + ( 0.066*ydirection*tDelta );
 
        if (xpos > display.contentWidth - 20 or xpos < 20) then
                xdirection = xdirection * -1;
        end
        if (ypos > display.contentHeight - 20 or ypos < 20) then
                ydirection = ydirection * -1;
        end
 
        circle:translate( xpos - circle.x, ypos - circle.y)
end
 
Runtime:addEventListener( "enterFrame", animate );


실행 결과는 똑 같습니다.

다만 system.getTimer() 와 event.time으로 time base로 볼의 움직임을 콘트롤 한 것이 다릅니다.


이 time base의 경우에도 디바이스가 메모리가 딸려서 버벅 거린다면 문제가 일어날 수 있겠죠?


이렇게 버벅거리는 경우 아래 코드로 보완 할 수 있다고 하네요.

-- Add the following below the code in the previous example
 
local tSuspend
local function onSuspendResume( event )
        if "applicationSuspend" == event.type then
                tSuspend = system.getTimer()
        elseif "applicationResume" == event.type then
                -- add missing time to tPrevious
                tPrevious = tPrevious + ( system.getTimer() - tSuspend )
        end
end
 
Runtime:addEventListener( "system", onSuspendResume );


이 코드를 아까 time base 코드에 덧 붙이세요.

이 경우는 테스트 해 보기가 어려워서 직접 테스트는 못했는데요.

그냥 사용하면 될 것 같습니다.


오늘은 transition library와 Movieclips 그리고 코딩으로 애니메이션 구현하는 법에 대해서 배웠습니다.


다음시간엔 movieclips보다 조금 더 복잡하지만 세밀한 애니메이션 효과를 낼 수 있는 Sprite Sheets 에 대해서 살펴 보겠습니다.


그럼....

반응형