I
이번주 화요일의 튜토리얼은 코로나 Ambassador 인 Brent Sorrentino 씨가 해 주셨습니다. parallax scrolling 과 여러분 앱에 customizable touch-and darg parallax view 를 구현하는 데모 프로젝트에 대해 다룹니다.
We Live in a Parallax World
Parallax 는 천문학, photography,광학 에서 다루는 개념인데요 좀 의미가 광범위 합니다. 모바일 게임 개발자의 경우 2-dimensional scrolling simulation 에 대해 작업할 경우 parallax는 카메라와 움직이는 객체 사이의 거리감 (sense of “distance”) 을 제공하게 되죠. 이 메소드는 16 비트 닌텐도 시절부터 사용되어져 왔습니다. 그리고 요즘 인기있는 Angry Birds 와 Squids 등에서도 사용되고 있죠.
코로나의 display groups를 활용하면 차례로 겹쳐진 layer 들로 parallax scrolling을 간단하게 구현할 수 있습니다. 이론적으로는 그런데 실제 많은 개발자들이 실제 이것을 코딩하려고 하면 많이 헛갈려 하시죠. 오늘의 튜토리얼과 데모 프로젝트는 이 부분에 촛점이 맞춰져 있습니다.
1. Getting Started
처음으로 우리가 할 작업은 우리의 parallax "layers" 들을 display groups 로 configure 하는 겁니다. main.lua 파일에 아래 코드를 복사해 넣으세요.
--First, declare a local reference variable for the stage.
local stage = display.currentStage
--Declare your parallax layers in back-to-front order and specify their distance ratio.--This "distanceRatio" sets the layer's scrolling speed in relation to the foreground (1.0) layer.local back00 = display.newGroup() ; back00.distanceRatio = 0.2local back01 = display.newGroup() ; back01.distanceRatio = 0.4local back02 = display.newGroup() ; back02.distanceRatio = 0.6local back03 = display.newGroup() ; back03.distanceRatio = 0.8local foreground = display.newGroup() ; foreground.distanceRatio = 1.0
--IMPORTANT NOTE 1: You MUST have one layer set to 1.0 ratio, even if it won't contain any objects.--IMPORTANT NOTE 2: Attach a reference variable named "refGroup" to the stage table and set its--value to the 1.0 layer from above. This group will be used as the core reference group in--relation to screen touch-and-drag.stage.refGroup = foreground
각 parallax layer 는 “distanceRatio” parameter를 정해 줍니다. 이것은 아주 중요한 부분입니다. 우리는 이것을 foreground 의 1:1 scrolling 과 연결해서 각 레이어별로 스크롤링 스피드를 주는부분에서 사용할 겁니다. 만약 특정 layer 가 parallax scrolling에서 제외되어야 한다면 간단하게 이 파라미터를 undeclare 하면 됩니다. 예를 들어 이 display group setup의 hierarchy 중에 한개 나 두개의 layer 를 scroll 하고 싶지 않다면 , 예를 들어 UI/button/widget layer 같은 경우가 될 수 있겠죠, 이럴 경우 이 distanceRatio 값을 넣지 않으면 됩니다. 이 “distanceRatio” parameter 가 있는 layer 만 parallax scrolling 이 될 테니까요.
Additional note: “distanceRatio” parameter 는 여러분이 원하신다면 1.0 보다 클 수도 있습니다. 예를 들어 1.4로 했다면 이 레이어는 foreground 보다 더 빨리 움직일 겁니다. 이건 아마 카메라와 foreground 사이에 연한 안개가 있도록 할 경우에 활용할 수 있겠네요.
2. Setting Scroll Limits
대부분의 시나리오에서 어떤 제한된 공간(세계) 가 있게 되죠. 유저가 어느쪽으로 어디까지 drag 할 수 있는지에 대한 제한 등이 그런 것들인데요. 이런것들은 다음에 나오는 4개의 변수들에 의해 해결할 수 있습니다. 다음에 이것들을 쉽게 사용하도록 하기 위해 stage 의 파라미터들로서 이 4개를 정의해 둡니다.
여러분의 프로젝트에 다음 한 줄을 추가해 주세요.
stage.xMin = -400 ; stage.xMax = 400 ; stage.yMin = -150 ; stage.yMax = 1000
이 4개의 파라미터가 간단하게 그 제한된 공간을 나타낼 겁니다. xMin는 대개 음수가 되겠죠. 왼쪽까지 얼마나 멀리 그 공간이 정해질지를 정합니다. xMax는 오른쪽까지의 공간이구요. yMin 과 yMax는 위쪽과 아래쪽으로 스크롤할 수 있는 공간을 나타낼겁니다.
이 숫자들은 모두 픽셀단위를 사용합니다. % 가 아닙니다. 또한 foreground 1:1 레이어는 움직이지 않을 거구요. 이 foreground layer 이외의 layer 들은 이 제한사항들이 적용될 겁니다.
3. Add Layers to a Containing Table
이제 우리는 이 parallax layer 들을 paraGroups라는 이름의 테이블에 포함시킬 겁니다. 그리고 그 테이블은 stage 의 sub-table 이 될 거구요.
아래 코드를 여러분 프로젝트에 복사해 넣으세요.
stage.paraGroups = {}
for g=1,stage.numChildren do if ( stage[g].distanceRatio ) then stage.paraGroups[#stage.paraGroups+1] = stage[g] endend
이 코드를 보면 첫번째로 테이블을 정의합니다. 그리고 display groups 에 대해 stage 의 각 child 숫자 만큼 루프를 돌립니다. 그리고 if 문을 사용해서 “distanceRatio” parameter가 있는 경우에만 테이블에 집어 넣습니다.
4. Populate the World
다음 코드에서는 gradient background를 세팅할 겁니다. 그리고 our world 에 몇개의 샘플 객체들을 추가할 거구요. 이 코드들에 대해서는 일일이 설명하지는 않을께요. 여러분들은 여러분들 나름대로의 parallax world 를 만들실 거니까요. 아래에서 하나의 객체를 각 parallax layer 에 add 하는 것을 보실텐데요. 여러분은 많은 객체들과 이미지들을 추가하셔야 한다는 것만 기억해 두세요.
local cX = display.contentWidth/2 ; local cY = display.contentHeight/2
local bkgrad = graphics.newGradient( {42,17,10}, {0,0,0}, "up" )local bk = display.newRect( 0,0,cX*2,cY*2 ) ; bk:setFillColor( bkgrad ) ; bk:toBack()
local object00 = display.newRect( back00,cX-16,cY-16,32,32 ) ;
object00:setFillColor(150,0,50,120)local object01 = display.newRect( back01,cX-32,cY-32,64,64 ) ;
object01:setFillColor(150,20,50,140)local object02 = display.newRect( back02,cX-48,cY-48,96,96 ) ;
object02:setFillColor(150,40,50,160)local object03 = display.newRect( back03,cX-64,cY-64,128,128 ) ;
object03:setFillColor(150,60,50,180)local foreObject = display.newRect( foreground,cX-80,cY-80,160,160 ) ;
foreObject:setFillColor(150,80,50,200)
5. Implementing Touch and Drag
여러분이 움직일 수 없다면 이 scrollable world 는 소용이 없겠죠. 아래 함수는 screen touch 의 "began" 과 "moved" phases 를 사용해서 paraGroups table 안에 있는 모든 그룹들을 스크린 내에서 여러분이 drag 할 수 있도록 만들겁니다.
이 함수와 touch listener 를 여러분 프로젝트에 복사해 넣으세요.
local function touchScreen( event )
local stageID = event.target local refGroup = stageID.refGroup ; local paraGroups = stageID.paraGroups local eventX = event.x ; local eventY = event.y
if ( #paraGroups < 1 ) then return end
if ( event.phase == "began" ) then
for i=1,#paraGroups do paraGroups[i].offsetX = eventX - refGroup.x paraGroups[i].offsetY = eventY - refGroup.y end
elseif ( event.phase == "moved" ) then
local xDif = eventX - refGroup.offsetX local yDif = eventY - refGroup.offsetY
--If you are NOT limiting the boundaries of your world, comment out these 2 lines. if ( xDif < stageID.xMin ) then xDif = stageID.xMin
elseif ( xDif > stageID.xMax ) then xDif = stageID.xMax end if ( yDif < stageID.yMin ) then yDif = stageID.yMin
elseif ( yDif > stageID.yMax ) then yDif = stageID.yMax end
for i=1,#paraGroups do local group = paraGroups[i] group.x = xDif * group.distanceRatio group.y = yDif * group.distanceRatio group = nil end xDif, yDif = nil,nil
end
stageID, refGroup, paraGroups, eventX, eventY = nil,nil,nil,nil,nil return true
end
stage:addEventListener( "touch", touchScreen )
이 코드에 대해서도 일일이 설명을 드리지는 않겠습니다. 단지 이 behavior를 summarize 할께요.
began phase에서 우리는 paraGroups table에 대해 루프를 돌립니다. 그리고 the foreground reference group 에 대해 각각 특정 X/Y 값을 세팅합니다. 이것은 core 1:1 group 의 포지션에 근거해서 각 layer들의 위치를 정해주기 위해 필요한 부분 입니다.
moved phase 는 실제 action 이 일어나는 곳입니다. 우선 첫번째로 어디에 유저가 touch 했는가에 따라 관련 group 들을 움직이기 위해 xDif 와 yDif ”delta”
values를 정해야 합니다. 그리고 바로 직전의 phase check 으로부터 얼마나 멀리 움직였는지도 정해야 하구요.
마지막으로는 paraGroups table에 루프를 돌리고 각각의 parallax layer의 위치를 조정합니다. 이 때 group 에서 정해 줬던 distanceRatio value에 따라 위치를 조정하게 됩니다. distance ratio 가 1.0 인 foreground
group은 정확히 유저의 touch 를 따라서 움직이게 됩니다. 그리고 그 이외에 layer 들은 여러분이 정해 준 distance ratio 에 따라서 약간씩 다르게 움직입니다. 한번 ratio들을 바꾸고 나서 다시 시도해 보세요. 움직임이 다를 겁니다. 여러번 테스트 해 보시고 가장 그럴듯한 ratio 들을 정하셔서 사용하세요.
아주 간단하죠? 이제 몇개의 layer 든지 상관없이 scrolling touch-and-drag parallax world 를 구현할 수 있는 flexible 한 메소드를 구현했습니다. 이제 실전에서는 각각의 ratio 들만 조정해서 사용하시면 됩니다. 아니면 database 나 text file을 이용해서 dynamically 움직임들을 조정 할 수도 있죠.
6. Cleaning Up
마지막으로 layer references들을 clean up 하는 것을 잊지 마세요. 특히 여러분이 Storyboard 나 Director 와 같은 scene manager 를 사용하고 있다면 더 잊지 마셔야 됩니다. 각 scene manager 에서 사용하는 standard cleanup practices 를 사용하는 것 외에 parallax display groups 에 대한 references 를 가지고 있는 paraGroups table 을 clean up 하는 것도 중요합니다. scene 들이 바뀔 때마다 이 작업들이 이루어 지도록 해야 합니다. touch listener도 remove 하는 것 잊지 마시구요. (전체 메소드가 전체 scene 에서 작동하는 global level 이면 필요가 없겠지만요.)
for i=#stage.paraGroups,1,-1 do
stage.paraGroups[i] = nilendstage:removeEventListener( "touch", touchScreen )
Looking Forward!
다음 튜토리얼에서는 이 메소드를 build 하고 dynamic 하게 parallax layer 를 zoom in/out 하는 간편한 zoom feature에 대해 다루겠습니다. 그 때까지 이 데모 project 를 구현하고 수정하고 테스트 해 보시고 질문이나 제안이 있으면 댓글 달아 주세요.
'Corona SDK > Corona Doc' 카테고리의 다른 글
간단하게 Device 분별하는 예제 (0) | 2012.12.13 |
---|---|
다양한 디바이스 해상도에 맞게 이미지 표시하기 - config.lua file- (0) | 2012.12.06 |
physics engine (물리엔진)의 새로운 기능 event.contact 소개 (0) | 2012.11.29 |
새 위젯 사용하기 Part 1 (0) | 2012.11.08 |
Blend Modes 사용해서 Creative Effects 내기 (1) | 2012.11.01 |
Sprite 로 애니메이션 표현하기와 그 methods 들 (0) | 2012.10.11 |
코로나에서 외부 모듈은 어떻게 작동 될까? (0) | 2012.08.29 |
스토리 보드 기본 사용법 (1) | 2012.08.23 |
메모리 부족 경고 시 처리 방법 (2) | 2012.08.17 |
화면 전환 하면서 state(상태) 관리하기 (0) | 2012.08.09 |