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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

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 내용이긴 하지만 기본에 충실한 것이 좋은 앱을 만드는 바탕이 됩니다.

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

American idol 과 밀알 장애인 선교단

2012. 2. 29. 22:31 | Posted by 솔웅


반응형
한국에서도 오디션 프로그램이 아주 인기있다고 하던데요. 여기 미국에서도 요즘 American Idol 이 아주 인기리에 방영되고 있습니다.

작년까지 American Idol에서 독설가 역을 맡았던 Simon이 X-Factor란 새로운 프로그램을 만들어서 나갔지만 제니퍼 로페즈, 에어로 스믹스의 스티븐 테일러, 그리고 잘 모르지만 랜디 잭슨이라는 심사위원이 재밌게 잘 이끌어가고 있습니다.

작년인가 재작년에는 한국계로 존 박이 24강까지 진출했던 것 같은데 올해는 한희준이라는 한인이 24강까지 진출했습니다.



여기를 누르시면 아메리칸 아이돌 웹사이트의 한희준군 페이지로 가실 수 있습니다.

요새 조금 바쁘게 지내다 보니까 아메리칸 아이돌을 못 보고 지나치는 경우가 많아서 그냥 한국계가 24강에 올라갔다 라는 정도만 인식하고 있었습니다.
그런데 한희준군이 인터뷰에서 출전 동기가 출연료를 받으면 밀알 장애인 선교단에 헌금을 좀 더 많이 할 수 있을것 같아서라고 했다는 소리를 들었습니다.
그리고 지지난주인가에 American Idol 프로그램에 한희준군이 밀알 선교단에서 장애인 아이들에게 춤과 노래를 가르쳐주는 장면이 잠깐 나왔구요.

이 얘기를 들으면서 좀 더 관심이 가더라구요.

한희준군은 뉴욕 플러싱에 살고 있어서 뉴욕 밀알 장애인 선교단 에서 활동하고 있고 저는 뉴저지에 살고 있어서 뉴저지 밀알 장애인 선교단에 그냥 가끔 들르고(^^) 있거든요.

뉴저지 밀알 모임에서 목사님으로부터 가끔 이 아메리칸 아이돌과 한희준군에 대한 소식을 전해 듣습니다.

그래서 좀 더 관심이 가더라구요.

어제는 24강중에 남자 출연자들이 콘테스트를 벌였는데 보지는 못했어요. 바로 밀알 모임일이어서...
오늘은 꼭 봐야겠어요. 24명중에 13명을 뽑는것 같던데 한희준군이 13명중에 뽑혔으면 좋겠습니다.

예전에 보면 이 13명중에 뽑히면 나중에 아메리칸 아이돌 끝난 후에 하는 미국 전국 투어 공연에 참여하게 되더라구요.
완전 미국 인기 연예인이 되는거예요.

밀알 선교단은 한국에서 소외받는 장애인들을 위한 일을 하려고 만들어진 건데요. 세계 각 국에도 밀알 선교단이 있어서 대개 현지 한인 장애인들을 위해 일을 하고 있습니다.

이곳 미국에도 뉴욕, 뉴저지, 워싱턴, LA 등 여러곳에서 밀알 선교단이 활동중으로 알고 있구요. 캐나다나 남미도 밀알이 현지 장애인들을 위해서 아주 좋은 일들을 많이 하고 있습니다.

위 사진은 지난 설날 때 윷놀이하고 찍은 뉴저지 밀알 가족 단체 사진이예요.
자체 건물이 없어서 저 교회도 장애인 선교에 뜻을 같이하는 다른 교회가 장소 사용을 허락하셔서 일주일에 한번 잘 이용하고 있습니다.

한국에서 특히 돈과 권력을 섬기는 큰 교회들이 많이 있어서 일반인들에게 많은 비판을 받고 있는 것으로 알고 있습니다.
저도 비판 받아 싸다고 생각하고 있구요. 비판을 넘어서 그런 모습들은 쓸어서 없애 버려야 한다고 생각하구요.
하여간 그래서 기독교가 아니라 개독교라고 교회 전체가 싸잡아 비난을 받고 있지만 그런 비난 속에서도 이렇게 소외받는 힘없는 사람들을 위해 일하는 많은 분들이 있다는 걸 알아 주세요.

뉴저지, 뉴욕 밀알 선교단 홈페이지 링크 걸어 놨으니 그들이 어떤 활동을 하고 있는지 관심 있으신 분들 한번 봐 주세요.

그리고 한국에도 여러분 주위에 이런 좋은 활동하는 단체와 사람들이 분명 있을 테니 잠깐만이라도 그쪽으로 눈길 한번 돌리는 시간을 가져 주시면 좋겠습니다.

이번주 American Idol에 한희주 군이 꼭 Top 13에 뽑혔으면 좋겠습니다.
~~~~~~~~~~
반응형


반응형
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 하면 되겠죠?

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



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


반응형
지난시간에 Sencha Touch 2.0 Beta SDK Tutorial에 있는 예제를 해 봤습니다.
3개의 Tab 이 있었고 첫번재 탭은 이미지와 텍스트 뿌리는 거였고 두번째 탭은 원격 블로그를 JSON으로 불러오는 거 였습니다.
여기 두번째 까지 다뤘었구요. 세번째 이메일 보내는 탭을 할 차례인데요. 이거 하기 전에 두번째 탭에 대해 조금 더 살펴 보고 가죠.

Tutorial에는 없는 내용인데 그냥 제가 궁금해서 한번 살펴 봤습니다.
두번째 탭에서 가장 중요한 부분은 아래 부분이었습니다.

 url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/SenchaBlog',

구글 api를 이용해서 http://feeds.feedburner.com/SenchaBlog 의 내용을 가져 오는 거 였습니다.
저 웹사이트를 한번 가 봤습니다.

우리가 지난시간에 만들었던 List 첫번째 제목과 이 웹싸이트 첫번째 글 제목이 같네요.
그리고 이 List의 첫번째 아이템을 클릭하면 저 웹싸이트의 해당 글 내용이 그대로 나옵니다.
위 웹사이트의 소스를 한번 봤습니다.

제목이 <title> 태그 안에 있죠? <author>도 있고 <content> 도 있습니다.

이는 지난시간에 했던 아래 fields tag랑 일치합니다.

fields: [
                            'title', 'link', 'author', 'contentSnippet', 'content',
                            {name: 'leaf', defaultValue: true}
                        ],
즉 proxy에서 설정한 url로 가서 fields 에 명시한 필드들의 값을 googleapi를 거쳐서 가져 오는것 같습니다.

혹시나 해서 저 소스를 복사해서 제 local 에 넣고 proxy의 url 을 local의 해당 파일로 설정했는데 잘 안 되더라구요.
이번 tutorial에서는 client side에서 작업하는 것만 돼 있고 원격 server side에서 작업하는 방법이 자세하게 설명돼 있지 않아서 방법을 잘 모르겠습니다.

혹시 server side 에서 어떻게 하는지 아시는 분이나 이것 관련해서 자세히 설명된 강좌 싸이트 아시는 분 알려주시면 감사하겠습니다.

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

그럼 지난시간에 이어서 세번째 탭인 이메일 보내기를 해 보겠습니다.

***** Creating a Contact Form

마지막으로 우리가 다룰 부분은 contact form을 생성하는 겁니다.
우리는 유저이름과 이메일 주소 그리고 메세지를 받을겁니다. 그리고 이것을 FieldSet을 이용해서 보기 좋게 만들거구요. 아래 코드를 참조하세요.
Ext.application({
    name: 'Sencha',

    launch: function() {
        Ext.create("Ext.tab.Panel", {
            fullscreen: true,
            tabBarPosition: 'bottom',

            items: [
                {
                    title: 'Contact',
                    iconCls: 'user',
                    xtype: 'formpanel',
                    url: 'contact.php',
                    layout: 'vbox',

                    items: [
                        {
                            xtype: 'fieldset',
                            title: 'Contact Us',
                            instructions: '(email address is optional)',
                            items: [
                                {
                                    xtype: 'textfield',
                                    label: 'Name'
                                },
                                {
                                    xtype: 'emailfield',
                                    label: 'Email'
                                },
                                {
                                    xtype: 'textareafield',
                                    label: 'Message'
                                }
                            ]
                        },
                        {
                            xtype: 'button',
                            text: 'Send',
                            ui: 'confirm',
                            handler: function() {
                                this.up('formpanel').submit();
                            }
                        }
                    ]
                }
            ]
        });
    }
});

이 코드를 보시면 fieldset을 가지고 있는 form을 생성한 것입니다. fieldset에는 3개의 field가 있습니다. (name,email,message)
그리고 layout은 VBox layout을 사용했구요. 이것은 아래위로 아이템들을 정렬합니다. 아래쪽에는 tap handler와 함께 Button이 하나 있구요. 이 버튼이 눌려지게 되면 데이터가 url로 전달되고 submit을 통해서 결과값을 받습니다.



이 예제에서는 여기까지만 있는데요. example 폴더의 getting started 예제를 보면 버튼이 아래와 같이 돼 있습니다.
{
                            xtype: 'button',
                            text: 'Send',
                            ui: 'confirm',

                            // The handler is called when the button is tapped
                            handler: function() {

                                // This looks up the items stack above, getting a reference to the first form it see
                                var form = this.up('formpanel');

                                // Sends an AJAX request with the form data to the url specified above (contact.php).
                                // The success callback is called if we get a non-error response from the server
                                form.submit({
                                      success: function() {
                                        // The callback function is run when the user taps the 'ok' button
                                        Ext.Msg.alert('Thank You', 'Your message has been received', function() {
                                            form.reset();
                                        });
                                    }
                                });
                            }
                        }

버튼을 누르면 Contact.php로부터 결과값을 받아서 성공했을 경우 Message를 띄워 주는 겁니다.

Contact.php에는 간단하게 아래와 같이 돼 있네요.
{
    "success": true
}

일단 여기까지 3개 화면 모두 각각 만들어 봤습니다.

이제 이것을 하나로 모으는 일이 남았습니다.

모으는 방법은 .join("") 을 사용하는 방법이 있고 , 를 찍고 그냥 다음 item을 넣는 방법이 있습니다.

아래가 전체 소스입니다.
//We've added a third and final item to our tab panel - scroll down to see it
Ext.application({
    name: 'Sencha',

    launch: function() {
        Ext.create("Ext.tab.Panel", {
            fullscreen: true,
            tabBarPosition: 'bottom',

            items: [
                {
                    title: 'Home',
                    iconCls: 'home',
                    cls: 'home',
                    html: [
                        '<img width="65%" src="http://staging.sencha.com/img/sencha.png" />',
                        '<h1>Welcome to Sencha Touch</h1>',
                        "<p>You're creating the Getting Started app. This demonstrates how ",
                        "to use tabs, lists and forms to create a simple app</p>",
                        '<h2>Sencha Touch 2</h2>'
                    ].join("")
                },
                {
                    xtype: 'nestedlist',
                    title: 'Blog',
                    iconCls: 'star',
                    displayField: 'title',

                    store: {
                        type: 'tree',

                        fields: [
                            'title', 'link', 'author', 'contentSnippet', 'content',
                            {name: 'leaf', defaultValue: true}
                        ],

                        root: {
                            leaf: false
                        },

                        proxy: {
                            type: 'jsonp',
                            url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/SenchaBlog',
                            reader: {
                                type: 'json',
                                rootProperty: 'responseData.feed.entries'
                            }
                        }
                    },

                    detailCard: {
                        xtype: 'panel',
                        scrollable: true,
                        styleHtmlContent: true
                    },

                    listeners: {
                        itemtap: function(nestedList, list, index, element, post) {
                            this.getDetailCard().setHtml(post.get('content'));
                        }
                    }
                },
                //this is the new item
                {
                    title: 'Contact',
                    iconCls: 'user',
                    xtype: 'formpanel',
                    url: 'contact.php',
                    layout: 'vbox',

                    items: [
                        {
                            xtype: 'fieldset',
                            title: 'Contact Us',
                            instructions: '(email address is optional)',
                            items: [
                                {
                                    xtype: 'textfield',
                                    label: 'Name'
                                },
                                {
                                    xtype: 'emailfield',
                                    label: 'Email'
                                },
                                {
                                    xtype: 'textareafield',
                                    label: 'Message'
                                }
                            ]
                        },
                        {
                            xtype: 'button',
                            text: 'Send',
                            ui: 'confirm',
                            handler: function() {
                                this.up('formpanel').submit();
                            }
                        }
                    ]
                }
            ]
        });
    }
});


위 화면이 완성된 화면입니다.

이 Tutorial은 여러분 localhost :  http://localhost/sencha-touch-2-rc/docs/#!/guide/first_app 로 가시면 보실 수 있습니다.
웹으로 보시려면 http://docs.sencha.com/touch/2-0/#!/guide/first_app
로 가시면 보실 수 있습니다.

그리고 Sencha Touch SDK 는 http://www.sencha.com/products/touch/download/ 로 가셔서 아래 2.0 베타버전을 다운 받으셔서 여러분 서버에 설치하세요.

2.0 Release Candidate for Developers


이번 시간은 본격적인 Tutorial로 들어가기 전에 샘플 앱을 하나 만들어 본 겁니다.
다음 시간부터 본격적으로 Sencha Touch Tutorial을 정리해 보도록 하겠습니다.

***** *****
반응형


반응형
처음 Sencha SDK 설치 한 후 지지난 번에 첫번째 Sencha Application을 만들어 봤습니다.

그 다음에 Sencha에서 제공하는 Tutorial대로 차근차근 배워보기로 하고 지난 시간에 간단한 맛보기 코드를 다뤘습니다.

오늘 공부할 걸 보니까 다시 Sencha Touch로 만든 첫 번째 앱이네요.
지난번 만든건 1.1.1 버전으로 만든거니까 이번에 할 거는 2.0 베타 버전으로는 처음 만드는 앱입니다. ^^


오늘 배울 앱을 보니까 메인 화면에 Sencha Logo 가 나오고 밑에 텍스트가 나오네요.
그리고 bottom에 toolbar가 있고 세개의 버튼이 있습니다.
두번째 blog는 JSON으로 원격 웹 페이지 내용을 보여주는 부분이구요.
세번째 Contact us는 이메일을 보내는 form이 나오더라구요.

정확히 어떤 앱이고 또 이 앱을 구현하려면 어떻게 코딩을 해야 하는지 자세히 공부해 보도록 하겠습니다.

***** Getting Started
첫번째로 할 부분은 우리가 지난시간에 했던 코드랑 거의 비슷합니다. 화면이 있고 툴바가 하나 있으니까 우선 그것부터 만들어 보겠습니다.
Ext.application({
    name: 'Sencha',

    launch: function() {
        Ext.create("Ext.tab.Panel", {
            fullscreen: true,
            items: [
                {
                    title: 'Home',
                    iconCls: 'home',
                    html: 'Welcome'
                }
            ]
        });
    }
});
처음엔 별거 없습니다. launch:function()안에 코딩을 하는데 Ext.create 을 사용해서  안에 Ext.tab.Panel을 사용합니다. fullscreen은 true로 하고 item에는 Home버튼을만들고 Welcome이라는 글을 쓰게 될 겁니다.

아주 기초적인 부분입니다. 처음부터 꼼꼼히 다 알려고 하면 지칩니다.
자꾸자꾸 반복해서 몸으로 익히세요. 첨부터 머리로 익히려고 하면 골치 아픕니다.

이제 할 일은 tabBar를 밑으로 내리고 Welcome 부분에 이미지도 넣고 텍스트도 조금 더 넣을 겁니다.
Ext.application({
    name: 'Sencha',

    launch: function() {
        Ext.create("Ext.tab.Panel", {
            fullscreen: true,
            tabBarPosition: 'bottom',

            items: [
                {
                    title: 'Home',
                    iconCls: 'home',
                    html: [
                        '<img src="http://staging.sencha.com/img/sencha.png" />',
                        '<h1>Welcome to Sencha Touch</h1>',
                        "<p>You're creating the Getting Started app. This demonstrates how ",
                        "to use tabs, lists and forms to create a simple app</p>",
                        '<h2>Sencha Touch (2.0.0)</h2>'
                    ].join("")
                }
            ]
        });
    }
});

tabBar를 밑으로 하는건 tabBarPosition을 Bottom으로 하면 되구요. 이미지와 텍스트를 추가하는건 html부분을 바꾸시면 됩니다.

이제 첫번째 화면은 완성 됐죠? tabBar 넣는 일은 이제 여러번 반복해서 쉽게 하실 수 있을 겁니다.

***** Adding The Blogs Page
이제 두번째 페이지를 넣을 차례입니다.

두번째 페이지는 위와 같이 display할 겁니다.
위 아래 tab bar가 있고 가운데에는 List 가 들어갑니다. 이 텍스트들은 JSON을 통해서 외부에서 불러옵니다.
그러면 저 텍스트를 클릭하면 그에 따른 내용들이 보여집니다. 일반 웹페이지를 불러온거니까 일반 웹페이지 Navigate하는 식으로 다 작동 될 겁니다.
코드는 아래와 같습니다.
Ext.application({
    name: 'Sencha',

    launch: function() {
        Ext.create("Ext.tab.Panel", {
            fullscreen: true,
            tabBarPosition: 'bottom',

            items: [
                {
                    xtype: 'nestedlist',
                    title: 'Blog',
                    iconCls: 'star',
                    displayField: 'title',

                    store: {
                        type: 'tree',

                        fields: [
                            'title', 'link', 'author', 'contentSnippet', 'content',
                            {name: 'leaf', defaultValue: true}
                        ],

                        root: {
                            leaf: false
                        },

                        proxy: {
                            type: 'jsonp',
                            url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://feeds.feedburner.com/SenchaBlog',
                            reader: {
                                type: 'json',
                                rootProperty: 'responseData.feed.entries'
                            }
                        }
                    },

                    detailCard: {
                        xtype: 'panel',
                        scrollable: true,
                        styleHtmlContent: true
                    },

                    listeners: {
                        itemtap: function(nestedList, list, index, element, post) {
                            this.getDetailCard().setHtml(post.get('content'));
                        }
                    }
                }
            ]
        });
    }
});

코드가 너무 복잡하죠? 중괄호{}도 너무 많구요. 직접 코딩하실 때는 중괄호 끝나는 부분에 } 이게 어떤 부분의 끝인지 주석을 달아 주시면 나중에 수정하거나 분석할 때 편하실 겁니다.
여기선 몇개의 못보던 configuration들이 있죠? xtype,displayField,store 같은 것들이요.
store config는 nested list에게 data를 어떻게 수집(fetch)하는지를 알려 줍니다.
store config 내에 여러가지 요소가 있는데요.
type을 tree로 한 건 tree store를 생성한다는 거구요.
fields는 블로그 내 데이터 중 어떤 fields들을 가져오겠다고 알려주는 겁니다.
이 경우엔 블로그에서 데이터를 어떤 field 이름을 사용해서 처리했는지를 알아야 겠죠?
proxy는 이 데이터를 어디에서 가져올 거라는 것을 알려 줍니다. 이 부분은 나중에 좀 더 자세히 다룰 겁니다.
root는 leaf가 아니라는 것을 알려 줍니다.
이 Store configuration중에서 proxy가 가장 중요한 역할을 합니다.
이 예제에서는 블로그의 데이터를 JSON-P 양식으로 리턴하기 위해 Google의 Feed API Service를 사용할 거라는 것을 proxy에게 알려줍니다.
Google의 Feed API Service는 어떤 블로그의 데이터에서도 쉽게 데이터를 가져와서 우리들의 엡에 display할 수 있도록 해 줍니다.
@@@@@ url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.slashdot.org/Slashdot/slashdot', 이렇게 바꾸시면 다른 데이터를 가져 올 수 있습니다. 서버단에서 웹 페이지는 어떻게 만들어야 되는지는 나중에 다룰 겁니다. @@@@@
그 다음으로 proxy안에는 rootProperty: 'responseData.feed.entries' 부분이 있습니다.
이 부분은 그냥 이렇게 하면 Google에서 알아서 처리를 합니다. 마지막에 entries라고 복수형을 썼기 때문에 배열 형식으로 구글에서 처리할 겁니다.
이건 그냥 나중에 copy and paste해서 계속 이렇게 사용하시면 됩니다.

그 다음에 나오는 것이 detailCard와 listeners입니다.
detailCard는 유저가 tab했을 때 특정한 view를 제공할 수 있도록 해 줍니다. 우리는 스크롤이 가능하도록 세팅을 했고 글자를 좀 더 보기 좋게 하기 위해서 styleHtmlContent를 사용했습니다.

다음은 listeners에 있는 itemtap인데요.
이건 어떤 item을 tap했을 때 그 해당 item이 무엇인지 알 수 있도록 해 줍니다.
각 아이템을 클릭하면 detail들이 나올텐데요 클릭한 item을 보내줘야 해당 details를 가져올 수 있습니다.

조금 코드가 생소해서 어렵게 느껴 질 수도 있겠지만 이 코드로 직접 만들어 보시고 이것 저것 변형 시키면서 익히시면 훨씬 이해가 빠르실 겁니다.

오늘은 여기까지 하구요.
다음 시간에는 메일 보내는 화면을 마치고 세개의 화면을 하나의 앱속에서 표현될 수 있도록 하는 작업을 해 보겠습니다.

반응형


반응형
Corona SDK를 만든 Ansca의 모토 중 하나가 숙련된 프로그래머가 아닌 보통 사람들도 모바일 앱을 만들 수 있도록 하자 입니다.

Corona SDK가 나온지 2년여 됐고 이런 사례들은 많이 나왔습니다.

오늘도 한 평범한 아이가 Corona SDK를 이용해서 자신의 앱을 만들고 이를 마켓에 올린 이야기를 소개합니다.



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

제 이름은 Tyler Poon 이고 9살입니다. 저는 Corona를 이용해서 게임을 만들었습니다.

저는 Visual Basic Express for Kids라는 책을 통해서 7살때 처음 프로그래밍을 접하게 됐습니다.
그리고 Code Academy라는 웹사이트의 온라인 Tutorial들을 통해서도 배웠습니다.
그리고 나서 Youtube의 tutorial들을 보기 시작했고 테스트 프로그램들을 만들어 보기 시작했습니다.

Corona는 내가 좋아하는 툴입니다. 왜냐하면 아주 powerful하거든요. 그리고 간단하고 재밌어요. 레고처럼 아이들도 끼워 맞추면서 프로그램을 할 수 있더라구요. 코로나는 사용하기 아주 편하고 강력해서 더 재밌어요. 누구든지 관심이 있고 프로그래밍 능력이 아주 조금만 있어도 게임을 만들 수 있어요.
코로나는 또한 21세기에 맞아요. 왜냐하면 스마트폰이나 태블릿용 앱을 만드는데 사용될 수 있거든요. 스마트폰과 태블릿 용 앱을 모두 개발하고 싶으시면 코로나로 하시면 되요. 자동적으로 두 플랫폼에 맞게 빌드해 주거든요.

제가 만든 앱은 Balloons and Bombs예요.

만들면서 아주 재밌었어요 그리고 올리자마자 몇주 안에 1000번이 넘는  다운로드가 있었어요. 이 세상에서 제가 아는 사람은 1000명이나 되지 않아요. 그러니까 내 가족하고 친구들만 다운 받은건 아니예요.

제가 이 앱을 만든 과정은 코딩하고 테스트하고 수정하고 개선하고 하는 이런 과정들을 계속 반복했어요. 코딩을 할 때는 메인 게임을 만들고 타이틀 스크린을 만들었어요. 내가 할 수 없었던건 graphic이었어요. 저는 그래픽 웹 사이트를 통해서 좋은 이미지들을 얻어왔어요.
메인 게임을 코딩하고 나서 내 가족들하고 친구들한테 게임을 테스트 해 달라고 했어요. 가족들하고 친구들은 버그를 찾고 개선사안들을 제안하고 해 줬어요. fix하는 단계에서는 그들이 찾은 버그들을 수정했어요. 개선단계에서는 여러 제안들을 제 앱에 적용했어요. 그리고 나서 이 과정들을 반복했어요.

내 스스로 코딩을 할 수 있다는게 너무 재밌고 멋졌어요. 다음엔 꼭 제가 직접 디자인한 그래픽으로 제 앱을 만들고 싶어요.

제일 재밌었던건 앱을 테스트 하면서 새로운 것들을 배우기 위해 Corona API를 찾고 하나하나 배우는 것이었어요. 처음에는 문제점이 발견되면 뭘 해야 될지 몰랐지만 그 방대한 API에서 하나하나 찾아내는 방법을 알고 난 뒤엔 너무 재밌었어요.

Ansca에서 저에게 이런 글을 써 달라고 제안이 왔을 때 너무 좋았어요. 한가지 더 제가 얻은 보너스는 제 친구들도 아주 재밌어 한다는 거예요. 코로나는 애들이 배우고 사용해도 될 만큼 아주 쉬워요. 나는 내 친구들에게 코로나에 대해 가르쳐 줄 생각이예요. 걔네들도 다른 애들한테 가르쳐 주면 아주 많은 아이들이 코로나를 알 수 있겠죠? 또 한가지 보너스로 얻은 것은 제 아빠도 코로나로 게임을 만들려고 한다는거예요. 아빠는 주로 JAVA와 C로 프로그램을 만드셨거든요.

제 생각엔 코로나는 애들이 사용하기 쉽고 또 애들이 아주 훌륭한 앱을 만드는데 함께 할 툴이라고 생각해요.


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

애가 아주 귀엽게 글을 잘 썼네요.
Corona SDK는 Script 언어이기 때문에 이렇게 평범한 사람들도 배우기 쉽습니다. 그리고 Box 2D를 사용한 Physics엔진을 지원하고 또 쉽게 사용할 수 있도록 만들어서 간단하게 Physics 효과를 줄 수 있습니다.
그래서 쉽게 간단한 게임을 제작할 수 있습니다.

Tyler Poon이 만든 Balloons and Bombs는 코로나에서 제공하는 여러 샘플들을 잘 연구하고 또 나름대로 아이디어를 내서 적용해서 만든 것 같네요.
그래픽 이미지는 웹 싸이트에서 다운 받아서 썼다구 하구요.

Tyler는 2년 전에 Visual Basic에 대해 공부하고 유튜브등을 통해 프로그래밍 기법을 배웠다고 하는걸로 봐서 프로그래밍에 관심이 많았나 봐요.

Corona 가 아주 쉽다고는 하지만 이정도의 관심은 있어야 프로그래밍을 할 수 있을거예요.
그리고 Tyler의 아버지도 프로그래머 셨네요. 아마 그 영향도 있었나 봅니다.

모바일 앱을 만들고 싶으시면 여러분들도 한번 도전해 보세요.
재밌을 거에요.

그리고 혹시 프로페셔널 프로그래머들 이 글을 읽고 아무나 프로그래밍을 하면 내 밥줄 끊어지는거 아냐? 하면서 걱정하실 필요 없어요.

게임 만들면서 적용해야 하는 여러 로직이나 전체 설게 기타 전문적인 지식은 항상 필요하고 이건 단시간에 되는게 아니라 오랫동안 노하우가 축적되야 하니까 본인의 실력을 차근차근 높이시면 걱정하실거 없습니다.
단지 남들 소스 코드 가져다가 약간 변형해서 사용하는 정도가 아니라 확실히 자신의 것으로 만들고 자신의 노하우를 익히고 또 여러 정보를 공유해서 네트워크를 만들고 커리어를 만들고하는 전문가적인 활동을 하셔야 겠죠?

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

또 한가지 짜투리 소식은 조만간 안드로이드를 위한 in App Purchase도 나온다고 하네요.
관련 동영상 보시려면 여기를 클릭하세요.

안드로이드를 위한 In App Purchase는 안드로이드 마켓에만 적용 될 겁니다.
아마존이나 Nook에서는 적용이 안 될 거구요.
나중에 Tutorial 나오면 정리할께요.
그럼....


오늘도 꾹~~꾹~~~ 추천 날려 주시면 감사하겠습니다.  ~~~~~~~~
반응형


반응형
안녕하세요?

이번주에는 코로나에서 enterFrame에 대한 블로그 강좌를 했네요.
이 강좌 내용을 아래에 정리했습니다.

원본은 여기를 클릭하시면 보실 수 있습니다.

Understanding Corona’s enterFrame Event

오늘은 코로나의 enterFrame Event에 대해 알아보겠습니다.
Event 전반에 대해 알고 싶으시면 여기를 클릭하세요.

****** What is an enterFrame event?

앱이 시작하면서 여러분의 앱은 아주 빠른 속도로 화면을 새로 갱신하면서 보여주게 됩니다.
이 속도를 나타내는 단위는 frames-per-second (FPS)입니다. 코로나에서는 두가지 세팅을 지원하는데요. 30과 60 FPS입니다.
관련된 정보는 여기에 있습니다.

이 속도를 다른 말로는 framerate이라고도 합니다.
여러분이 config.lua파일에 60FPS로 설정을 했으면 이것은 1초에 스크린을 60번 다시 그린다는 겁니다.

enterFrame아라는 말은 새로운 프레임에 entering하는 순간을 말합니다. 즉 framerate이 30이라면 이 enterFrame이벤트는 1초에 30번 일어나게 됩니다.
그러니까 이 enterFrame 이벤트를 사용하면 여러분은 매 프레임마다 어떤 컨트롤을 할 수 있게 되는 겁니다.

****** enterFrame Listeners
이 enterFrame이벤트와 다른 많은 코로나 이벤트와 다른점은 리스너를 Runtime으로만 설정할 수 있다는 겁니다.
각 object마다 이 enterFrame을 따로 적용할 수는 없습니다.

아래 이 enterFrame 사용 예제를 보세요.

-- listener function
local function onEveryFrame( event )
    print( "This function will be called on every frame." )
end

-- assign the above function as an "enterFrame" listener
Runtime:addEventListener( "enterFrame", onEveryFrame )

우선 함수를 만들고 그 다음에 Runtime에 enterFrame 이벤트를 add합니다.
이 예제는 아주 기본적인 거구요. 다음 예제에서 조금 응용한 걸 보여드리겠습니다.

***** Translating objects
아래 예제는 각 프레임마다 객체가 천천히 아래로 내려갔다가 한번에 다시 올라가고 또 내려오는 동작을 반복하는 움직임을 보일 겁니다.

local ball = display.newImage( "redball.png" )
ball.x = math.random( display.contentWidth )
ball.y = -ball.contentHeight

-- listener function for enterFrame event
local function onEveryFrame( event )
    ball:translate( 0, 1 ) -- move ball 1pt down on every frame

    -- move ball above top of screen when it goes below the screen
    if ball.y > display.contentHeight then
        ball.y = -ball.contentHeight
    end
end

-- assign the above function as an "enterFrame" listener
Runtime:addEventListener( "enterFrame", onEveryFrame )

***** Tracking Time

enterFrame 리스너의 이벤트 테이블 안에는 여러분의 앱이 시작한 이후부터 지금까지의 시간에 대한 정보가 들어있습니다.
event.time이 시작한 시간인데요. system.getTimer()메소드를 통해서 값을 얻을 수 있습니다.
아래 예제는 유저가 버튼을 누르고 3초 이상 지났을 때를 체크하는 코드 입니다.
local timeThresh = 3

local button = display.newImage( "button.png" )
button.markTime = system.getTimer()

-- enterFrame listener function
local function trackTime( event )
    local secondsPassed = (event.time - button.markTime) / 1000 -- divide by 1k to get seconds
   
    if secondsPassed >= timeThresh then
        print( "You held down the button for at least " .. timeThresh .. " seconds." )
       
        -- stop tracking time
        Runtime:removeEventListener( "enterFrame", trackTime )
    end
end

-- touch event for the button object
function button:touch( event )
    if event.phase == "began" then
        print("Touched");
       
        -- assign touch focus to this object
        display.getCurrentStage():setFocus( self )
        self.isFocus = true
       
        -- mark time and start tracking time with enterFrame listener
        self.markTime = system.getTimer()
        Runtime:addEventListener( "enterFrame", trackTime )
   
    elseif self.isFocus then
        if event.phase == "ended" or event.phase == "cancelled" then
           
            -- stop tracking time
            Runtime:removeEventListener( "enterFrame", trackTime )
           
            -- remove touch focus from button
            display.getCurrentStage():setFocus( nil )
            self.isFocus = false
        end
    end
   
    return true
end

button:addEventListener( "touch", button )

이 코드 아주 유용하게 쓰여질 수도 있겠네요.

****** Special Considerations

이 enterFrame은 각 프레임별로 체크를 하기 때문에 아주 강력합니다. 대신에 메모리를 많이 소비하므로 꼭 필요할 때만
사용하고 그렇지 않을 때는 없애 줘야 합니다.
한 scene에서 enterFrame을 사용했는데 다른 scene으로 넘어갈 때 이 enterFrame을 제거하지 않는다면 유저가 다시 첫번째
scene으로 돌아 왔을 때는 각 프레임마다 이 enterFrame이 두번 실행 될 겁니다.
다시 다른데 갔다가 돌아오면 세번 실행되겠죠? 각 프레임마다.... 그럼 performance가 아주 형편 없어질 겁니다.

이 enterFrame사용시 절대 잊어서는 안되는 것이 이런 상황을 만들지 않는 겁니다.


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


반응형
지난달 Michelle Fernandez 가 만든 Corona SDK Game Development Beginner's Guide 책 표지 디자인 공모 소식을 전해 드렸었습니다.

그 글 읽으신 분 들 중 혹시 표지 디자인에 공모하신 분이 계신 지 모르겠는데요.

그 표지 디자인 콘테스트 결과가 발표 됐습니다.

총 40여면이 응모했다고 하는데요 3편이 당선 됐고 그중 최종 우승자는 Raphael Pudlowski 작품이 선정됐습니다.
Pudlowski 는 폴란드의 Cracow 사람입니다.
Cracow는 예전에 가 본적 있는데 도시 중앙 광장이 아주 넓은 .. 그리고 예전에는 섬유업이 아주 발달했던 도시로 기억납니다.
왕이 살던 궁전도 언덕위에 아주 아름답게 있었구요.
무엇보다 아우슈비츠 수용소가 가까이 있어서 저도 들르게 됐었습니다.


작가는 이 작품이 개인적으로 진행하던 프로젝트 였는데 콘테스트 광고를 보고 성격에 잘 맞을 것 같아서 응모했다고 하네요.
코로나가 아주 급속도로 발전/성장하고 있고 주로 게임에 이용되는 툴이기 때문에 재미와도 연관되고 해서요...
카멜레온이 환경에 맞게 자신의 색을 마음대로 변하듯이 코로나도 그런 이미지가 있다고 느꼈답니다. 한번 개발해서 여러 플랫폼용으로 빌드할 수 있다는 점이요. 그리고 카멜레온은 또한 Corona 맥주 광고에도 나온다고 하네요.

심사위원 중 Ansca의 CEO인 Carlos는 로케트가 위를 향해서 발사되는 모습하고 카멜레온이 마음에 들었다고 합니다. 카를로스에게 위로 발사되는 로케트는 성공을 연상시켰고 그 로케트는 corona sdk가 아주 발사 됐다는 연상도 됐구요. 그리고 카멜레온은 외로운 인디'indie' 가 연상됐다고 하네요. 개별 개발자 나 앱이라는 무기를 쉽게 장착할  수없는 개인이 로케트라는 장치에 쉽게 올라타서 멋진 글라이딩을 펼칠 수 있는 그런 느낌. 우리의 Carlos는 그런 느낌을 받아서 이 작품을 선정했다고 합니다.

덧붙여서 Corona는 원래 태양을 의미하고 Lua 는 달을 의미합니다. 그 이미지와도 연관이 있구요.

이 작품은 Michelle M. Fernandez가 쓴  Corona SDK Beginner's Guide라는 책의 표지 모델로 사용이 될 겁니다. 4월말에 출판 될 예정이라네요. 그리고 Corona SDK 무료 이용권하고 Packt Publishing으로부터 100달러 상당의 이미지 라이센스 사용권을 받는다고 합니다. 그리고 책 안에도 이름과 작품이 언급될 예정이구요.

아주 멋지죠?

2위는 미국 조지아에 사는 Andrew Wardlow의 아래 작품이 선정됐습니다.


3위는 멕시코의 Michoacan에 사는 Adam Jhesu Rufino Nakamura가 탔습니다.
성이 나카무라네요. 일본계인가보죠?


2위와 3위는 Packt Games Library의 120불 상당 회원권을 받구요 Corona SDK Game Development Beginner's Guide책도 무료로 한권 받는 답니다.

이상 뉴저지에서 Corona SDK 명예 홍보대사 Douglas 였습니다. ^^~~~~~



반응형