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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

Storyboard API 추가 사항 안내

2012. 4. 2. 10:49 | Posted by 솔웅


반응형

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를 참조하세요.


아주 오랜만에 글을 올립니다. 개인적으로 좀 일이 있어서요.

오랜만에 올렸는데...
오랜만에 추천도 꾸욱~~ 해 주세요. :)

반응형

Developing for iPad Retina Display

2012. 3. 23. 12:01 | Posted by 솔웅


반응형
애플이 얼마전 새로운 아이패드를 만듦으로서 iOS 용 앱도 이제 3~4가지 해상도를 고려해서 개발을 해야 되네요.
안드로이드까지 합쳐지면 해상도 종류가 굉장히 많아지죠?

일단 이미지를 Display 할 때 이미지가 찌그러지거나 흐리게 나오거나 하는 문제들이 있습니다.

각기 다른 해상도에서도 선명한 이미지를 보여줄 수 있는 방법에 대해 이번에 Corona에서 블로그에 포스팅을 해 주었네요.

Android Native Language로 할 때는 px 말고 div인가? 뭐 그런 이미지 사이즈 단위를 사용하는 방법도 있고 또 코드 내에서 디바이스 프로파일 정보를 얻어서 다른 이미지를 출력하는 방법 또는 layout xml을 디바이스별로 다르게 준비해서 사용하는 방법이 있고 그렇죠?
Android Native Language로 개발한지 오래 되서 잘 모르겠네요.

하여간 코로나에서는 비교적 간단하게 이 부분을 해결 할 수 있습니다.

이번에 코로나에서 아주 정리를 깔끔하게 잘 해서 올려 준 것 같습니다.
원본은 여기로 가시면 보실 수 있습니다.



Developing for iPad Retina Display

Corona SDK는 현재 공식적으로 New iPad (이 후에는 iPad 3라고 부르겠습니다.) 를 support하고 있습니다. 이 support는 일반 공개버전이나 유료사용자를 우한 Daily Builds 모두에서 지원하고 있습니다.

이 iPad 3는 원래 iPad 보다 3배나 많은 픽셀을 지원합니다. 그래서 개발자들은 이 해상도를 위해 최적화 된 그래픽을 지원하는 방법에 대해 혼란스러워 하고 있습니다.

좋은 소식은 현재의 iPhone이나 iPod touch 를 위한 retina display에서 여러분이 작업을 했다면 새 iPad3도 기본적으로 똑 같다는 겁니다. 하지만 좀 혼동할 수 있는 부분도 있을 것 같아 이 Tutorial에서 그 부분에 대해 설명 하겠습니다.

이 글은 몇개의 다른 시나리오로 나뉠겁니다. 특정 configuration을 이용하는 방법과 여러분의 app이 target 하는 특정 디바이스의 타입에 대해 해야 하는 일 등으로 나뉠겁니다. 여러분은 그냥 필요로하는 부분에 대해 읽고 따라하시면 됩니다.

iPad-only Apps

이 시나리오는 여러분의 앱이 iPad 형식의 디바이스를 위해 만들어지는 경우를 가정한 겁니다. (그러니까 다른 tablet들에도 해당이 됩니다.)

쉬운 방법은 아이폰을 위한 앱을 만들 경우 일단 아이폰에 맞게 작업을 하고 그 다음에 새로운 아이폰에 맞춰 작업하는 겁니다. 그리고 이 방법이 정상적입니다.

그래픽 이미지들을 평상시처럼 만드세요. 그라고 나서 똑같은 이미지를 width와 height가 두배로 키워서 만드세요. 두배로 큰 이미지는 이미지 이름에 공통된 접두어같은 것을 넣어 두세요. (나중에 config.lua 파일에서 사용할 겁니다.) 그렇게 되면 코로나 엔진이 상황에 맞게 필요한 이미지를 가져다가 display 할 겁니다.

그냥 이미지 관련 프로그램으로 원래 이미지를 두배 늘리는 일은 하지 마세요. 그러면 이미지가 번지거나 흐려지게 될 거예요. 원래 목적이 큰 해당도에서도 깨끗한 이미지를 보여주기 위한 거니까 두배로 큰 이미지는 크면서도 깨끗하게 보일 수 있도록 따로 작업하세요. 큰 이미지를 먼저 만들고 나서 작은 이미지로 크기를 줄이는 방법도 좋을 겁니다.

아래 두 개의 작은 해상도를 위한 이미지와 큰 해상도를 위한 이미지에 대한 파일 이름과 관련한 예제가 있습니다.
큰 이미지에는 @2x라는 접미어가 똑같이 붙어있습니다.

    star.png – 128 x 128
    star@2x.png – 256 x 256
    background.png – 768 x 1024
    background@2x.png – 1536 x 2048

그리고 이를 config.lua에서 어떻게 처리해야 하는지 아래에 예제가 있습니다.

application =
{
    content =
    {
        width = 768,
        height = 1024,
        scale = "letterbox",

        imageSuffix =
        {
            ["@2x"] = 2,    -- images with "@2x" appended will be used for iPad 3
        }
    }
}

어떤 화면 방향을 taget으로 하던지 width와 height는 항상 portrait 를 기준으로 config.lua에 명시하셔야 합니다. (그러니까 width는 항상 height보다 작겠지요?)

위 config.lua에서 imageSuffix 테이블에는 @2x 라는 아이템이 있습니다. 이는 코로나 엔진에게 해상도가 두배인 디바이스인 경우에는 이 @2x가 붙은 이미지를 사용하라고 얘기하는 겁니다. (만약에 있으면)

위에 iPad  해상도의 width와 height를 정해 줬죠? iPad 3의 해상도는 이 보통 아이패드의 딱 두배 입니다. 그러니까 위의 예제 config.lua를 사용하시면 이미지를 사용할 때 iPad 3 이면 그 이미지 이름 뒤에 @2x가 붙은 이미지를 사용할 겁니다. (만약에 @2x 가 붙은 이미지가 없으면 원래 이미지를 씁니다.)

여러분이 이렇게 config.lua만 제대로 세팅해 놓으면 코로나는 알아서 디바이스의 크기를 체크하고 이미지를 불러올 때마다 거기에 맞는 이미지를 display 합니다.

local bg = display.newImage( "background.png" )

위와 같이 이미지를 불러오고 위에 제시한 config.lua를 사용한다면 background.png는 iPad 와 iPad 2 에서 display 될 겁니다. 그리고 iPad 3 에서는 background@2x.png가 display 될 겁니다.


iPad + iPhone (Universal) Apps

이 시나리오는 iPhone 해상도 (320X480)에 맞게 작업을 하고 코로나의 dynamic content-scaling 기능을 이용해서 iPad 에 맞게 자동적으로 이미지가 늘어나서 화면에 꽉 차게 display하는 방법을 사용하는 방법입니다.

이 시나리오대로 하기 위한 config.lua 예제가 아래에 있습니다.

application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = "letterbox",

        imageSuffix =
        {
            ["@2x"] = 2,    -- for iPhone, iPod touch, iPad1, and iPad2
            ["@4x"] = 4,    -- for iPad 3
        }
    }
}


위 config.lua를 사용하면 여러분의 앱은 iPhone 해상도에 맞게 작업이 이뤄질 겁니다. 어떤 디바이스이든지 상관 없이 안의 로직은 똑 같이 적용되서 돌아갈 겁니다. 하지만 이미지는 해상도에 맞게 별도로 display 할 수 있습니다. @2x 나 @4x 라는 글자가 추가된 이미지들이 디바이스에 맞게 선택되서 출력 될 겁니다.

@2x와 @4x 뒤에 붙은 2와 4의 의미는 320X480을 기준으로 해상도가 2배 이면 @2x가 붙은 이미지를 보여주고 해상도가 4배이면 @4x가 붙은 이미지를 보여주라는 뜻 입니다.

Getting the Scale Factor

아래에 scale 과 관련한 약간의 트릭이 있습니다. 코로나 시뮬레이터에는 다양한 디바이스에 맞는 시뮬레이터 스킨이 있는데요 아래 코드를 main.lua에 넣고 시뮬레이터를 실행해 보세요.

local deviceWidth = ( display.contentWidth - (display.screenOriginX * 2) ) / display.contentScaleX
local scaleFactor = math.floor( deviceWidth / display.contentWidth )
print( scaleFactor )

위 코드가 하는 일은 device의 width을 얻어내서 이것을 content width로 나눕니다. 이러면 config.lua에 있는 해상도와 비교해서 지금 디바이스 해상도의 크기가 몇배인지 대략적으로 알 수 있습니다.

코로나 시뮬레이터(Corona Simulator)에서 각각의 device skin들을 바꿔가면서 테스트 해 보세요. 그러면 숫자가 바뀌는 걸 보실 수 있으실 겁니다. @2x 에 해당하는 값을 보시려면 iPhone4 시뮬레이터 스킨을 실행해 보시면 됩니다. 그러면 터미널에 2가 찍힐 겁니다. 그리고 iPad Retina 도 선택해 보세요. 그러면 숫자 4가 찍힐 겁니다. New ipad 이전의 iPad는 iPhone 해상도의 두 배 입니다.


Cross-Platform Apps

이 시나리오는 iPad 3를 비롯한 여러개의 디바이스에서 동시에 사용할 수 있도록 앱을 개발하려고 할 때 dynamic content scaling 을 사용할 수 있는 방법입니다.

좋은 소식은 바로 전에 보여드렸던 예제대로 하시면 된다는 겁니다. 단지 좀 더 많은 image suffixes 들이 config.lua의 imageSuffix 테이블에 정의 되어야 겠죠. 또한 이미지들도 여러 사이즈에 맞도록 미리 준비가 되어 있어야 하겠구요.

아래 예제가 있습니다.

application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = "zoomStretch",

        imageSuffix =
        {
            ["@1-5"] = 1.5, -- for Droid, Nexus One, etc.
            ["@2x"] = 2,    -- for iPhone, iPod touch, iPad1, and iPad2
            ["@3x"] = 3,    -- for various mid-size Android tablets
            ["@4x"] = 4,    -- for iPad 3
        }
    }
}

이렇게 하시면 됩니다.

여기까지만 아시면 다양한 해상도를 가진 디바이스들에 (애플(Apple)의 뉴 아이패드(New iPad)를 포함해서) 맞는 이미지를 보여주기 위한 기본 세팅 방법은 모두 알고 계신 겁니다.

====== o ===== o ===== o ===== o =====

이런 방법으로 코딩은 아주 간단하게 해결할 수 있는데 해상도가 다르더라도 선명한 이미지를 보여주기 위해서는 아주 많은 이미지를 사용해야 하네요.
디자인 실력이 없는 프로그래머로서 이미지 하나 만드는것도 많이 신경쓰이고 시간이 많이 걸리는데..
이거 해결해줄 프로그램은 어디 없을까요???
반응형


반응형
App 마케팅과 관련한 기사가 떠서 소개해 드립니다.
Corona 에 대해 아주 좋게 얘기가 나와서 Corona에서 홍보를 했네요.
언론사의 기사라기엔 특정 회사의 이름이 너무 부각된게 아닌가 하는 느낌이 있긴 하네요.
(Corona 말고 GreatApps라는 회사도 나옵니다.)

하지만 앱 마케팅에 도움이 되는 기사이긴 합니다.
내 앱을 홍보하기 위해서는 앱에 대해 관심있는 사람들이 모이는 싸이트에서 열심히 활동하고 인정을 얻는것. 그래서 내가 글을 올렸을 때 좋은 반응을 얻게 만드는 것.
(이 글에서는 동양식으로 좋은 업보를 쌓으라고 표현했네요...)

예전에 SEO 강좌에서도 비슷한 내용이 언급 됐죠?
앱이 나왔을 때 뭐 마케팅할 방법이 뭐가 있지? 라고 고민하기 보단 평상시에 온라인을 통해 정보를 얻고 활동을 하고 좋은 네트워크를 만들고 이런 활동이 필요합니다.
오프라인에서도 아주 오랫동안 좋은 관계를 유지한 사람한테 일 새로 시작했는데 물건 하나 사주세요 라던지 우리한테 일을 맡겨주세요 라고 말하면 더 쉽게 영업을 할 수 있듯이 온라인도 마찬가지 아닐까요?

이런 활동도 하지 않으면서 마케팅 할 수 있는 방법이 왜 이렇게 없지? 라고 헤매는 사람이 되지 말아야 겠어요.

이 기사의 원본은 여기로 가시면 보실 수 있습니다.


5 Ways to Make Your App Take Off

Want your app to be the next Angry Birds or Pinterest? Try these expert strategies for getting it downloaded by the masses.
There are more than a million apps you can download to your mobile device. That’s good news for consumers, but not so great for developers. There’s so much competition in this noisy space that becoming the next Angry Birds or Pinterest is no simple feat. But there are a few things you can do to get your app noticed. Try these expert suggestions:

여러분 앱이 제2의 앵그리 버드나 Pinterest가 되길 원하세요? 그러면 이 전문적인 전략을 사용해 보세요.
여러분의 모바일 device에 다운로드 받을 수 있는 앱은 수백만개 됩니다. 소비자에게는 좋은 소식이죠? 하지만 개발자게에게는 그렇게 좋은 소식만은 아닙니다. 경쟁력이 너무 심해서 제2의의 앵그리버드나 Pinterest 가 되기는 그렇게 쉽지가 않습니다. 여기 여러분의 앱이 주목을 받게 할 몇가지 방법이 있습니다. 이 전문가의 추천을 참고해서 적용해 보세요.

1. Market your app far ahead of launching it.
1. 앱을 launching 하기 전에 마케팅을 하라.

According to Jesse Waites, author of “The Secrets Of My App Success,” it’s critical that you understand who your target market is and where they hang out online during initial product development. Find relevant Internet forums and meet-up groups and make them aware of your upcoming product. This is a great way to get feedback about your app before you even launch, as well as collect a database of potential customers. He says you should also have a widget on your website to collect the email addresses of these future customers so you can notify them when you finally release your product.

내 앱의 성공 비밀을 쓴 저자 Jesse Waites에 따르면 앱을 개발 할 때 이 앱의 타겟이 될 미래 고객을 분석하고 그들이 지금 온라인에서 어떻게 움직이고 있는지를 고려하는 것이 중요하다고 말합니다. 여러분이 개발하고 있는 앱과 관련있는 인터넷 포럼이나 동호회를 찾으세요. 그리고 그들에게 여러분의 앱이 조만간 출판 될 거라는 것을 알리세요. 이렇게 함으로서 여러분 앱이 다 개발되서 마켓에 나가기 전에 여러분의 앱에 대해 feedback을 받을 수 있는 아주 훌륭한 방법입니다. 그리고 잠재적인 고객에 대한 데이터를 모으세요. 저자는 말하길 여러분의 웹사이트에 이 미래의 고객들 이메일을 모을 수 있는 방법을 마련해야 한다고 합니다. 그런 후에 여러분의 상품이 release 될 때 그들에게 notify를 할 수 있습니다.

2. Get reviewed.
2. review를 받아라

Getting your app reviewed favorably is obviously a fantastic way to get people downloading it. iOS developers should definitely check out ManiacDev.com, which has compiled an exhaustive list of Apple app review sites listed in order of Alexa ranking. Many of these sites also review Android apps.

마켓에 올린 후에는 유저들이 댓글(review)를 좋게 올리도록 하는 것이 다른 사람들이 여러분 앱을 다운로드 받게 하는 아주 훌륭한 방법입니다. iOS 개발자들은 ManiacDev.com을 체크해야 합니다. ManiacDev.com은 Alexa ranking의  애플 앱에 대한  review 순위를 보여 줍니다. 또한 안드로이드 앱에 대한 review도 있습니다.

3. Try Corona by Ansca Mobile.
3. Ansca Mobile의 Corona를 이용하라.

Corona is the world’s No. 1 mobile app development platform and many developers have found that by using it not only do their apps work better, but they get more downloads. That’s because Ansca Mobile has partnered with some review sites and podcasts for apps such as 148apps.com, CrazyMikeApps.com, AppShrink.com, Experimental Game Dev Podcast, and MadDog Podcast.

코로나는 세계 제 1의 모바일 앱 개발 플랫폼입니다. 그리고 많은 개발자들이 이 플랫폼을 사용함으로서 앱 개발이 쉬워졌음은 물론이고 다운로드 수도 늘었습니다. 그 이유는 Ansca Mobile은 몇개의 review site들의 파트너사이고 148apps.com, CrazyMikeApps.com, AppShrink.com, Experimental Game Dev Podcast, and MadDog Podcast 샅은곳에 팟캐스트를 하고 있습니다.

Another great feature of the Corona platform is that it can quickly publish an app to multiple marketplaces simultaneously: the Apple App Store, Google Play (Android’s new name for its marketplace), Amazon (for the Kindle Fire) and Barnes and Noble (for the Nook Color tablet). And it’s cheap; a yearly subscription is only $349 or $199 if a developer only wants to build to one platform.

코로나 플랫폼의 또 다른 좋은 점은 빠른시간에 앱을 개발할 수 있고 동시에 애플 앱스토어, 구글 플레이 (안드로이드 마켓의 새 이름), 아마존 (킨들파이어), 반스 앤 노블즈 (Nook color tablet)에 올릴 수 있기 때문입니다. 그리고 코로나 SDK의 가격도 저렴합니다. 연 349불이고 한 마켓에만 올리기를 원하면 연 199불만 내시면 됩니다.

4. Use your online karma.
4. 온라인 업보(Karma)를 쌓아라

Denis Harscoat, co-founder of the action-tracking app DidThis recently got tech pundit Robert Scoble to feature a video blurb about the app on his YouTube channel. But before approaching Scoble about DidThis, Harscoat spent quite a bit of time making thoughtful commentary on Scoble’s blog posts so that when he wanted Scoble to check out his app (at a conference they were both attending), it was easier to get his attention.

액션 트래킹 앱인 DidThis를 공동 개발한 Denis Harcoat는 최근에 그의 유튜브 채널에 앱에 대한 비디오 안내문을 유명한 유튜브 파워블로거인 Robert Scoble의 블로그에 포스팅 되게 됐습니다. 이 DidThis 앱에 대해서 Scoble에게 approach하기 전에 Harscoat는 Scoble의 블로그에 많은 시간을 들여서 여러 충실한 댓글을 달았습니다. 그런 결과 harscoat가 Scoble에게 자신의 앱에 대한 검토를 부탁했을 때 (둘이 같이 참석한 컨퍼런스에서 부탁했답니다.) 그의 관심을 쉽게 끌 수 있었습니다.

Harscoat says DidThis also gleaned a lot of exposure after accumulating Karma points on Hacker News by engaging on the site. Later when he submitted to the site a link that touted his app, Harscoat’s network of supporters strategically up-voted it. “The key is to be genuinely part of a community where people care about certain things your app has a match with,” He says.

Harscoat는 이 DidThis 앱은 자신이 Hacker News 등에서 열심히 활동해 좋은 업보를 쌓은 덕분에 온라인 상에서 많이 노출되는 기회를 얻었다고 말합니다. 나중에 그 싸이트에 그의 앱에 대한 링크를 올렸을 때 Harscoat의 네트워크 지지자들이 많이 투표를 해 주었습니다. "키포인트는 진정성입니다. 사람들이 앱에 대해서 관심있어서 모이는 커뮤니티에 진정으로 열심히 참여하고 진정한 한 일부분이 되서 좋은 업보를 쌓아 두는 것입니다." 라고 그는 말합니다.

5. Get found when someone searches for “great apps.”
5. 누군가가 "좋은 앱"으로 검색할 때 나오게 하라

For as little as $95 you’ll get a year’s worth of promotion on GreatApps, which by way of its URL alone is getting about 40,000 unique visitors every month.  The marketing company also owns the singular domain GreatApp (minus the “s”) so when someone searches the Internet for “great apps” or “great app,” GreatApps almost always lands at the top of the search rank (even without quotes). And for every 50 apps that join its platform, Great Apps issues a press release touting them to more than 2,000 media outlets, although if you want to be included you’ll have to buy the highest level of membership, which is $495.

연 95불을 들여서 GreatApps의 프로모션에 투자를 하면 매달 4만의 방문자가 생길 수 있습니다. 이 마케팅 회사는 GreatApp이라는 단독 도메인을 소유하고 있기도 합니다. 그래서 누군가 인터넷으로 'great apps' 나 'great app' 으로 검색을 하게 되면 거의 항상 이곳이 top에 랭크 됩니다. 또한 그 플랫폼에 join한 50개의 앱들에 대해 Great Apps는 기사를 내 놓기도 합니다. 이 기사는 2천개가 넘는 미디어 싸이트에 광고 됩니다. 만약 여러분의 앱이 이 안에 들게 하고 싶으면 높은 레벨의 멤버가 되야 하구요 가격은 495불입니다.

Have other strategies worked well for you? If so, tell us in the comments about your app and how you’ve had success marketing it.
여러분 위 5개 이외에 여러분들이 사용한 다른 마케팅 전략이 잘 적용 되셨나요? 그렇다면 댓글로 남겨주세요. 어떤식으로 마케팅을 하셨는지요.

Christina DesMarais is an Inc.com contributor who writes about the tech start-up community, covering innovative ideas, news, and trends. Follow her tweets @salubriousdish or add her to one of your circles on Google+. Have a tip? Email her at christinadesmarais (at) live (dot) com. @salubriousdish


반응형

새로 추가된 이미지 캡쳐 기능

2012. 3. 21. 11:05 | Posted by 솔웅


반응형
Taking Snapshots of Objects and Groups

Corona Daily Build 2012.768 에서는 display.capture() 함수를 call 함으로서 간단히 display object (혹은 group) 를 snapshot 하는 새로운 기능이 추가 됐습니다.

이전에는 display.save() 함수를 사용해서 화면의 display 객체들을 저장했었습니다. 이번 display.capture()에서는 save to disk 부분을 거치지 않아도 됩니다. 그리고 snapshot의 새로운 display object로서 사용할 수도 있습니다.

이것은 기본적으로 display.captureScreen()과 같습니다. (display object를 return 한다는 점에서) 하지만 display.captureScreen()에서는 특정 display object나 display group을 따로 캡쳐할 수는 없습니다. display.captureScreen()은 화면 전체의 snapshot을 가져올 뿐입니다.

이번에 새로 추가된 display.capture()함수는 특정 객체나 그룹에 대해서만 snapshot을 할 수가 있습니다. 이 기능을 이용하면 아주 많은 부분에서 활용이 가능 하실 겁니다.

그리고 이 새로운 기능에서는 캡쳐된 스냅샷의 배경을 투명 처리 할 수도 있습니다. (display.captureScreen()과 display.save() 모두 백그라운드를 투명처리하지 못했습니다.)

NOTE : 안드로이드에서는 display.save() 기능이 업데이트 되서 백그라운드를 투명처리할 수 있게 됐습니다. 이것은 daily build 2012.768 부터 가능합니다. 아직까지 iOS에서는 지원이 안 됩니다.



Wait, display.save() can do the same thing!

display.capture() 가 아주 좋은 기능이라고 생각 되시죠? 그런데 display.save() 만 사용해서 저장된 이미지를 새로운 display 객체로 display.newImage()를 사용해서 로드할 수 있을까요?

배경 화면을 투명처리하는 것만 빼고는 가능합니다. display.capture() 가 하는 일과 똑 같이 display.save()를 사용해서도 할 수 있습니다. 그런데 여기에는 좀 큰 단점이 있습니다. 이미지를 디스크에 저장하고 이것을 다시 로드하는 과정에서 퍼포먼스에 큰 영향을 미치게 될 겁니다. 그러므로 display.save를 사용해서 하는 것보다 display.capture()를 사용하는 편이 훨씬 이로울 겁니다.

file I/O 과정을 생략하고 새로운 display 객체로 바로 이미지를 렌더링하는 것, display.capture()는 이런 점에서 display.save()를 사용하는 것 보다 훨씬 빠를 겁니다. 물론 display.save()도 아주 유용한 부분이 있죠. 이미지를 특정 위치에 save 해야 할 때는 display.save()를 사용 하셔야 합니다.

display.capture() Usage

신택스는 아래와 같습니다.
display.capture( displayObject [, saveToPhotoLibraryFlag ] )

아주 간단하죠? 아래 파라미터에 대한 설명이 있습니다.

displayObject — snapshot을 하고 싶은 display 객체나 그룹 입니다.

saveToPhotoLibraryFlag — 이 부분은 필수사항은 아닌데요. true로 설정하면 (디폴트는 false입니다.) 캡쳐된 객체는 display.captureScreen()의 같은 파라미터가 하듯이 디바이스의 photo library로 저장이 될 겁니다.

아래에 display.capture()를 사용하는 예제가 있습니다.

  local group = display.newGroup()

    local image1 = display.newImage( group, "image1.png" )
    local image2 = display.newImage( group, "image2.png" )

    -- take snapshot of the entire group
    local snapshot = display.capture( group )

    -- the object 'snapshot' is now another display object
    snapshot:translate( 100, 100 )
   
주의하셔야 할 부분은 display object가 return 됐을 때 이것은 캡쳐한 object 처럼 캡쳐되기 전과 같은 위치에 잊지 않을 거라는 겁니다. 디폴트로 return 된 display object는 0,0 에 위치합니다. 그러니까 좌상단에 위치하게 되죠. (디폴트로 이미지의 기준점은 이미지의 중앙이니까 실제로는 좌 상단을 더 벗어 나겠네요.)

반응형


반응형
Image Groups

Image Groups는 이번에 새로 소개되는 Corona의 기능입니다. 조금 전에 다뤘던 image sheets 와 이름이 비슷하긴 하지만 완전 다른 기능입니다. Image Groups는 일반 display groups의 sub class 입니다.

Here are the primary differences between Image Groups and normal Display Groups:
아래에 Image Groups가 일반 Display Groups 와 다른 점을 적어놓았습니다.

    Image sheet 객체로부터 생성된다.
    children은 반드시 같은 image sheet에서 나온 것이어야 한다.
    image group내의 모든 child 객체들에대해 제한을 갖는다.
    Image Groups는 nested 될 수 없다. (다른 image groups에 insert 될 수 없다.)

한개의 image sheet에서 나와야 한다? child 객체들에 제한이 있다? 여러분들은 이렇게 제한이 있으면 왜 일반적인 groups를 사용하지 않고 이 Image Groups를 사용해야 하는지 의아해 할 수 있습니다. 정말 그렇습니다. 하지만 여기 이 image groups를 사용함으로서 얻는 장점들도 있습니다.

객체들이 image group에 insert 될 때 일반 display object 들은 할 수 없는 몇가지 이미지 최적화 기능들을 사용할 수 있습니다. 여러분 앱이 최대의 퍼포먼스를 필요로 할 때 그리고 내부적인 그래픽 최적화를 필요로 할 때 바로 이 Image Groups 라는 것을 사용하시면 됩니다. 다음의 제한 사항이 여러분의 앱에 별 상관을 미치지 않을 때 사용하시면 되겠죠?

    image group에 insert 된 객체들은 개별적으로 Mask를 적용할 수 없다.
    nested image groups는 없다. 그러므로 같은 image sheet 안에 있는 다른 곳에 group화 되지 않은 객체만이 같은 image group에 insert 될 수 있다.
    per-object blend mode 가 없다. (image group에 insert 된 객체들에 대해)


How to Use Image Groups

Image Groups는 Image Sheets와 직접적으로 연결이 돼 있습니다. (그러니까 image sheet 을 제대로 보지 못했다면 Image Groups를 보기 전에 이전 글인 image sheet를 보셔야 합니다.)

Image Group Syntax:
display.newImageGroup( imageSheet )

imageSheet 파라미터는 graphics.newImageSheet()를 사용해서 생성한 image sheet 객체를 참고합니다. 한번 Image Group을 만들면 해당 imageSheet에 있는 객체들을 child 객체들로 image Group에 insert 할 수 있습니다.

아래 예제를 참고하세요.

-- assumes an image sheet has already been created
local imageGroup = display.newImageGroup( imageSheet )

local object1 = display.newImage( imageSheet, 1 )
local object2 = display.newImage( imageSheet, 2 )
local object3 = display.newImage( otherImageSheet, 2 )
local object4 = display.newImage( "image.png" )

-- insert objects into image group
imageGroup:insert( object1 )
imageGroup:insert( object2 )

-- lines below result in errors because 'object3' and 'object4'
-- do not belong to same image sheet as imageGroup
imageGroup:insert( object3 )
imageGroup:insert( object4 )

위 예제에서 보듯이 imageGroup은 약간 까다롭습니다. object3,object4 같이 다른 imageSheet나 imageSheet를 사용하지 않은 일반 이미지 객체는 위에서처럼 imageGroup에 insert 될 수 없습니다. 하지만 이렇게 사용하기 조금 불편하고 제약이 있음에도 불구하고 이 image group을 잘 사용하면 그렇지 않았을 경우에 나왔던 단점들을 훌륭하게 극복할 수 있습니다.

코로나는 일부 device에서 퍼포먼스의 문제가 있었습니다. 하지만 이 image groups를 사용함으로서 이러한 퍼포먼스 문제가 깨끗이 해결 됐습니다.
(저도 fireman -iPhone,iPad-, firefighter -Android- 앱을 개발 한 후에 퍼포먼스 문제로 아주 고민을 많이 했었거든요. 이 문제가 해결 됐다니 아주 반갑네요.)

Removing Image Groups

다른 display 객체들 처럼 image groups도 간단히 remove 할 수 있습니다. object:removeSelf()와 display.remove(object) 로 image groups도 remove 합니다. 이 작업을 한 다음에 nil을 대입해 주시는 걸 잊지 마세요.

image group이 child 객체들을 가지고 있다면 그 child들을 개별적으로 remove 한 다음에 image group을 remove 하시기를 권장해 드립니다.

Sprites

새로운 API인 image sheets, image groups 가 나오면서 기존에 있던 애니메이션을 위한 Corona Sprite API도 좀 더 쉽게 사용할 수 있도록 바뀌었습니다. 아래에 바뀐 sprite API에 대한 summary 가 있습니다.

    이전의 sprite sheets나 sprite sets 같은 혼란스러운 개념들 대신 그냥 image sheets를 사용해서 sprite animation 기능을 사용하시면 됩니다.
    변경된 API는 좀 더 직관적이고 이해하기 쉽습니다.
    image sheets를 사용함으로서 dynamic 하게 이미지 해상도에 맞게 작업을 해 줍니다. 다른 말로 이제 sprite를 사용함으로서 retina graphics를 아주 쉽게 사용할 수 있습니다.
    좀 더 파워풀하고 유연한 기능을 위해 새로운 프로퍼티들과 메소드들이 제공됩니다.
   
   
또한 sprite 객체들이 같은 image sheet에 있다면 image groups에 insert 할 수 있습니다. 이것을 사용하면 이전에 image groups에서 얘기했던 제한들이 sprite 객체에도 적용되게 됩니다.

Syntax
display.newSprite( [parent, ] imageSheet, sequenceData )
[Editors Note: Multisprites are not available yet. Sorry for the confusion]
[멀티 스프라이트는 아직 지원되지 않습니다. 혼돈을 드려서 죄송합니다.]

display.newSprite는 single image sheet에서 애니메이션 효과를 주는 객체를 생성하기 위해 사용하는 함수 입니다.
display.newMultiSprite()는 여러 image sheet으로부터 애니메이션 효과를 주기 위한 frame들을 불러와서 애니메이션 효과를 줄 때 사용합니다. 하지만 아직까지는 이 multi sprites는 지원되지 않습니다.

sequenceData는 특적 sequence에 대한 데이터를 가지고 있는 테이블 입니다. 혹은 single object에 대해 1개의 애니메이션 sequence 이상의 sequence를 가지고 있다면 sequenceData는 각각의 sequence에 대한 데이터를 가지고 있는 테이블 배열이 될 겁니다. 예를 들어 charactor 객체를 가지고 있다고 상상해 보면, 걷기, 점프하기, 수영하기 등의 각기 다른 애니메이션 효과를 가지고 있을 수 있습니다.
sequence는 해당 imagesheet의 순서대로 1,2,3,4 가 될 수 있고 1,3,4,6,9 처럼 순서대로 안 돼 있을 수 있습니다. 이 두 경우에 대한 예제를 모두 보시겠습니다.

Single Sequence; Consecutive Frames

아래의 경우는 1,2,3,4 처럼 한개의 image sheet에 있는 frame 순서대로 sequence가 이뤄지는 경우 입니다.

-- Example assumes 'imageSheet' already created from graphics.newImageSheet()

-- consecutive frames
local sequenceData = {
    name="walking",
    start=3,
    count=6,
    time=100, -- Optional. In ms. If not supplied, then sprite is frame-based.
    loopCount = 0 -- Optional. Default is 0 (loop indefinitely)
    loopDirection = "bounce" -- Optional. Values include: "forward","bounce"
}

local character = display.newSprite( imageSheet, sequenceData )

Single Sequence; Non-Consecutive Frames

아래 예제는 frame의 순서와 상관없이 sequence가 이뤄지는 경우인데요. 기본적으로 위의 예제와 같습니다. 다만 frames라는 배열을 넣어야 하는데 이것은 image sheet 안의 frame들의 index들을 넣은 배열입니다.

-- Example assumes 'imageSheet' already created using graphics.newImageSheet()

-- non-consecutive frames
local sequenceData = {
    name="walking",
    frames= { 3, 4, 5, 6, 7, 8 }, -- frame indexes of animation, in image sheet
    time = 50, -- Optional. In ms. If not supplied, then sprite is frame-based.
    loopCount = 0 -- Optional. Default is 0.
}

local character = display.newSprite( imageSheet, sequenceData )

Multiple Sequences

아래 예제는 하나의 sprite 객체에 어떻게 여러개의 애니메이션 sequence들을 가질 수 있는지를 보여 줍니다.
보시면 각 애니메이션 별로 1,2,3,4 처럼 순서대로 index를 사용할 수 있고 비 순서적으로 frame 인덱스를 넣어서 애니메이션을 만드실 수도 있습니다.

-- Example assumes 'imageSheet' already created using graphics.newImageSheet()

local sequenceData = {
    { name="walking", start=1, count=3 },
    { name="running", frames={ 3, 4, 5, 6, 7, 8 }, time=50, loopCount=4 },
    { name="jumping", start=9, count=13, time=300 }
}

local character = display.newSprite( imageSheet, sequenceData )

start/count, frame 파라미터이외에 다른 sequenceData 파라미터들이 있습니다.
아래 내용을 참조하세요.
   
    name - sequence에 대한 unique한 이름 애니메이션이 실행 될 때 이 name을 사용해서 sequence를 load 합니다.
    start & count - consecutive-frame sequences (순차적인 frame 시퀀스)를 위한 파라미터 입니다. start는 시작하는 frame이고 count는 start 부터 끝나는 frame 까지의 index 갯수를 말합니다.
    frames - non-consecutive-frame sequence (비 순차적인 frame 시퀀스)를 위한 파라미터 입니다. 애니메이션을 위해 play 되는 frame 들의 순차적이지 않은 index 데이터를 말합니다.
    time - 각 frame들 사이의 시간 (밀리세컨드)을 말합니다. 이 숫자를 지정하지 않으면 여러분 앱의 기본 framerate을 사용하게 됩니다.
    loopCount - 애니메이션이 몇번 일어나는지 그 숫자를 써 넣으시면 됩니다. 1을 넣으면 애니메이션이 1번 일어나고 멈추게 됩니다. 디폴트는 0이구요 애니메이션이 계속 반복되는 겁니다.
    loopDirection - forward 와 bounce가 있습니다. 둘 중에 아무것도 지정하지 않으면 디폴트인 forward가 지정됩니다. bounce는 forward로 진행했다가 다시 start로 가지 않고 backward로 진행하는 겁니다.
    imageSheet - 이 파라미터는 multi-sprite를 사용할 경우에 필요한 겁니다. (display.newMultiSprite). 해당 시퀀스가 속한 image sheet를 표시합니다. 하지만 아직까지는 multi sprite를 지원하지 않기 때문에 이 파라미터를 사용할 일은 없습니다.

Using “Old” Spritesheet Data

많은 third-party 툴들이 old spritesheet 데이터 포맷을 사용해서 작업을 합니다. 그래서 image sheet 객체를 생성할 때 이 데이터 포맷을을 사용할 수 있도록 했습니다. 아래 그 방법을 보시죠.

local oldStyleSpriteSheetData = require("uma").getSpriteSheetData()

local options =
{
    spriteSheetFrames = oldStyleSpriteSheetData.frames
}

local imageSheet = graphics.newImageSheet( "uma.png", options )

Sprite Properties

일반적인 display object 프로퍼티 이외에 sprite에서 사용하는 프로퍼티들이 있습니다.

    spriteObject.frame – Read-only – 로드된 시퀀드싀 frame index를 보여 줌
    spriteObject.numFrames – Read-only – 로드된 시퀀스의 frame 갯수를 보여 줌
    spriteObject.isPlaying – Read-only – 이름 그대로 현재 플레이되고 있는지 여부를 알려 줌.

Sprite Methods

아래는 display.newSprite()로 생성된 모든 object들과 연관된 sprite만의 메소드들입니다.

    spriteObject:setSequence( name ) – name을 가지고 애니메이션 시퀀스를 로드함. name 파라미터가 없을 경우 현재 로드된 시퀀스의 첫번째 프레임이 보여지게 됩니다.
    spriteObject:play() – 현재 로드된 시퀀스를 플레이 합니다.
    spriteObject:pause() – 시퀀스내의 현재 보여지는 프레임에서 pause 합니다.

Sprite Listener

old API를 보시면 sprite 객체들은 리스너 함수를 사용해 sprite event를 listen 할 수 있습니다. 이벤트 프로퍼티가 변경됐는데요, 지금은 began과 ended event phase 가 있습니다.

Here’s an example:

local function spriteListener( event )
    if event.phase == "began" then
        -- sequence has began playing; do something

    elseif event.phase == "ended" then
        -- sequence has reached the last frame; do something
    end
end
 
-- Add sprite listener
spriteObject:addEventListener( "sprite", spriteListener )

우리는 이 스프라이트 리스너 함수를 좀 더 유용하게 사용할 수 있도록 작업을 하고 있습니다. 조만간에 공개 될 겁니다.

Removing Sprite Objects

sprite 객체들은 다른 일반 display 객체들을 remove 하듯이 remove 하시면 됩니다. object:removeSelf()를 사용하시고 display.remove(object) 도 사용하세요. 이 작업을 한 다음에 nil값을 대입시키는 것도 잊지 마시구요.

Frame Trimming Not Yet Supported

Image Sheets 나 새로운 Sprite API에서 아직 지원하지 못하는 부분이 있는데 그것은 tril/crop frames 기능입니다. 이 기능이 가능할 수 있도록 지금 현재 작업중에 있습니다. 완료되면 공개 하겠습니다.



Wrapping it all up…

여러 이미지를 하나의 이미지 파일에 넣어서 각각의 이미지를 image sheet나 sprite API를 사용한 애니메이션으로 사용하는 방법을 다뤘습니다.
그런데 저는 개발자로서 그래픽 작업하는게 많이 부담 됩니다.
여러 이미지를 하나의 파일로 만들어야 되고 각각의 이미지들 규격도 알아내야 되고...
이러한 작업을 해 주는 third-party 제품들이 있습니다.
코로나에서는 SpriteLoqTexture Packer 를 추천하고 있습니다.
필요하신 분 잘 활용하세요..
저도 필요하긴 합니다.
요즘 시간적인 여유가 좀 생겨서 개인 프로젝트를 시작하려고 하는데요.
그래픽 부분이 부담 되서....
하여간 새로운 기술들을 잘 활용해서 개성있는 앱을 하나 만들어 보려고 합니다.
반응형


반응형
지난번에 올린 Tutorial 인 In App Purchase on Android 이전에 나왔던 새로운 기능에 대한 튜토리얼이 있었습니다.
그 주에 바빠서 정리를 못했는데 너무 delay 되다 보면 다루지 못하고 넘어갈 것 같아 서둘러 정리합니다.

앱을 만들다 보면 애니메이션을 사용할 때도 있고 꼭 애니메이션을 사용하지 않아도 많은 이미지 파일을 사용하게 됩니다.
disk에서 이미지를 불러와서 rendering 하고 화면에 display 하는 과정은 device의 resource를 많이 사용하는 아주 expensive 한 작업입니다.
너무 많은 이미지 사용은 앱의 용량도 크게하고 퍼포먼스에도 안 좋은 영향을 줍니다.

이번에 Corona에서 image sheet라는 새로운 API를 제공하면서 이러한 이미지 처리를 효율적으로 할 수 있는 방법을 제공하고 있습니다.

저도 Fire Man (Fire fighter)  앱이 너무 많은 애니메이션 기능 사용으로 아이폰 3GS나 구식 안드로이드 폰에서는 퍼포먼스가 아주 느려서 고민이 많았거든요.

다음 앱을 개발할 때는 이 image sheet를 사용해서 퍼포먼스에 문제가 없도록 해야 할 것 같습니다.



Corona build 2012.759 버전에 그래픽 관련 새로운 기능이 추가 됐습니다.
오늘은 이 기능에 대해 알아보겠습니다.

아주 많은 부분이 다뤄질 예정이니 주의를 집중해서 보세요. 조금 어렵기도 합니다. 아마 중급정도 수준의 튜토리얼이라고 할까요? 오늘 다룰 부분 중에는 이전의 Corona Doc나 튜토리얼에 나왔던 개념이 아닌 전혀 새로운 개념들도 있습니다.
오늘의 세가지 주요 topic은 아래와 같습니다.
- Image Sheets (새로운 기능)
- Image Groups (새로운 기능)
- Sprite (완전히 바뀜)

아래 다뤄지는 기능은 Corona sdk build 2012.759 버전 이상에서만 작동 됩니다. 그리고 build 2012.761 버전 이상을 사용하실 것을 권장합니다. 오늘 소개할 기능과 관련돼 약간 수정된 내용이 761버전 이후 부터 적용됐거든요.

Notes on Performance

Graphics의 많은 부분이 바뀌었고 그것과 더불어 performance 향상을 제공합니다. 특히 iPhone 3GS 같은 조금 오래된 기계에서 퍼포먼스가 안좋았던 부분이 많이 개선 됐습니다. 하지만 개발자로서 항상 유념해야 될 것은 잘 구성된 코드가 퍼포먼스 향상의 가장 기본이라는 것입니다.

Image Groups 같은 경우에는 어느 부분에서는 좋은 점을 제공하지만 또한 어느 부분에서는 사용하는데 제한이 있을 수 있습니다.
이 새로운 기능들을 사용할 때 이 잇점과 제한된 점을 잘 생각해서 best 한 선택을 하셔야 합니다.

그리고 또 하나의 좋은 소식은 최근의 코로나 버전에서 다른 방법으로 퍼포먼스 향상 효과를 주었는데요. 그것은 바로 화면 밖에 있는 객체에 대해서는 렌더링이 일어나지 않도록 만들었다는 것입니다. 이 방법은 따로 코딩을 바꾸실 필요는 없습니다. 그냥 최근 버전의 코로나를 다운 받으셔서 새로 빌드 하시면 됩니다.

Image Sheets

이 API는 이번에 새로 나온 기능 입니다. 전문 용어에 익숙하신 분은 texture atlas  기능이라고 하면 이해하시기 쉬우실 겁니다.

이해를 돕기위해 좀 은유적으로 설명을 드리자면 여러분 앱의 모든 이미지들이 한장의 종이에 있고 그 종이의 부분 부분을 가져와서 한개의 이미지처럼 사용할 수 있도록 합니다. 그러면 메모리를 줄일 수 있고 이미지 렌더링 시간도 줄일 수 있어서 큰 퍼포먼스의 향상을 가지고 올 수 있습니다.

disk에서 이미지를 메모리로 불러와서 그것을 렌더링 해서 앱에 표시하는 작업은 아주 비싼(에너지 소비가 많은) 작업입니다. 그래서 각각의 이미지별로 이 작업을 하도록 하기 보다는 여러 이미지를 하나의 이미지화 해서 이런 비싼 작업을 한번만 할 수 있도록 하는게 기본 개념입니다.

Texture Size Limit

한 개의 이미지 파일에 몇개의 실제 이미지를 넣을 수 있는지에 대한 제한은 없다. 하지만 이 부분은 유념해야 한다. 각 디바이스 마다 최대 texture size의 제한이 있다. 한개의 이미지 파일의 width,height에 대한 픽셀 수에 대한 제한값이다. 그러므로 한 이미지 파일안에 몇개의 실제 이미지가 들어가는지는 제한이 없지만 이미지 파일  크기가 너무 크면 사용할 수 없다. (그러면 이론적으로는 디바이스가 허용하는 최대크기의 이미지 파일의 픽셀 수가 최대 하용할 수 있는 이미지 갯수겠네요. 1픽셀짜리 이미지를 사용한다면.. 실제 그렇지는 않겠지만요.. 그러면 그건 이미지가 아니라 그냥 color가 있는 점이겠죠?  그냥 심심해서 상상해 봤어요... ^^)

아래 코드는 해당 디바이스에서 허용하는 texture 의 최대사이즈를 구하는 방법입니다.

print( system.getInfo( "maxTextureSize" ) )

대개 코로나가 지원하는 디바이스들은 허용 사이즈가 아주 크다는 겁니다. 여러분 앱에 수백개의 이미지 객체들이 들어간다고 하더라도 몇 개의 이미지 sheet만 사용해도 충분히 해결이 될 겁니다.

Wait, I’m already doing this!

여러분들 중에는 이전의 Sprite API를 사용해서 이러한 기능들을 이미 사용해 보신 분들도 많이 계실 겁니다. 이전의 Sprite API에서는 애니메이션을 사용하기 위한 기능을 주로 지원했습니다. 그래서 애니메이션이 아닌 정적인 이미지를 만들려면 불필요한 부분들이 많이 있습니다. 메모리를 절약하기 위해 이 Sprite API를 사용한다는 건 좀 부담스러운 일이죠.

그래서 이 image sheet를 지원하게 됐습니다. 이 image sheet API를 사용하면 훨씬 더 효율적으로 그리고 쉽게 사용할 수 있습니다. 이 API를 사용하면 정적인 이미지와 애니메이션 모두에서 사용하실 수 있습니다.

보너스가 한가지 더 있는데요. image sheet는 해상도별로 이미지를 다이나믹하게 지원해주는 기능이 있습니다. (예: retina graphics) 이전의 sprite API에서는 이 같은 기능을 구현하기 위해서는 조금 복잡하게 해야 합니다. 이 의미는 이 기능을 사용하면 이번에 해상도가 아주 높아져서 나온 새 애플(Apple)의 아이패드(New iPad) 에도 자동적으로 이미지가 맞게 지원된다는 겁니다.

How to Use Image Sheets

이제 이 image sheets를 어떻게 사용하는지 알아보겠습니다. 우선 신택스부터 보겠습니다. 그리고 나서 display.newImage()와 display.newImageRect()와 함께 어떻게 image sheets가 사용되는지 알아보는 예제를 다뤄보겠습니다. 이 image sheets를 image group과 sprite animation과 함께 사용 하실 수도 있습니다.

Image Sheet Syntax:
graphics.newImageSheet( filename, [baseDir, ] options )

아주 간단하죠? 파라미터 filename은 실제 image file의 이름이구요. baseDir은 디렉토리 입니다. (system.ResourceDirectory 가 될 수도 있고 아니면 다른 곳이 될 수도 있죠.) options 파리미터는 필수로 이 image sheet의 프레임에 대한 데이터를 가지고 있는 테이블을 가리킵니다.

혼란을 방지하기 위해 image는 image sheet file로 graphics.newImageSheet()로 불러온 파일을 말하고 frame은 그 image sheet안의 각각의 이미지들을 구분해서 말하고 있습니다.

options

option 테이블에는 세가지 케이스가 있을 수 있습니다.

    Simple: image sheet의 모든 frame들이 각각 같은 width와 height를 가질 경우
    Complex: image sheet의 frame들이 각각 다른 width나 height를 가질 경우
    Old-Style:  sprite API 데이터 포맷과 같은 방법입니다. (이전에는 sprite.newSpriteSheetFromData() 함수를 사용했었습니다.)

old style은 이제는 권장하지 않습니다. simple이나 complex 케이스 중 하나만 선택하시면 됩니다. old style에 대해서는 따로 다루지 않겠습니다. 이 케이스가 있는 이유는 이것을 이용하던 다른 third-party 툴들이 있기 때문에 아직 없애지 않은 겁니다.

Simple Example

예제를 하나 소개해 드리겠습니다. 우선 image sheet를 로딩할 때 simple option을 사용하는 방법을 보죠. 다시한번 언급하면 image sheet 내의 모든 frame이 각각 같은 width와 height를 가지고 있는 경우 이 simple option을 사용합니다.

local options =
{
    -- The params below are required
   
    width = 70,
    height = 41,
    numFrames = 2,

    -- The params below are optional; used for dynamic resolution support

    sheetContentWidth = 70, -- width of original 1x size of entire sheet
    sheetContentHeight = 82 -- height of original 1x size of entire sheet
}

local imageSheet = graphics.newImageSheet( "fishies.png", options )

예제에서 보시듯이 simple case option은 진짜로 simple 합니다. options에 들어가는 파라미터는 width,height,numFrames 이렇게 3개밖에 없습니다. 남은 2개의 optional 파리미터들은 dynamic resolution images를 사용할 경우 필요한 겁니다. (예를 들어 retina graphics 를 사용하기 위한 image sheet의 @2x 버전 같은)

Complex Example

image sheets에 여러 다른 객체들을 넣어서 사용할 경우 complex-case option 테이블을 사용해야 합니다. 이 경우 각각의 frame에 대해 정해줘야겠죠.

local options =
{
    -- array of tables representing each frame (required)
    frames =
    {
        -- FRAME 1:
        {
            -- all params below are required for each frame
            x = 2,
            y = 70,
            width = 50,
            height = 50
        },
       
        -- FRAME 2:
        {
            x = 2,
            y = 242,
            width = 50,
            height = 52
        },
    },

    -- optional params; used for dynamic resolution support
    sheetContentWidth = 1024,
    sheetContentHeight = 1024
}

local imageSheet = graphics.newImageSheet( "imageframes.png", options )

위 예제를 보시면 image sheet는 두개의 frame을 가지고 있습니다. simple case와는 조금 다르죠? 왜냐하면 각각의 frame들을 array로 그 값을 지정해줘야 하기 때문입니다. image sheet의 complex-case option 테이블을 이용할 경우 이 예제를 참고로 작성하시면 됩니다.

Using with Existing Image Functions

다음으로는 image sheets로부터 얻어낸 각각의 객체들을 기존의 함수들인 display.newImage()와 display.newImageRect()을 가지고 어떻게 사용해야 하는지를 알아보겠습니다.

일단 image sheet를 이용해서 이미지 객체를 이미 만들었다고 가정한 후 아래 예제를 살펴 보세요.
-- assumes 'options' is already constructed (simple or complex cases)
local imageSheet = graphics.newImageSheet( "myimagesheet.png", options )

-- display.newImage()
--
-- SYNTAX:
-- display.newImage( [parent ,] sheet, frameIndex )

local fish = display.newImage( imageSheet, 2 )
fish.x, fish.y = 100, 100

-- display.newImageRect()
--
-- SYNTAX:
-- display.newImageRect( [parent ,] sheet, frameIndex, width, height )

local frog = display.newImageRect( imageSheet, 4, 40, 82 )
frog:setReferencePoint( display.TopLeftReferencePoint )
frog.x, frog.y = 0, 10

보시다시피 일반적으로 display.newImage()나 display.newImageRect()함수를 사용하는것과 크게 다르지 않습니다. 다른 점은 image sheet를 사용할 경우 특정 filename 대신 해당 frame index number를 사용한다는 것입니다.

여러분들이 image sheet를 로딩할 때 simple을 사용했던지 complex를 사용했던지 상관없이 위 예제처럼 사용하시면 됩니다. (old-style을 사용해도 마찬가지 입니다.)

Power of 2 Dimensions

build 2012.264를 보시면 power of 2 에 대한 제한이 있었습니다. 지금은 이 image sheet를 사용하면서 이 제한이 없어졌습니다. 그 제한들은 width와 hight가 8, 16, 32, 64, 128, 256, 512, 1024, 2048 .... 사이즈에 부합되야 한다는 것이었습니다. 하지만 image sheets를 사용하면서 이런 제약은 없어졌습니다. 하지만 texture memory 관리 등을 생각하면 이 power of 2 에 대한 규칙을 지키는 것이 좋습니다.

Removing Image Sheets

image sheet를 remove하려면 image sheet를 사용하는 객체를 그냥 remove 하시면 됩니다. (image objects, sprites, image groups 등) 그리고 나서 image sheet를 nil로 선언하세요.

아래 예제가 있습니다.

-- obj1 and obj2 are using the image sheet
obj1:removeSelf()
obj1 = nil

obj2:removeSelf()
obj2 = nil

-- remove reference to the image sheet
imageSheet = nil


======= o =====  o ====== o ======== o ========

내용이 길어서 2회로 나눠 싣습니다.
다음 글에서는 Image Groups() , Sprites 등에 대해 다룰 겁니다.
반응형


반응형
코로나 SDK에서 안드로이드용 In-App Purchase 관련  API를 내 놨습니다.
이제 아이폰,안드로이드폰 모두에서 코로나로 개발한 In-App Purchase기능을 사용할 수 있게 됐습니다.

아래 이번주에 Corona SDK에서 배포한 안드로이드 In-app Billing 튜토리얼을 정리했습니다.

여러분도 참고하세요.

======o ===== o ===== o ===== o ===== o =====

Getting Started with Android In-app Billing

앱을 통해서 돈을 벌 수 있는 방법은 유료 앱으로 publish를 하던가 광고를 달던가 아니면 가상 머니를 사용하는 방법이 있습니다.
그 외에 in-App Billing이 있는데요. 이번에 Corona SDK에서 안드로이드용 In-App Billing 기능을 발표했습니다.

이 in-App Purchase 기능은 모바일 앱을 이용한 많이 애용되는 비지니스 모델인데요 이것을 다른 말로 freemium 이라고 합니다. freemium은 일단 무료로 제공하고 그 외의 고급 기능이나 아이템을 유료로 구매할 수 있도록 하는 것을 말합니다.
모바일 앱의 경우는 다음 레벨로 가거나 특별한 아이템을 구한다던가 virtual currency를 사용하던가 하는 기능을 넣을 수가 있을 겁니다.

유저가 구매를 approve하면 새로운 컨텐츠가 unlock 되거나 외부 소스로부터 다운로드 되던가 할 겁니다.
이 방법을 사용하면 아주 다양한 방법의 수익 모델을 만들어 낼 수 있습니다. 그리고 이번에 Corona SDK에서 안드로이드 용으로 이 기능을 지원했기 때문에 그 다양한 수익 모델을 Corona SDK로 개발하면서도 사용할 수 있습니다.
아이폰 앱에는 이미 이 기능이 지원됐기 때문에 코로나 개발자들은 두개의 시장에서 이 기능을 이용할 수 있게 되겠죠? 이것이 Corona SDK 같은 cross-platform development tool의 매력이라고 할 수 있을 겁니다.

하지만 이 좋은 기능도 개발자나 기획자가 사용할 줄 모르면 아무 소용이 없을 겁니다. 이 기능을 이용하려면 최신버전의 Corona SDK가 있어야 합니다. (현재는 유료 사용자만이 다운 받을 수 있습니다.)



Getting Started

시작하기 전에 여러분이 준비해 두셔야 할 부분이 있습니다.
1. Corona SDK build 2012.769 이후 버전
2. Indie-AndroidCorona Pro 유료 사용자 일 것
3. Android Developer 계정을 가지고 있을 것

1. Android Deveoper Console
안드로이드 내에서 billing이 가능하게 하려면 BILLING 퍼미션이 build.settings에 세팅 돼 있어야 합니다. 그리고 이것을 Android Developer Console에 없로드해서 당신의 앱이 In-App Billing Products를 시작할 수 있도록 만들어 두어야 합니다.
main.lua에 아무런 코딩이 안 돼 있어도 이 작업을 해야 합니다. 그리고 지금 개발이 진행 중이라도 상관없습니다. 어쨌든 우선 이 step을 밟아야 합니다. 여러분의 앱에 In-app 상품을 넣을 수 있으려면 우선 이 과정을 거쳐야 하는게 구글이 만들어 놓은 룰입니다.
당신의 앱이 이미 판매중이거나 마켓에 오픈돼 있는 상태라도 이 기능을 넣으려면 우선 build.settings에 퍼미션을 넣고 업로드 한 다음에 In-App purchase 기능을 개발해야 합니다.
한번 이렇게 해 두면 Android developer console의 해당 앱 밑에 in-app products라는 링크를 클릭해서 이곳에서 올린 in-app 상품을 보실 수가 있습니다.

build.settings에 BILLING 퍼미션을 넣는 방법은 아래와 같습니다.

settings =
{
    orientation =
    {
        default = "landscapeRight",
    },

    android =
    {
        usesPermissions =
        {
            "com.android.vending.BILLING",
        },
    }
}

이 예제에서 주의깊게 보셔야 할 점은 android - usesPermissions의 com.android.vending.BILLING 부분 입니다.
이 부분은 orientation을 지정한 settings 다음에 위치해 있습니다.
 
이렇게 하신 후에 android 앱으로 build하세요. 그리고 그 apk화일을 android developer console에 업로드 하시면 됩니다.

아직까지는 Publish를 하지는 마세요.

그렇게 한 다음부터 In-app 제품을 넣기 위한 Administering In-app Billing Guide를 진행 하실 수 있습니다.

안드로이드 개발자로서 마켓에 앱을 올려보신 분들은 아시겠지만 앱을 다 개발 한 다음에 publish를 해야하는데요. 요즘은 이것을 또 Activate 하는 단계도 생겼더라구요.
혹시 나중에 앱을 다 만들고 나서 마켓에 올리고 테스트 할 때 주의하세요.

Google Documentation

구글 Guide에 대해서는 위에 링크를 걸어 놓기는 했지만 여기에 대해서는 한번 언급하고 넘어가는게 좋을 것 같습니다.

구글에서는 In-app Products를 어떻게 셋업해야 하는지에 대해 꽤 좋은 가이드를 제공하고 있습니다. 그리고 그것을 쉽게 테스트 할 수 있도록 했구요.
만약 여러분이 Android Developer Console쪽에서 어떻게 세팅해야 하는지를 자세히 알고 싶으시면 아래 두 가이드를 참고하세요.

2. The Corona "store" API

이 튜토리얼에서는 구글에서 제공하는 test product identifier들을 사용하겠습니다.
이 테스트 상품에서는 아래 세가지 Action을 가져올 수 있습니다.

- android.test.purchased : 구매가 성공했을 때 얻어 옴
- android.test.canceled : 구매 트랜잭션이 cancel 됐을 때 얻어 옴
- android.test.item_unavailable : 해당 제품 구매가 가능하지 않을 때 얻어 옴

이 테스트 상품의 진짜 nice 한 점은 이렇게 각각 다른 상황에서 여러분들이 이를 어떻게 쉽게 콘트롤 할 수 있을 지 경험할 수 있게 해 준다는 점 입니다. 예를 들어 여러분은 android.test.canceled 상품을 이용해서 유저가 트랜잭션 중 cancel했을 경우에 대한 코딩을 할 수 있게 됩니다.

store.init("google", transactionCallback)

여러분이 코딩을 하면서 이 in-app purchase 기능을 구현하기 위해서는 제일 처음 store.init() API를 사용하게 될 겁니다. 파라미터로는 구글 마켓(얼마전 Google Play로 바뀌었습니다.)을 사용할 거라는 것을 알리는 "google"을 첫번째로 넣고 두번째로는 불러올 함수 명을 넣습니다.

아래 transaction callback listener 함수와 함께 store.init()을 사용하는 방법에 대한 샘플 예제가 있습니다.

local function transactionCallback( event )
    local transaction = event.transaction

    if transaction.state == "purchased" then
            -- Transaction was successful; unlock/download content now
   
    elseif transaction.state == "restored" then
           -- You'll never reach this transaction state on Android.

    elseif transaction.state == "refunded" then
        -- Android-only; user refunded their purchase
        local productId = transaction.productIdentifier
        -- Restrict/remove content associated with above productId now
  
    elseif transaction.state == "cancelled" then
        -- Transaction was cancelled; tell you app to react accordingly here

    elseif transaction.state == "failed" then
            -- Transaction failed; tell you app to react accordingly here
     end

    -- The following must be called after transaction is complete.
    -- If your In-app product needs to download, do not call the following
    -- function until AFTER the download is complete:

    store.finishTransaction( transaction )
end

store.init( "google", transactionCallback )

맨 아래 store.init()이 transactionCallback 함수를 call 하는 보분이 있죠? 이 부분이 Android In-app Billing 이벤트가 발생 했을 때 실행 될 부분입니다.

Handling Refunds

Android In-app billing은 iOS의 In-app billing과 거의 같은데 한가지 refunded라는 트랜잭션 상태가 더 있습니다. iOS와는 다르게 안드로이드 플랫폼에서는 유저가 refund할 수 있도록 해 줍니다. 그래서 유저에게 주었던 contents를 다시 가져오려면 바로 이 refunded 트랜잭션 상태일 때 해야 할 것입니다.

위 샘플에서 보듯이 refunded 트랜잭션 상태에서 받는 중요한 데이터는 event.transaction.productIdentifier입니다. 이 정보를 가지고 여러분은 필요한 작업을 하실 수 있습니다. 아마도 그 필요한 작업은 환불 했을 경우 해당 content를 다시 block 시키는 거겠죠? 아니면 돈을 내고 추가로 다운 받은 파일을 지우는 기능이던가요.

No "restored" State on Android

store.restore() 함수는 로그인 된 유저 계정과 연관된 product id의 리스트를 다시 검색할 수 있도록 해 줍니다. iOS에서는 이 product 리스팅이 transactionCallback listener 의 restored 트랜잭션 상태에서 받을 수 있습니다. 그리고 안드로이드에서는 이 restored 트랜잭션 상태가 없습니다. 대신에 그 상품이 purchased를 다시 실행하면서 그 기능을 할 수 있습니다.
아주 작은 차이이지만 transactionCallback listener 함수를 디자인할 때 잘 고려해서 디자인을 해야 합니다.

Other Transacton Event Data

transaction events와 관계된 다른 모든 데이터들은 iOS의 In-app purchase와 동일합니다. 그러니까 다음 guide를 꼭 봐 주세요.
In-app  Purchase Guide
Transaction Listener Callback Events
그리고 예전에 in-Purchase app 샘플을 분석했던 글을 보시면 도움이 되실겁니다.
코로나 네트워킹 과 웹 서비스 3 (In App Purchase 1)

store.finishTransaction (transaction)

위 샘플 코드에 있는 transactionCallback() 함수에 있는 모두 아주 중요한 것들입니다.
store.finishTransaction은 모든 트랜잭션의 마지막부분에 반드시 call 되야 합니다.
어떤 트랜잭션이 끝났다는 것을 확실히 정의하는 부분입니다.
만약 어떤 파일을 다운로드 받아야 할 때는  어떤 상황이 발생할 까요? 아마도 이 다운로드가 모드 끝나고 나서 store.finishTransaction()이 call 되어야 할 겁니다. (그러려면 어딘가에 network.download() 리스너가 있어야 겠죠.)

만약 이미 코딩은 최초 다운받은 앱에 다 돼 있고 단순히 어떤 content를 unlock 하는 기능만 수행될거면 callback 리스너 마지막 부분에 store.finishTransaction()을 넣으면 되겠죠.

두 경우 모두 첫번째 인수로 event.transaction 테이블을 넘겨줘야 한다는 것을 잊지 마세요.
 store.finishTransaction( event.transaction )

3. Purchasing Products

이제 purchases, refunds, failed/cancelled 같은 트랜잭션들을 어떻게 다뤄야 할 지 알아 보겠습니다. iOS in-app purchase에서와 같이 store.purchase()를 사용해서 트랜잭션을 초기화 합니다. 대개 앱 화면에서 Buy 버튼을 누르면 이벤트 리스너가 감지해서 call할 때 이 동작이 이뤄 집니다.
-- single product purchase
    store.purchase( { "android.test.purchased" } )

-- multi-item purchase
   store.purchase( { "android.test.purchased", "android.test.canceled" } )

여기서도 Google에서 제공하는 테스트 product들을 사용해서 테스트 해 볼 수 있습니다.
좀 더 자세한 정보를 보시려면 store.purchase() documentation 을 참고하세요.

Cross-Platform Development

코로나의 장점은 한번의 코딩으로  아이폰, 안드로이드 용 앱을 만들 수 있는 multi-platform 기능입니다. 이 기능을 좀 더 쉽게 콘트롤 할 수 있도록 코로나에서는 store API에 새로운 프로퍼티를 추가했습니다.
애플의 In-app Purchase는 iOS 디바이스들에서만 가능하고 안드로이드의 In-app Billing은 Google Play에서만 가능합니다. (같은 안드로이드 앱이라도 Nook나 Kindle Fire 에서는 In-app Billing을 사용할 수 없습니다.)
새로 제공되는 기능은 store.availableStores 테이블로 어떤 디바이스 인지를 알수 있는 파라미터 입니다.

아래 예제가 있습니다.

if store.availableStores.apple then
    store.init("apple", transactionCallback)
   
elseif store.availableStores.google then
    store.init("google", transactionCallback)
end

이렇게 코딩을 하면 아이폰용과 안드로이드 용 파일을 따로 관리할 필요가 없겠죠?

iOS의 In-app Purchases와 Android의 In-app Billing은 한가지 크게 다른 개념이 있습니다. 안드로이드에서는 각각의 In-App product들에 대해 정보를 retrieve할 수 없는 반면에 iOS에서는 이 기능이 가능합니다. 이것은 구글의 한계라고 볼 수 있겠죠. 이 의미는 상품의 이름, description같은 정보들을 직접 앱 내에서 혹은 외부 서버에서 개발자들이 직접 관리해야 한다는 얘기 입니다. (만약에 필요하다면요.)

이 다른 점 때문에 store.loadProducts() 함수가 있는데 이것은 iOS in-app purchases에서만 사용될 수 있습니다. 여러분이 iOS,안드로이드 두 플랫폼 모두에서 돌아가는 앱을 개발하고자 한다면 이 함수가 가능한지 여부를 체크하기 위해서 store.canLoadProducts 프로퍼티를 사용하실 수 있습니다. (store.init()에서 pass된 플랫폼이 무엇인가에 따라 true와 false를 return 하게 됩니다.)

 Additional Resources

Android In-app Billing 을 테스트 하시려면 구글에서 제공하는 테스트 상품으로 쉽게 테스트하실 수 있구요. 또 여러분이 만든 상품으로도 쉽게 테스트 하실 수 있습니다. 이번에 새로 제공되는 Corona SDK 내의 InAppPurchase 샘플 코드를 참조하세요.
/SampleCode/Networking/InAppPurchase 에 있습니다.

그리고 예전에 iOS in-app purchase와 관련해서 올려 놓은 In-app Purchase Guide도 보시구요. iOS용 가이드 이지만 대부분이 안드로이드에서도 적용 됩니다. 그리고 각각의 store API 함수에 대한 정보를 보시려면 In-app Purchase API Reference를 보시기를 권장합니다.

이 기능은 Corona Daily Build 2012.760 이후 버전에서만 가능합니다.
현재까지 이 버전은 유료 사용자만 받으실 수 있습니다.

======o ===== o ===== o ===== o ===== o =====

요즘 예전처럼 폭풍집필이 잘 안되네요.
슬럼프인가봐요.. 휴~~~~~~~
여러분의 추천이 큰 힘이 될 수 있을 것 같아요.
추천 부탁드려요.

추천.. 추천.. ~~~ ~~~ 감사.. 감사..
반응형


반응형

요즘 사무실 이사에 이런 저런 일들이 많이 생겨서 블로그 글 올리는 일이 뜸해졌습니다.

어느 정도 일이 정리 되면 다시 열심히 Study 해서 이 블로그에 정리 해 놓을께요. 그리고 댓글 올리신 분들도 많이 계신데 미처 답글을 드리지 못했습니다. 이번주에 질문 올리신 분들 제가 research 하고 직접 테스트 한 답을 구해서 답글 올릴께요.

오늘은 코로나에서 새로 나올 Corona Level Editor 에 대한 아이콘 콘테스트가 있어서 이 소식을 소개합니다.

아래 글은 Corona sdk를 만든 회사인 Ansca 의 CEO 인 Carlos 가 올린 글입니다.


===== o ===== o ===== o ===== o =====

Corona Level Editor Icon Challenge

Should I really explain what this is about?

이게 뭔지 일일이 설명해야 할 까요?

You seen our forthcoming level editor. Well… Guess what? Time to unleash the artist in you and we are going to hold the Level Editor Icon Challenge.

여러분 아마 조만간 나올 level editor를 보셨을 겁니다. 이제 뭔지 아시겠어요. 이제 여러분 몸속에 흐르는 예술인의 피를 맘껏 펼치실 때입니다. 코로나에서는 Level Editor 아이콘 콘테스트를 엽니다.

Submit a Corona Level Editor Icon by April 2nd. (See, if I would have put down April 1st, the US folks here would have thought this would have been an April’s Fools Joke. O el dia de los inoncentes)… Send me a PNG file at least 512×512 and then I will need the full PSD if we select your icon. (AI files works wonders too…)

코로나 레벨 에디터 아이콘을 4월 2일까지 응모해 주세요. (아마 내가 4월 1일이라고 얘기하면 여기 미국 애들은 이게 만우절 거짓말이라고 생각할 수도 있을거예요. 그래서 4월 2일로 했습니다.  O el dia de los inoncentes) 최소 512X512 크기의 PNG 파일로 보내주세요. 선택되면 PSD 원본을 제출해 주셔야 합니다. (모두 다 제대로 동작해야 겠죠?)

And, because I want to keep his a surprise, the only way you can enter is by e-mailing me your entries at my email address at  cicaza [at]@ anscamobile []dot[]. com. (protecting myself from spammers.)… (remove the [at] and the []dot[])

응모 방법은 cicaza [at]@ anscamobile []dot[]. com. (스팸 방지를 위해서 이렇게 쓴 겁니다. )... (여기서 [at] 하고 []dot[]을 빼시면 되요.)

Winner will get a free one year subscription to Corona PRO and or an extension to their subscription and some other Ansca goodies. ;=)

우승자는 Corona PRO 1년 사용권을 드립니다. 기존 사용자에게는 1년 연장해 드리구요. 그리고 다른 Ansca 제품들도 조금 더 준비 돼 있습니다.

The winning entry will have to give us all rights to the image. No prior/derivative or copies of images are to be entered. Once we select a winning entry I will notify you via email and then disclose publicly.

우승작품은 모든 사용 권한이 Ansca 에게 있게 됩니다. 다른 곳에 응모했거나 남의 작품을 보내주시면 안되구요. 당선작은 이메일로 알려드리고 또 공개도 할 겁니다.

Thanks

Carlos.

===== o ===== o ===== o ===== o =====

이상입니다.

아마 코로나 레벨 에디터에 대해 전혀 모르시는 분 계실테죠?

아래 이미지가 앞으로 나올 Corona Level Editor 화면이랍니다.

그림을 보니까 단순히 Level별 난이도를 조절하는게 아니라 Physics 적용이나 화면 배치 등 GUI 방식으로 어느정도 개발을 쉽게 해 주는 기능이 많은 것 같습니다.

지난번에 Corona sdk 책 표지 광고 디자인 응모전에서는 제 기억에 폴란드 사람이 우승하고 미국사람하고 멕시코 사람이 준우승해서 상품을 받은 것 같은데요.

이번엔 한국 분이 받으면 좋겠네요.

그래픽 디자인 가능하신 분 응모 하세요.

반응형


반응형
Corona SDK에서 명예 홍보 대사 임명됐다는 메일을 담당자로부터 그냥 개인적으로 들었는데 오늘 공식적으로 임명 됐다는 메일이 왔어요. :)
원래는 한달 쯤 전에 공식 발표 될 거라고 했는데... 이것 저것 준비 하다가 늦어졌다고 하네요.

아래가 메일 중 일 부분이예요.

======== o ========= o ========= o ========= o ========= o

Dear Corona Ambassador,
코로나 대사 귀하

Welcome to the Corona Ambassador Program! You are part of our very first batch of 42 Corona Ambassadors! We have members from all over the world, from San Jose to Sydney.

코로나 대사 프로그램에 오신것을 환영합니다. 당신은 첫번째 Corona 대사로 임명된 42명중 한명입니다. 코로나 대사는 산호세부터 시드니까지 전 세계에 걸쳐 있습니다.

Thank you for joining and for bearing with us while we rolled this out. It has taken us longer than we'd like, but we've been very busy. As you know, we are seeing more and more activity around Corona every single day and there are many things to do.

이렇게 참여해 주시고 우리가 이 일을 다 처리할 때까지 기다려 주셔서 감사합니다. 당초 예상보다 늦어졌습니다. 아주 바빴거든요. 아시다시피 매일매일 코로나 관련 여러 활동들이 있었고 많은 처리 해야 할 일들이 있었습니다.

In any case, we are excited to be officially starting the program. As I mentioned to you when we spoke, our goals are to spread the word about Corona SDK, develop closer relationships with you, our top developers, and to help you achieve your goals - from just meeting other Corona developers to discussing app ideas to growing your businesses.

어쨌든 이렇게 공식적으로 코로나 대사 프로그램을 시작할 수 있어서 매우 기쁩니다. 당초 말씀 드렸듯이 우리의 목표는 Corona SDK를 전 세계에 홍보하는 것이고 개발자들과 대사간의 긴밀한 관계를 맺도록 하는 것입니다. 이러한 목표를 달성하기 위해서 우리 코로나의 top 개발자들이 당신을 도울 겁니다. 단순한 코로나 개발자들의 모임에서부터 코로나를 사용하는 분들의 비지니스 성장을 위한 앱 아이디어관련 토론 등 여러 분야에서 도움을 드릴겁니다.

------------------

In exchange, we'd like to work with you to organize events/meetups in your area every 30 to 60 days - we'll help promote these events and cover costs. 
Also, feel free to send me any comments/ideas/questions you may have. We are open to anything that will help grow this program and spread the word about Corona.

이를 위해 여러분도 30일에서 60일에 한번은 코로나 관련한 이벤트나 모임을 만드시기를 부탁드립니다. 이 이벤트와 비용에 대해 일정 부분 도움을 드리겠습니다.
그리고 어떤 코멘트,아이디어, 질문 이라도 좋으니 많은 의견 보내 주세요. 이 프로그램이 좀 더 활성화 될 수 있고 Corona가 전 세계에 좀 더 많이 퍼질 수 있다면 어떤 의견이라도 받아들이겠습니다.

--------------------

Thanks again and I'm looking forward to working with all of you!
다시 한번 감사드리며 여러분과 같이 일하게 돼 기쁘다는 말씀 전해 드립니다.

David

======== o ========= o ========= o ========= o ========= o

이렇게 공식적으로 대사 임명 메일을 받으니 아주 기분이 좋네요.

코로나에서는 대사가 진행하는 모임의 의견이나 질문을 듣는 공식적인 루트를 마련해 준다고 했습니다.

그러니 여러분이 개발하시면서 아니면 다른 코로나 관련한 질문이 있으시면 제가 정리해서 질문을 할 수 도 있습니다. 그러면 좀 더 성의있고 빠른 답변을 받을 수 있을 것으로 기대합니다.

제대로 코로나 SDK 개발자 모임을 만들려고 합니다.

혹시 Tistory에서 특정 메뉴를 membership으로 운영하는 방법이 있는지 모르겠습니다.
아니면 카페를 만들어야 하는지.. 그리고 제가 미국에 있어서 Online 모임을 할 수 있는 방법이 무엇이 있는지 등등에 대해 여러분의 조언을 바랍니다.

membership이 완성이 되면 따로 online모임을 할 수도 있고 서울이나 지방 아니면 여기 뉴저지나 뉴욕에 사는 멤버들끼리 모임을 유도할 수도 있을 것 같구요.

물론 그 모임에 어떤 지원을 할 수 있을지 제가 코로나 측에 알아봐서 지원을 해 드릴 수도 있습니다.

혹시 member가 되시고 싶은 분 여기 댓글에 남겨 주세요. 그리고 모임을 구성할 정도가 되면 어떻게 모임을 이끌어 나가면 좋을지에 대한 의견 있으시면 올려주시면 아주 도움이 많이 되겠습니다.

저도 많이 고민해 보겠습니다.

같이 코로나 SDK 개발의 전문가가 되고 싶으신 분 여기여기 모이세요. ~~~~~~~



~~~~~~~~~~
반응형

Corona Display Groups 101

2012. 3. 1. 22:03 | Posted by 솔웅


반응형
이번주 코로나에서 제공하는 튜토리얼은 Display Group에 대한 겁니다.

기본 API는 여기에 있습니다.
group.numChildren, group:insert(), group:remove() 세가지 요소들이 있습니다.
group.nemChildren은 해당 그룹에 있는 객체들의 숫자를 알 수 있는 메소드 입니다.
주로 그룹 내 모든 객체들에 어떤 변경이나 효과를 줄 때 for 문에서 이용하게 됩니다.
group:insert()는 새로운 객체를 해당 그룹에 추가할 때 사용하구요.
기본은 맨 마지막에 삽입 되는데 원하면 삽입되는 위치도 지정해 줄 수 있습니다.
그리고 group:remove()는 그 그룹에서 특정 객체를 제거할 때 사용합니다.

그룹을 처음 만들 때는 display.newGroup()을 사용하구요.
여기를 클릭하시면 이와 관련되서 정리한 문서를 보실 수 있습니다.

오늘 다룰 튜토리얼의 원본은 여기 있습니다.
이 원본을 정리해 두겠습니다.

======= o ======= o ======= o ======= o ======= o ======= o

Corona Display Groups 101



이번주 다룰 주제는 모든 개발자들이 가장 자주 접하는 코로나 프로그래밍에서 아주 기본이 되는 group에 관련 해서 다루겠습니다. 이 group을 자주 사용했던 개발자 분들에게도 아무 도움이 되는 내용일 겁니다.

What are Groups?

코로나에서 화면에 나오는 모든 객체들은 display object 입니다. 이 display object에는 세가지 유형이 있습니다.
- Vectors (Shapes & Text)
- Images (익히 알려져 있는 "normal" display objects)
- Groups

코로나 display group(이후 부터는 group으로 하겠습니다.)은 좌표(x,y), 투명도, 회전값 등의 여러 property들과 메소드들을 가지고 있습니다. 이는 이 object를 control 하는데 아주 편리한 기능을 제공해 줍니다.

Object Grouping

group의 목적은 다른 object 들을 하나로 묶는 것입니다. 그래서 여러개의 object들을 하나의 object 처럼 다룰 수 있도록 해 줍니다. 이 기능은 프로그래밍 할 때 손쉽게 여러 object들을 제어할 수 있게 도와줘서 편리하기도 하지만 반면에 불편한 점도 있습니다.
여러분들이 어떤 display object를 group에 넣고 이 그룹의 property들을 변경하더라도 그 그룹 안에 있는 개별 object들의 property들은 변경되지 않습니다. 다만 group의 property에 따라서 display 될 뿐입니다.
이 group이 또 다른 group에 포합 될 수도 있고 그 group이 또 다른 group에 포함될 수도 있습니다. 이 경우에도 group의 프로퍼티와 그룹 내 object의 프로퍼티의 관계는 위와 같습니다.
이런식으로 group의 포함관계가 많이 될 수록 이 그룹과 그 안의 요소들을 콘트롤 하는게 만만치 않습니다.

하나 예를 들어보죠.

A와 B 라는 그룹이 있습니다. 그리고 보통 display object인 C 가 있습니다. 모두 위치는 0,0 입니다. C가 B에 insert 됐습니다. B는 다시 A에 insert 됐습니다. 그러면 이제 A의 x를 100으로 바꾸고 B의 x를 50으로 바꾸겠습니다. C의 좌표는 여전히 0,0입니다. 하지만 이 C가 실제로 화면에 표시 될 때는 150,0 의 위치에 표시 됩니다. 왜 그럴까요? 왜냐하면 그 parent인 B의 x 값이 50이고 또 B의 parent인 A의 x 값이 100이기 때문입니다.

약간 혼란스럽기는 하지만 실제 프로그래밍할 때는 그렇게 크게 문제가 되지는 않죠? 그냥 group별로 display 되면 되니까요.  하지만 touch 리스너에 따라 그룹 내의 특정 object를 움직이거나 회전시키거나 크기를 변화시킬 때는 약간 혼란 스러울 수가 있습니다. 만약 여러분의 parent group들의 값이 변경 됐을 때 그 children들에 어떻게 영향을 미치는지 자세히 알고 있다면 이런 경우 문제없이 프로그래밍을 하실 수 있을 겁니다.

Group Methods

Group에는 insert와 remove라는 두개의 메소드가 있습니다.

group:insert( [index,], child, [, resetTransform] )

이 메소드는 group에 display object 를 insert 할 때 사용됩니다. 이 함수에는 한개의 필수 parameter가 있고 두개의 옵션 파라미터들이 있습니다.

아래 예제는 이 insert  함수를 어떻게 사용하는지에 대해 보여줍니다. 주석을 잘 보시면 그룹의 프로퍼티들이 바뀔 때 그 안의 child는 어떤 영향을 받는지 잘 설명돼 있습니다.

-- 이미지 객체를 생성한다. 객체의 이름은 object1이고 위치는 50,50이다.
local object1 = display.newImage( "image.png" )
object1.x, object1.y = 50, 50
-- display group을 생성한다. 그룹의 이름은 group1이다.
local group1 = display.newGroup()
-- 그룹의 위치를 100,100으로 한다.
group1.x, group1.y = 100, 100
-- 이미지 객체를 그룹에 insert 한다.
group1:insert( object1 )
-- 이미지 객체의 위치는 50,50이지만 화면에 나타날 때는 150,150 위치에
나타난다.
-- group1에 insert 돼 있기 때문에 group의 위치인 100,100이 더해
지기 때문이다.

디폴트로 insert된 객체는 그 그룹의 top 에 위치 됩니다
디폴트로 insert된 객체를 그 그룹의 top에 위치 됩니다. 하지만 옵션 파라미터인 첫번째 argument인 index 번호를 바꿈으로서 해달 객체의 순서를 지정할 수 있습니다.
이 때 index번호 1은 가장 하위를 가리킵니다. 새로운 객체를 1로 지정하면 이전의 객체들은 하나씩 위로 올라갑니다. 다른 위치에 insert해도 그 상위의 객체들은 하나씩 위로 올라가게 됩니다.

예를 들어서 그룹에 4개의 객체들이 있는데 여러분이 새 객체를 index 위치 2로 지정하면 새 객체를 그룹내의 두번째 객체가 되고 기존의 2,3,4번째 객체들은 3,4,5번째 객체들로 바뀌게 됩니다.

만약에 새 객체를 그 그룹 안에 있는 객체수 보다 더 큰 수의 index 위치로 지정하게 되면 코로나는 그냥 default 로 처리해서 top에 위치시킵니다.

그 외에 optional parameter로 resetTransform이 있습니다. 만약에 여러분이 객체들의 위치, 회전, 투명도, 크기 등을 그룹에 insert 할 때 디폴트값으로 재 세팅하기를 원하신다면 이것은 true로 세팅 돼 있어야 합니다. 즉 그 객체가 가지고 있는 기본 값(위치, 회전, 투명도 등)은 적용되지 않고 오직 group의 값만 적용 되게 됩니다. resetTransform의 디폴트 값은 false입니다.

IMPORTANT NOTE

하나의 객체는 한 그룹 내에만 소속될 수 있습니다. 그렇기 때문에 객체를 group A에 insert 한 후 다시 group B에 insert 하면 이 객체는 A의 그룹에서는 자동으로 해제 되게 됩니다.
참고로 코로나의 display stage도 하나의 display group입니다. 그렇기 때문에 display object나 그룹이 생성되면 자동적으로 이 stage 그룹에 포함 되게 됩니다.
그렇기 때문에 한 객체가 다른 그룹에 insert 되면 그 객체는 더이상 stage에 소속 돼 있지 않겠죠. 하지만 그 그룹의 stage에 소속돼 있으니까 화면에 display하는데는 문제 없을 거예요.

group:remove( indexOrChild )

이 메소드는 그룹 내에 있는 특정 객체를 remove 하기 위해 사용 됩니다. removeSelf()나 display.remove() 와 개념이 유사합니다. 괄호 안에는 객체 이름이나 그 객체의 index 번호를 넣으면 됩니다.
어떤 display object를 remove 할 때 그 객체를 nil 로 만드는 것을 잊지 마세요. 효율적으로 메모리를 사용하는데 중요한 사항입니다.

Group Properties

group도 display object이기 때문에 이 그룹도 일반 display object들이 가지는 일반적인 메소드나 프로퍼티들을 가지고 있습니다. 그리고 numChildren이라는 프로퍼티를 덤으로 가지고 있구요.
이 numChildren은 그룹 내에 몇개의 객체들이 있는지 쉽게 알수 있게 해 줍니다. 이 프로퍼티는 for문등 루프를 돌릴 때 주로 사용 됩니다.
아래 예제는 그룹내의 모든 object들에 대해 어떤 값을 변경하기 위해 루핑 하는 방법을 보여줍니다.
-- This example assumes you have already inserted
-- several objects into the 'group2' display group. -- forward iteration
for i=1,group2.numChildren do
  local child = group2[i]   child.score = child.score + 1
end
-- backwards iteration; useful for removing objects manually
for i=group2.numChildren,1,-1 do
  local child = group2[i]   totalScore = totalScore + child.score
  child:removeSelf()
end
Property Differences

Group과 일반 이미지 객체와 몇가지 다른 점이 있습니다.
가장 중요한 다른 점은 default reference point가 다르다는 겁니다. 그룹은 display.TopLeftReferencePoint가 디폴트이고 다른 display object는 display.CenterReferencePoint가 디폴트입니다.
그 다음은 contentWidth와 contentHeight인데 당연히 group은 자체적으로 어떤 모양이 없기 때문에 고정된 width와 height가 없습니다. 그 child 중에 가장 큰 object의 값을 가질 겁니다.

Wrap-Up and Further Reading

지금까지 정리한 내용만 충분히 이해하면 코로나 Display Group에 대해서는 전문가가 되신 겁니다.
이번 튜토리얼은 basic 내용이긴 하지만 기본에 충실한 것이 좋은 앱을 만드는 바탕이 됩니다.

~~~~~~~~~~
반응형