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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
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 를 추천하고 있습니다.
필요하신 분 잘 활용하세요..
저도 필요하긴 합니다.
요즘 시간적인 여유가 좀 생겨서 개인 프로젝트를 시작하려고 하는데요.
그래픽 부분이 부담 되서....
하여간 새로운 기술들을 잘 활용해서 개성있는 앱을 하나 만들어 보려고 합니다.
반응형