Storyboard Scene Events Explained
Posted by Jonathan Beebe
지난 11월에 Storyboard API를 소개했을 때 (한글, 영어) 이 스토리보드 API 소개와 함께 어떻게 사용할 것인가에 대한 간단한 설명을 한 이후로 이 API에 대한 추가적인 가이드나 튜토리얼을 소개해 드리지 못했습니다.
그래서 오늘 스토리보드 API 전체를 구성하고 움직이게 하는 각각의 개별 이벤트들에 대해 설명하려고 합니다. 그리고 이 각기 다른 이벤트들이 어떻게 조화를 이루도록 하는지에 대해 보여 드리겠습니다. 여러분 중 scene 이벤트들에 대한 이해가 부족해서 스토리보드 API를 사용하시는데 문제가 있으셨던 분들은 이 글이 많은 도움이 되실 겁니다.
일단 스토리보드 의 scene 객체들이 무엇인지 그리고 각 scene들의 view display group과 scene을 purge 한다는게 무슨 의미인지에 대해 설명 드리겠습니다. 스토리보드 scene 이벤트들을 사용하시면서 view group이나 purge, remove 같은 개념들을 이해하시는 것은 중요한 일입니다.
Scene Objects
Storyboard API의 가장 핵심 객체는 scene 객체 입니다. 이 객체는 단지 특정 프로퍼티들과 이벤트들로 구성된 테이블입니다.
모든 scene 객체들은 storyboard.newScene() 함수를 사용해서 생성됩니다. 여러분은 여러분들이 원하는 만큼의 scene을 만들 수 있습니다. 하지만 일반적으로 새로운 모듈의 top에서 storyboard.newScene() 함수를 한번 call 하게 됩니다. 그리고 모듈의 마지막 부분에 이것을 return 합니다. (그 사이에 scene event-handling 하는 부분이 있겠지요.) 이 방법을 따른다면 scene들은 각 루아 모듈(루아 파일) 마다 하나씩 나오게 됩니다. 그리고 이렇게 정석대로 개발하게 되면 코딩이 더 쉬워지고 가독성도 훨씬 올라가게 됩니다.
The “view” display group
모든 scene들은 display group으로 구성됩니다. 이 display group에 각 scene의 display 객체들이 포함되게 됩니다. 이 display group은 view 프로퍼티를 통해서 access 될 수 있습니다.
sceneObject.view -- Corona display group
이 display group은 항상 현재 상태인 것은 아닙니다. scene들이 루아 모듈들과 서로 관계하면서 부터 가끔씩 모듈 자체가 로드 되게됩니다. 이 때 scene 객체는 active 상태가 됩니다. 하지만 view display group은 그렇지 않습니다. scene이 purged 상태일 때 주로 그렇습니다. 이것은 스토리보드 API를 이용할 때 자주 발생하게 됩니다.
Scene Purging
scene이 purged 된다는 것은 view display group이 removed 됐다는 걸 의미합니다. scene이 purged 됐을 때 scene object는 아직 메모리에 있는 상태입니다. 하지만 눈에 보이는 상황은 아니죠. 이것은 조만간에 다시 이 scene을 로드할 때 유용합니다. 메모리에 있기 때문에 빨리 불러 올 수가 있죠. 실제 texture 메모리를 차지하지는 않으면서 단지 메모리에 존재하는 상태이기 때문에 빨리 불러 올 수 있는 겁니다.
Scene Events
코로나 SDK로 이벤트를 작업는것과 같은 개념으로 스토리보드 API가 설계 됐습니다.
scene이 생성하고 purge , remove 하고 scene들 사이에서 서로 왔다갔다 하는 것들을 모두 API를 통해 콘트롤 할 수 있습니다. 각각의 상황에 맞는 이벤트들이 존재하고 또 연관을 맺게 됩니다. 이 이벤트들이 있음으로 해서 특정 액션이 일어나기 직전이나 일어난 이후에 어떠한 일을 할 수가 있게 됩니다.
아래에 scene 과 관련한 이벤트 들이 열거돼 있습니다.
- createScene
- enterBegan (requires build 2012.773 or later)
- enterScene
- exitScene
- exitEnded (requires build 2012.773 or later)
- destroyScene
createScene
이 이벤트는 scene의 view display group이 생성 될 때 dispatch 됩니다. 그러니까 일반적으로 storyboard.gotoScene()에 의해 call 되는 사이에 dispatch 되게 되죠. 그런데 storyboard.gotoScene() 이 call 됐는데 view display group이 이미 있다면 어떻게 될까요? (이 얘기는 이전에 이 scene이 불려져서 view 객체들이 화면에서는 없어졌지만 메모리에는 아직 남아있는 purge 상태라는 거죠.) 이럴때는 이 createScene 이벤트가 call 되지 않습니다. 곧바로 enterBegan-enterScene 이벤트로 가게 되죠.
createScene 이벤트 리스너 함수내에서는 그 scene에 등장해야 할 display 객체들을 생성하고 그 객체들을 그 scene의 view display group에 insert 하는 일을 하게 됩니다.
아래에 createScene 이벤트 리스너 관련 예제가 있습니다.
local storyboard = require "storyboard"
local scene = storyboard.newScene()
-- forward declarations
local object1, object2
function scene:createScene( event )
local group = self.view
object1 = display.newImage( "image1.png" )
object2 = display.newImage( "image2.png" )
group:insert( object1 )
group:insert( object2 )
end
scene:addEventListener( "createScene", scene )
return scene
Side note : 이 객체를 선언할 때는 creaScene 바깥에서 로컬로 선언을 합니다. 그리고 구체적인 이미지나 텍스트 할당을 createScene 함수 안에서 하게 되는거죠. 이렇게 해야지 그 객체들을 다른 이벤트 리스너 (enterScene 등) 에서 사용할 수 있습니다.
enterBegan
NOTE : 이 이벤트는 Corona build 2012.773 버전에서 추가 됐습니다. 그 이전 버전에서는 사용하실 수 없습니다.
storyboard.gotoScene()이 call 됐을 때 그 scene의 view display group이 생성 될 것입니다. (이미 있지 않으면) 바로 그 다음에 그리고 다른 transition이 일어나기 전에 enterBegin 이벤트가 실행 될 겁니다.
enterBegan 이벤트 리스너를 통해 enterBegin 하는 순간에 원하는 일을 할 수 있습니다. pre-loading 을 한다거나 데이터를 저장한다거나 하는 일들을요. 객체들이 실제 화면에 뜨기 바로 직전에 어떠한 일을 할 수가 있는 겁니다. 아래 예제가 있습니다.
local storyboard = require "storyboard"
local scene = storyboard.newScene()
-- forward declarations
local object1, object2
function scene:createScene( event )
local group = self.view
object1 = display.newImage( "image1.png" )
object2 = display.newImage( "image2.png" )
group:insert( object1 )
group:insert( object2 )
end
scene:addEventListener( "createScene", scene )
function scene:enterBegan( event )
object1.isVisible = false
object2.isVisible = false
end
scene:addEventListener( "enterBegan", scene )
return scene
이 예제에서 createScene 이벤트 리스너와 enterBegan 이벤트 리스너가 어떻게 역할 분담을 해서 일을 하게 할 수 있는지에 대해 보실 수 있을겁니다.
enterScene
이 이벤트는 enterBegan이랑 비슷합니다. 단지 이 이벤트는 scene transition이 일어난 이 후에 call 된다는 것만 다릅니다. 객체들을 특정 지점에 positioning 하거나 유저에게 메세지를 보여주거나 physics를 시작하거나 touch나 enterFrame 같은 이벤트 리스너들을 추가하거나 하는 일들을 이 enterScene 이벤트 리스너에서 하시면 됩니다.
storyboard.gotoScene()에서 enterScene 이벤트까지 어떠한 과정들이 있는지 아래 그림을 통해 보실 수 있습니다.
exitScene
storyboard.gotoScene() 으로 다른 scene을 call 했을 때 현재의 scene에서는 어떠한 일이 일어날까요? 첫번째로 exitScene 이벤트가 dispatch 될 겁니다. 이 이벤트는 현재의 scene이 transition out 되기 전에 일어나게 됩니다.
이 exitScene에서는 어떤일을 주로 하는게 좋을까요? 여기서는 touch, enterFrame 같은 이벤트 리스너들을 remove 하고 애니메이션을 stop 시키고 physics를 pause 시키는 일들을 해야 합니다.
다시 정리하자면 유저가 storyboard.gotoScene()을 call 하면 현재의 scene에서 exitScene 이벤트가 첫번째로 dispatch 될 겁니다. 저 위에 있는 다이어그램을 다시 보시면 이 exitScene 다음에는 어떤 이벤트가 그 다음에 dispatch 되는지 아실 수 있죠?
exitEnded
NOTE : 이 이벤트는 Corona build 2012.773 에서 새롭게 추가 됐습니다. 그러므로 이전 버전에서는 사용하실 수 없습니다.
exitScene은 현재의 scene이 transition out 되기 전에 dispatch 됩니다. 그리고 exitEnded 이벤트는 그 scene이 완전히 transition out 된 직후에 dispatch 됩니다. 그러니까 그 다음 scene이 나오기 바로 직전에 dispatch 되는 겁니다. 아래에 이 5개의 다른 scene 이벤트들에서 어떠한 일들을 시켜야 하는지에 관한 예제가 있습니다.
local storyboard = require "storyboard"
local scene = storyboard.newScene()
-- forward declarations
local object1, object2
-- enterFrame event listener function
local function onUpdate( event )
-- do something here
end
function scene:createScene( event )
local group = self.view
object1 = display.newImage( "image1.png" )
object2 = display.newImage( "image2.png" )
group:insert( object1 )
group:insert( object2 )
end
scene:addEventListener( "createScene", scene )
function scene:enterBegan( event )
object1.isVisible = false
object2.isVisible = false
end
scene:addEventListener( "enterBegan", scene )
function scene:enterScene( event )
object1.isVisible = true
object2.isVisible = true
Runtime:addEventListener( "enterFrame", onUpdate )
end
scene:addEventListener( "enterScene", scene )
function scene:exitScene( event )
object1.isVisible = true
object2.isVisible = true
Runtime:removeEventListener( "enterFrame", onUpdate )
end
scene:addEventListener( "exitScene", scene )
function scene:exitEnded( event )
print( "This scene has fully transitioned out and is no longer the active scene." )
end
scene:addEventListener( "exitEnded", scene )
return scene
destroyScene
이 이벤트는 그 scene의 view display group이 remove 될 때 dispatch 됩니다. 이 이벤트는 view display group이 모두 remove 되기 전에 display object들과 관련된 어떠한 일들 (이벤트 리스너를 없앤다던가 특정 scene 객체들을 manually 없앤다던가 하는) 일들을 하기에 좋습니다.
scnen이 purge 될 때마다 destroyScene은 dispatch 됩니다. scene purging은 다음과 같은 상황에서 발생하게 됩니다.
- storyboard.purgeScene() 이나 storyboard.purgeAll()이 call 됐을 때
- storyboard.removeScene() 이나 storyboard.removeAll() 이 call 됐을 때 (scene은 scene objects 들이 remove 되기 전에 먼저 purged 됩니다.)
- OS 가 메모리 부족 경고 메세지를 보낼 때 가장 최근에 사용된 scene은 자동적으로 purged 됩니다. (모듈은 load 된 상태로 남아 있습니다. 다만 view display group은 texture memory 공간을 확보하기 위해서 remove 됩니다.)
Putting it all together
지금까지 모든 events 에 대해 어떻게 동작들을 하는지 설명했습니다. 그리고 이 각각의 이벤트들이 서로 어떻게 연관을 맺으면서 일을 하게 되는지를 보여주는 간단한 예제들을 보여 드렸습니다. 그런데 이 다른 스토리보드 이벤트들을 필요에 따라 어떻게 활용해야 할까요? 이건 기억해 두세요. 이 모든 이벤트들을 다 활용할 필요는 없습니다. 이 이벤트들은 당신이 필요로 할 때 사용할 수 있도록 만들어져 있지 당신이 모두 사용해야만 하도록 만들어 진 것은 아닙니다.
그리고 일단 createScene 이벤트 리스너에는 객체를 생성하는 코드를 넣으세요. 리스너를 달고 객체들의 위치를 잡고 physics를 시작하고 하는 일들은 대개 enterScene 리스너에서 하게 됩니다. 그리고 객체와 리스너를 remove 하고 physics를 없애고 하는 일들은 exitScene에서 하게 됩니다. (이 exitScene에서는 주로 이렇게 어떤 것들을 해제하거나 없애는 장소 입니다. 다른 화면으로 넘어가기 전에 현재 화면해서 메모리를 잡아 먹고 있는 것들을 다 해제해 주는 작업을 하는 것이죠.)
SampleCode/Interface/Storyboard에 있는 샘플 코드를 실행해 보세요. 터미널에 transition이 시작되거나 끝날 때 이러한 이벤트들이 dispatch 되는 로그들이 찍힐 겁니다.
그리고 이 글을 읽고 난 후에 직접 한번 만들어 보세요. 금방 하실 수 있을 겁니다. 그리고 API의 더 다양한 메소드와 관련된 정보를 얻으시려면 Storyboard Reference를 참조하세요.
아주 오랜만에 글을 올립니다. 개인적으로 좀 일이 있어서요.
오랜만에 올렸는데...
오랜만에 추천도 꾸욱~~ 해 주세요. :)
'Corona SDK > Corona Doc' 카테고리의 다른 글
안드로이드에서 back,menu, key 이벤트 감지하기 (2) | 2012.04.19 |
---|---|
Storyboard, Network 등 변경 사항 안내 (0) | 2012.04.15 |
Tutorial: Detecting Touches in Corona (0) | 2012.04.12 |
Database Access in Corona with SQLite - 2 - (0) | 2012.04.05 |
Database Access in Corona with SQLite - 1 - (0) | 2012.04.04 |
Developing for iPad Retina Display (5) | 2012.03.23 |
새로 추가된 이미지 캡쳐 기능 (2) | 2012.03.21 |
Image Sheets, Image Groups, and Sprites 02 (5) | 2012.03.20 |
Image Sheets, Image Groups, and Sprites 01 (8) | 2012.03.19 |
안드로이드 In-App Purchase with Corona SDK (0) | 2012.03.17 |