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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
Emanuele Feronato의 블로그를 알게되서 가끔 들어가 보는데 아주 훌륭한 로직들을 많이 share하고 있네요.

눈내리는 효과, 물방울 올라가는 효과 두가지를 분석해 봤는데요.
여기 뱀 기어다니는 효과가 재밌어서 제 블로그에 정리해 둘까 합니다.
Emanuele는 String Avoider라고 이름을 붙였는데요. 제 눈에는 뱀 기어다니는걸로 보이더라구요.

아래 유튜브에도 올려놨는데 아주 간단한 코드로 이런 효과를 주고 있습니다.


아래 소스가 있습니다.

-- Declaring Variables
-- Stage Width and Height
local _W,_H = display.contentWidth,display.contentHeight
 
local tailLength = 5
local tailNodes = 200
local head = display.newCircle(_W/2,_H/2,10)
local nodes = {}
 
for i=1,tailNodes,1 do
    nodes[i] = {}
    nodes[i].x = head.x
    nodes[i].y = head.y
end
 
-- Creating Display Groups
local tailGroup = display.newGroup()
 
local function startDrag(event)
    -- Store the Target (the Head) in a variable
    local t = event.target
    if event.phase == "began" then
        -- When the touch started, set the Focus on the Head
        display.getCurrentStage():setFocus( t )
        t.isFocus = true
        -- Store initial Position of the Head
        t.x0 = event.x - t.x
            t.y0 = event.y - t.y
    elseif t.isFocus then
        if event.phase == "moved" then
            -- While moving the head
            -- remove every drawn line from the group
            for i=tailGroup.numChildren,1,-1 do
                tailGroup:remove(i)
            end
 
            -- Move the Head
            t.x = event.x - t.x0
            t.y = event.y - t.y0
 
            -- Create starting line and insert it into the group
            local line = display.newLine(head.x,head.y,nodes[1].x,nodes[1].y)
            tailGroup:insert(line)
            line.width = 20
 
            nodes[1].x = head.x
            nodes[1].y = head.y
 
            -- Loop through every tailNode and save new positions in table
            -- Note: LUA tables start with an index of 1 and not 0!
            for i=2,tailNodes,1 do
                local nodeAngle = math.atan2(nodes[i].y-nodes[i-1].y,nodes[i].x-nodes[i-1].x);
                nodes[i].x = nodes[i-1].x+tailLength*math.cos(nodeAngle)
                nodes[i].y = nodes[i-1].y+tailLength*math.sin(nodeAngle)
 
                -- You could use
                -- line:append(nodes[i].x,nodes[i].y)
                -- but this wouldn't allow you to alter each segment (fading the color, reducing linewidth etc.)
 
                -- Creating new line segments
                local nLine = display.newLine(nodes[i-1].x,nodes[i-1].y,nodes[i].x,nodes[i].y)
                -- c will store the colorvalue - starting from 255 and ending with 0 (white to black)
                local c = 255-i/tailNodes*255
                nLine:setColor(c)
                -- width will start at 20 and fade out to 0
                nLine.width = line.width-i/tailNodes*line.width
 
                -- Important: insert the new Line segments into the table!
                tailGroup:insert(nLine)
            end
        elseif event.phase == "ended" or event.phase == "cancelled" then
            -- Remove the focus
            display.getCurrentStage():setFocus( t, nil )
            t.isFocus = false
        end
    end
end
 
-- Create touch Eventlistener
head:addEventListener("touch",startDrag)

한번 분석해 볼까요?

첫줄은 모바일 기기의 가로 세로 길이를 변수에 담았구요.
tailLength와 tailNodes 변수에 숫자를 대입했습니다.
그리고 head라는 변수에 원을 그려 넣었구요. nodes 라는 테이블 변수를 만들었습니다.

다음 for 문에서는 tailNodes 값 만큼 nodes에 head를 넣습니다. 총 200개가 되겠죠?
nodes 테이블에는 작은 원 200개가 들어있습니다. 이걸 가지고 효과를 만들겁니다.

다음에는 Display Group을 만들었습니다. tailGroup이라는 이름으로요.

그 다음으로는 맨 밑에 있는 리스너를 보죠.
head에 touch 리스너를 달았네요. 맨 처음 그려진 head에 Listener가 달립니다.
이 head를 touch 하면 startDrag함수가 실행되구요. 그러면 began, moved, ended phases 에 따라서 Control 할 수가 있습니다.

이제 startDrag 함수를 분석해 보죠.
처음 변수 t를 만들고 여기에 event.target 즉 head 를 넣습니다.
이제 control을 해 보죠.
began 단계에서는 t에 setFocus를 합니다.
setFocus는 해당 리스너에 Focus를 둔다는 의미인데요. 제 블로그에서 setFocus로 검색하시면 관련 글이 뜰 겁니다. 참고 하세요.
그리고 t.x0 에는 현재 이벤트가 일어나는 x포인트에서 t(head)의 x포인트를 뺀 값을 넣습니다. t.y0에도 현재 이벤트가 일어나는 y포인트에서 t의 y포인트를 뺀 값을 넣구요.
began에서는 여기까지 하구요. t.isFocus가 계속 유지되고 있으면 moved 일 때 로직을 실행합니다.
moved에서 처음 하는 일은 tailGroup의 모든 구성요소들을 지우는 겁니다. 이전 이미지가 그대로 남아 있으면 움직이는 효과가 아니라 선이 그려지는 효과가 날겁니다.

이 지우는 기능을 빼면 이런 효과가 납니다. 한번 해 보셔도 재밌을 거예요. 이 로직도 잘 이용하면 좋은 효과를 낼 수 있겠는데요.

그리고  t.x와 t.y를 이벤트가 일어난 좌표에서 began에서 구했던 t.x0와 t.y0를 뺀 값을 넣습니다. 그러면 head가 움직이게 됩니다.

그리고 head의 x,y좌표에서 그 다음 node에 선을 긋습니다. (뱀의 몸이 이어지도록 보이겠죠?)
그리고 이 라인을 그룹에 insert하구요. 그 width를 20으로 설정합니다.
그리고 이 node 1을 head 위치로 옮깁니다.

다음에는 for문을 돌려서 모든 tailNode를 새로운 위치로 옮겨서 뱀 몸체가 기어가는 효과가 나도록 합니다.
우선 현재의 node와 이전 node 사이의 각도를 구해서 nodeAngle에 넣습니다.
두 점의 좌표를 가지고 각도를 구하는 공식은 math.atan2(y,x) 함수를 이용하시면 됩니다.
그리고 이 각도를 이용해서 각 node의 x,y좌표값을 얻습니다.
x는 math.cos(x) 함수를 이용하시고 y는 math.sin(x)를 이용하시면 됩니다.

이제 뱀 머리를 움직이면 이전 이미지들은 지워지고 이전 node 이미지들이 계속 따라오면서 움직이는 효과가 날 겁니다.

그런데 아직까지는 짧은 선이 계속 따라 올 거구요. 긴 뱀 꼬리가 따라오도록 하는 건 아래 로직에서 처리 해 줍니다.

아까는 head와 첫번째 node사이에 line을 그려 줬는데요. 이제는 node와 node들 사이에 라인을 그려 줍니다.
그리고 나서 색이 점점 검은색에 가까와 지도록 계산을 해서 이 새 라인의 색을 set 해 줍니다.
그러면 꼬리로 갈 수록 점점 색이 여리게 나올 겁니다.

여기까지 하면 이런 효과가 납니다.
아직 width를 설정해 주지 않아서 그렇습니다.
이 모양은 정자가 움직이는 모양 같네요.

이 node들 사이의 line의 두께는 뒤로 갈 수록 점점 줄어들도록 하는 공식을 넣습니다.
그리고 이 라인을 tailGroup에 insert합니다.

여기까지 하면 모든 움직이는 로직은 완료 됩니다.
마지막으로 유저가 손을 떼어서 이벤트가 완료 되면 setFocus를 해제합니다.

이러면 저 위에 유튜브 영상에서 보는 것처럼 뱀이 기어다니는 효과를 주실 수 있습니다.

이 소스에서는 math 함수 3개에 대해서 익숙해 지도록 연습하라고 권해 드리고 싶네요.
그러면 정말 아주 다양한 효과들을 낼 수 있습니다.
즐코딩 하시구요. ~~~~ ~~~~ 추천 추천 부탁 드려요...
반응형


반응형
오늘은 config.lua에서 세팅하는 imageSuffix에 대해 알아보겠습니다.

스마트폰은 종류가 아주 다양하고 해상도도 여러가지 입니다. 여기에 iPad나 Galaxy Tab 과 같은 태블릿도 종류가 많아서 어느 한 해상도에 맞추다보면 다른 디바이스에서는 이미지가 깔끔하게 안 나오는데요.

해상도에 맞는 이미지가 출력되도록 하는 방법중의 하나인 imageSuffix 사용하는 방법에 대해 알아보겠습니다.

이 글의 원본은 여기 가시면 보실 수 있습니다.
지난번 물방울 올라가는 효과도 이 친구가 개발해서 공유한 소스입니다.
Emanuele Feronato 인데요.
이 웹사이트에 가면 어도비(Adobe)의 플래시(Flash)나 포토샵 (PhotoShop), 워드프레스, PHP 같은 툴에 대한 좋은 정보도 있으니까 참조하시면 좋을 거예요.
그리고 고맙게 자신의 노력을 공유하는 우리 Emanuele에게 고맙다는 댓글도 달아 주시면 좋겠죠?


이번 앱은 위 두 이미지 가지고 작업을 할 건데요.
왼쪽 이미지는 iPhone에 맞는 480*320 크기이구요 오른쪽 이미지는 iPhone4에 맞는 960*640 입니다. 해상도 크기가 가로 세로 딱 두배 입니다.

여러분은 여러분들 나름대로 이미지를 사용하셔도 됩니다. 이미지 사이즈만 두개로 맞게 해 놓으면 되겠죠?
이 예제에서 왼쪽 이미지는 splash.png 입니다. 그리고 오른쪽 이미지는 splash_hd.png 입니다.
여기서 중요한 것은 큰 이미지는 뒤에 _hd가 붙었다는 겁니다.
여러분도 이미지 이름은 마음대로 하셔도 되지만 뒤에 _hd를 붙이셔야 합니다.
(아니면 다른 글자를 붙이셔야 하는데 나중에 config.lua 파일에서 이 부분을 수정하셔야 합니다.)

이제 build.settings, config.lua, main.lua를 만들어 볼까요?

settings =
{
    orientation =
    {
        default = "landscapeRight",
    },
}
위 파일은 build.settings 파일입니다.
앱 방향을 가로로 설정했네요.

다음은 config.lua인데요. 이 부분이 핵심입니다.
application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = "letterbox",
        imageSuffix =
        {
            ["_hd"] = 2,
        },
    },
}

해상도의 기본 설정은 iPhone  해상도인 320*480으로 설정했습니다.
그리고 scale은 letterbox로 했구요.

예전에도 다룬바 있는데 scale은 dynamic 하게 이미지를 해상도에 맞도록 바꿔주는 기능입니다.
none,letterbox,zoomEven, zoomStretch 네가지 종류가 있습니다.

letterbox는 이미지를 해상도에 맞게 늘려줍니다. 이미지 가로 세로 비율이 깨지지 않도록요. 만약 가로 세로 해상도 비율이 다르면 까만 배경이 나오는 부분이 있습니다. TV에서 영화를 영화 화면 비율로 상영할 때 처럼 말이죠.

zoomEven 은 이미지를 그냥 확대합니다. 때에 따라서 어떤 이미지는 화면 밖으로 나갈 수도 있습니다.

zoomStretch는 화면안에 모든 이미지가 들어오게 만들면서 화면을 꽉 채웁니다. 이렇게 되면 이미지의 가로 세로 비율이 달라져서 약간 이그러져 보이겠죠?

이 scale을 한 후 오늘 하려고 하는 imageSuffix를 코딩합니다.
위 코드의 의미는 해상도가 2배이면 이미지 이름 끝에 _hd가 붙은 이미지를 사용하라는 뜻입니다.

아래는 main.lua 입니다.

display.setStatusBar(display.HiddenStatusBar)
local bg = display.newImageRect("splash.png",480,320)
bg.x = bg.contentWidth/2
bg.y = bg.contentHeight/2

첫줄은 아이폰의 status bar를 없애고 배경이미지를 display 하고 위치를 가운데로 잡습니다.

main.lua 에서는 따로 코딩할 부분은 없습니다.

그러면 아래와 같이 iPhone과 iPhone 4에서 각각 다른 이미지를 display 하게 됩니다.


imageSuffix 에 대해 좀 더 자세히 알고 싶으시면 여기를 누르세요.
~~~~~~~~~~
반응형


반응형
얼마전에 눈발 흩날리는 효과를 주는 앱에 대해 다뤄봤습니다.
꽤 그럴듯 했죠?

오늘은 보니까 물 속에서 물방울 올라가는 효과 비슷한 코드가 소개됐더라구요.
이것도 꽤 그럴듯하고 나중에 앱 만들 때 유용하게 쓰일 수 있을 것 같습니다.

코드부터 보자면요. config.lua는 아래와 같이 만드세요.
application =
{
	content =
	{
		width = 320,
		height = 480,
		scale = "letterbox"
	},
}
해상도는 320*480 에 맞췄구요. scale은 letterbox로 했습니다.

build.settings는 아래와 같이 작성하세요.
settings = { orientation = { default = "landscapeRight", }, }

이러면 앱이 눕혀서 실행 되겠죠?

다음은 main.lua입니다.

display.setStatusBar(display.HiddenStatusBar) local background = display.newImage("background.png") local mobs = display.newGroup() math.randomseed(os.time()) for i = 1, 10 do local greenCircle = display.newImage("greencircle.png") greenCircle.x = math.random(0,479) greenCircle.y = math.random(0,319) local randomDirection = math.rad(math.random(0,359)) greenCircle.xSpeed = 2*math.cos(randomDirection) greenCircle.ySpeed = 2*math.sin(randomDirection) mobs.insert(mobs,greenCircle) end   local function update(e) for i = 1, mobs.numChildren do mobs[i].x = mobs[i].x + mobs[i].xSpeed mobs[i].y = mobs[i].y + mobs[i].ySpeed if(mobs[i].x<0) then mobs[i].x = mobs[i].x + 480 end if(mobs[i].x>480) then mobs[i].x = mobs[i].x - 480 end if(mobs[i].y<0) then mobs[i].y = mobs[i].y + 320 end if(mobs[i].y>320) then mobs[i].y = mobs[i].y - 320 end end end   Runtime:addEventListener("enterFrame",update)

것도 눈발 흩날리는 느낌을 주는 앱처럼 enterFrame을 사용하고 있습니다.
지난 글에서 다뤘던 것처럼 이 enterFrame을 사용할 때는 메모리 관리를
확실하게 해 줘야 합니다.

위 소스를 보면요.
처음엔 아이폰의 status bar를 없애는 거구요.
다음에 배경 이미지를 넣었고 mobs라는 group을 만들었습니다.
그리고 random값을 이용할 건데 그 seed를 os.time으로 설정했습니다.

다음에는 for 문이 있는데요.
물방울 모양이 될 이미지를 하나 display 합니다.
그리고 이 이미지를 특정한 위치에 놓습니다.
이 때 random 하게 x,y좌표를 만들어서 화면 여러곳에 퍼지게 만듭니다.

다음으로는 이 원이 갈 방향을 random 하게 만듭니다. 이것은 각도를 radian
값으로 바꿔서 값을 갖고 있게 됩니다.

이 각도와 라디안 그리고 sin,cos 계산공식은 게임을 만들 때 아주 자주
사용하게 됩니다.
저도 Spin the bottle 등을 만들 때 리얼한 느낌을 주기 위해서 이런 공식을
사용 했었는데요.
tool이 아니라 game 앱을 만들려면 이런 기초 수학을 알아 두시면 아주
좋습니다.

다음 10~11번째 줄은 삼각함수를 이용해서 x,y 좌표로 이 원이 움직이는 범위(속도)를 계산해 넣습니다.
이 값은 update 문이 계속 반복 되면서 계산해야 하기 때문에 원의 프로퍼티 값으로 가지고 있어야 합니다.
그래야 일정한 방향으로 원을 움직일 수 있게 됩니다.

그 다음은 아까 생성한 mobs라는 group에 원을 insert 합니다.

그 다음 update 함수인데요. 먼저 34번째 줄 리스너를 볼까요?
enterFrame을 사용해서 각 프레임마다 update 함수를 실행 하도록 합니다.
그럼 update 문을 보시면요.
mobs에 있는 children들을 scan 하고요 이 children의 갯수만큼 for 문을
돌립니다.
그러니까 각 원마다 어떤 행동을 하도록 컨트롤 할 수 있게 되는거죠.

거기서 하는 일은 아까 처음 for문에서 정했던 x,y의 스피드를 기반으로 원의
위치를 바꾸게 됍니다.
여기까지 하면 원이 자연스럽게 움직여서 물방울 효과를 주게 됩니다.

그런데 여기까지만 하면 원이 화면 밖으로 나가면 없어져 버리게 되서요.
다음 if 문들은 원이 화면 밖으로 나가게 되면 다시 화면 안으로 들어오도록
해 줍니다.

이 정도만 해도 아주 그럴싸한 물방울 효과가 나옵니다.
진짜 할리우드 영화처럼 real한 느낌을 주시려면 원의 좌표를 바꾸는 부분을
좀 더 정교하게 control 하면 되겠죠?

아래 유튜브 영상이 이 앱을 실행한 화면입니다.



좋은 효과 잘 활용하시구요.. 추천 추천 부탁드려요... ~~~~~~~
반응형