반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 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 하면 되겠죠?

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



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


반응형
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 였습니다. ^^~~~~~



반응형


반응형
얼마전 Corona SDK Ambassador 프로그램이 진행 됐습니다.

코로나 SDK 명예 홍보 대사를 뽑는 행사인데요.
자격조건이 Corona SDK로 두 개 이상 앱을 Publish 했고 1~2개월에 한번씩 Corona SDK 관련 모임을 주관할 수 있고 (이 때 Corona 측에서 지원이 있을겁니다.) 그리고 Corona SDK에 대해 홍보해 줄 수 있는 사람이었습니다.

제가 혹시나 해서 신청했었습니다.
Skype 로 화상통화 Interview도 가졌었구요.

얼마전에 메일이 왔는데 명예 홍보 대사로 뽑혔다는 내용이었습니다.


이 이미지가 명예 홍보 대사로 뽑혔다는 메일과 함께 온 뱃지 입니다.

기분이 아주 좋습니다.
공식 발표를 조만간 한다고 하던데 언제 할지는 확실히 모르겠습니다.

공식 발표가 되면 저도 명예 홍보 대사로서 Corona를 어떻게 많은 분들에게 알릴지 그리고 Corona SDK에 대해 궁금하거나 배우고 싶은 분들이나 의견이 있으신 분들의 문의를 받아서 Corona측에 전달하는 일을 어떻게 효율적으로 진행할지 생각해 뒀다가 일을 하려고 합니다.

Corona SDK에 대해 관심 있으신 분들 많은 참여 바랄께요.

감사합니다.

글 추천도 꾸~~~~욱~~~~ 부탁드립니다. ~~~~~
반응형


반응형
오늘은 Corona로 그럴듯하게 눈발 흩날리는 느낌을 한번 줘 보겠습니다.

ramdom하고 translate, newImageRect 를 이용해서 이 효과를 줘 봤습니다.

우선 먼저 소스를 보고 분석 해 보죠.

display.setStatusBar( display.HiddenStatusBar )
local mRand = math.random; math.randomseed(os.time())
local xGravity,yGravity,xWind, yWind = 0,18,45,2
local bg = display.newImage("usa_bg2.png")
local snow = display.newGroup()
local function animateSnow( event )
    for i=1, snow.numChildren do
        local flake = snow[i]
        flake:translate((flake.xVelocity+xWind)*0.1,(flake.yVelocity+yWind)*0.1)
        if flake.y > display.contentHeight then
            flake.x, flake.y = mRand(display.contentWidth), mRand(60)
        end
    end
    if mRand(64) == 1 then xWind = 0-xWind; end
end

local function initSnow(snowCount)
    for i=1,snowCount do
        --local flake = display.newImageRect(snow,"flake.png",1,1)
        local flake = display.newImageRect(snow,"drophose.png",6,6)
        if mRand(1,2) == 1 then flake.alpha = mRand(25,100) * .01; end
        flake.x, flake.y = mRand(display.contentWidth), mRand(display.contentHeight)
        flake.yVelocity, flake.xVelocity = mRand(60), mRand(50)
    end
    Runtime:addEventListener("enterFrame", animateSnow)
end
initSnow(1000)

처음엔 아이폰의 status바 없애는 부분이고요.
두번째 줄은 mRand라는 변수에 랜덤값을 넣구요 randomseed로는 os time을 사용합니다.
중력은 y방향으로반 18을 주고 바람의 첫번째 값은 x로 45 y로 2 입니다.
다음는 배경화면을 깐겁니다.
5번째 줄에 그룹을 만들었는데요 이 그룹은 눈을 담을 겁니다.
눈 이미지는 하나만 사용할 거구요. 이 이미지를 1000개 만들어서 이 그룹에 넣게 됩니다.

다름에 animateSnow 함수가 나옵니다.

이 부분이 눈발을 흩날리는 부분입니다.
처름에 for문을 돌리는데요. snow그룹안에 있는 인자들의 갯수만큼 for문을 돌립니다.
 맨 아랫줄 보시면 1000이라는 숫자가 보이죠? snow그룹안에는 인자가 천개가 될 테니까 1000번 돌겁니다.
그 다음 flake라는 변수에 snow의 i번째 인자를 담구요 이 flake를 translate 시킵니다.
이 falke가 y방향으로 밖으로 나가게 되면 다시 화면 안으로 들어오게만들구요.

여기서 falke의 방향하고 속도는 initSnow에서 랜덤하게 정해진 값입니다.

initSnow함수는 snowCount만큼 for문을 돌립니다. 역시 1000개가 되겠죠?
flake에 imageRect를 할당합니다.
여기서 Rect에 크기를 조절하면 싸리눈도 되고 함박눈도 됩니다.
그리고 이 flake에 alpha값을 랜덤하게 지정해 줍니다.
위치도 랜덤하게 지정하구요.
다음으로 속도도 랜덤하게 적용합니다.

이렇게 1000개의 flake를 만들구요. 그 다음에 animateSnow를 Runtime의 enterframe으로 실행 시킵니다.

맨 마지막 줄은 이 initSnow함수를 실행시키는데 인자 값으로 1000을 전달합니다.
이 숫자가 적으면 눈이 적게 내리겠고 많으면 눈이 많이 내래겠죠?



완성된 화면입니다.
눈이 바람에 흩날리면서 내립니다.
눈(flake)의 갯수나 imageRect 사이즈를 조정하시면 눈을 많이 내리게도 할 수 있고 조금 내리게도 할 수 있고 싸리눈이 될 수도 있고 함박눈이 될 수도 있습니다.

이렇게 그럴듯한 눈내리는 효과를 단 25줄로 처리해 버립니다.
코로나SDK 아주 훌륭합니다...
이 효과 잘 활용하시구요. 꾹~~ 꾹~~ 추천 부탁드립니다.~~~~~
반응형

WebView, Video and Network Updates

2012. 2. 13. 06:43 | Posted by 솔웅


반응형
아래 내용은 Corona SDK Web site 에 원본이 있습니다.
아래 내용은 이 원본을 번역한 내용입니다.

===========
=========== =========== =========== =========== ===========

WebView, Video and Network Updates



이번에 native Web/Video objects 가 릴리즈 되면서 API에 몇가지 중요한 기능이 추가 됐습니다. 또한 Network library에 몇가지 아주 유용한 기능이 추가 됐구요.

***** Web View Updates

아래와 같이 native web view object 들의 상태를 back이나 forward로 control 할 수 있습니다. back()/forward() 메

소드를 써서 간단하게 조정 가능합니다.

local webview = native.newWebView( 0, 0, 320, 240 )
webview:request( "http://www.anscamobile.com" )
webview:request( "http://www.google.com" )
webview:back()   -- goes back to www.anscamobile.com
webview:forward() -- goes forward to www.google.com

canGoBack/canGoForward

위 두 메소드와 관련해서 당신의 web view object가 back이나 forward가 가능한지에 대해 체크할 수 있습니다.
예를 들어 web view object를 처음 만들었다면 이 web view object는 단지 하나만 있기 때문에 back()을 할 수도 없고

forward()를 할 수도 없습니다. 이럴 경우 canGoBack/canGoForward 모두 false 가 됩니다.

print( webview.canGoBack )  -- false

좀 더 자세한 내용은 native.newWebView() documentation을 참조하세요.



*****Video Properties and Phases


새로운 video objects와 관련해서 isMuted 프로퍼티가 새로 선 보였습니다. 이것은 get/set 프로퍼티 입니다. 여러분의 앱에 video

를 임베딩 하는데 있어 좀 더 유연하게 콘트롤 할 수 있도록 도와 줄 겁니다. 또한 새 phase 프로퍼티도 생겼는데요 video 리스너가 그것입니

다. 이 리스너에는 ready와 ended phases 가 있습니다.

아래 예제를 참고하세요.

local function videoListener( event )
    if event.phase == "ready" then
        print( "Video is ready." )

    elseif event.phase == "ended" then
        print( "Video playback has ended." )
    end
end

local videoObj = native.newVideo( 0, 0, 320, 480 )
videoObj:addEventListener( "video", videoListener )

-- load a video and jump to 0:30
videoObj:load( "myvideo.m4v", system.DocumentsDirectory )
videoObj:play()

좀 더 자세한 내용은 native.newVideo() documentation을 참조하세요.


***** Network Library

이 native object 관련 내용을 추가하면서 networkRequest 가 한가지 status와 url 프로퍼티를 갖게 됐습니다.
이것은 network request들을 콘트롤 하는데 유용하게 이용될 수 있습니다.
현재까지는 Mac/iOS/Android 에만 지원 됩니다. (Windows 에서는 조만간 지원될 예정입니다.). 이 두 새로운 프로퍼티를 사용하는 방법

에 대한 예제가 아래 있습니다.


local function networkListener( event )
    local status = event.status
    local url = event.url

    print( "The url " .. url .. " returned a status code of: " .. status
end

network.request( "http://www.google.com", "GET", networkListener )

좀 더 자세한 사항은 Network API documentation 을 참조하세요.

이 기능들을 이용하시려면 코로나 최신 버전을 사용하셔야 합니다.
최신버전은 subscriber들에게만 오픈 돼 있습니다.

추천 버튼 꾹꾹 눌러 주세요. ~~~~~~~~~~~~~~
반응형

Tutorial: Text Input with Native UI

2012. 2. 10. 00:24 | Posted by 솔웅


반응형
아래 내용은 아래 블로그에서 그 원본을 보실 수 있습니다.
http://blog.anscamobile.com/2012/02/tutorial-text-input-with-native-ui/


Text Input with Native UI

아래 내용은 코로나 SDK로 Text Field와 Text Box를 사용할 때 유용한 방법에 대해 설명한 내용입니다.

***** Text Fields vs. Text Boxes

텍스트 필드와 텍스트 박스는 아래와 같은 각각의 특징이 있습니다.

Text Fields
- 1줄 입력 기능을 제공한다. (스크롤 기능이 없다.)
- password fields로 이용할 수 있다.
- 오직 숫자만 입력하도록 설정할 수 있다. (전화기의 숫자 키보드가 나옴.)

Text Boxes
- 여러 줄 입력 기능을 제공한다. (스크롤 기능이 있다.)
- text만 보이도록 하기 위해 background를 숨길 수 있다.
- read only로 세팅할 수 있다.

아래는 두 가지 모두에 있는 기능들입니다.
- 폰트, 글자 사이즈, 글자 색을 바꿀 수 있다.
- 배경색을 바꿀 수 있다.
- userInput listening 기능이 있다.

더 자세한 신택스를 보려면 아래를 참조하세요.

Native Text Fields Documentation
Native Text Boxes Documentation 
   



***** Events and Listeners   

userInput 이벤트를 어떻게 감지하는지에 대해 알아보겠습니다.
텍스트 필드나 텍스트 박스를 생성할 때 이 userInput 이벤트 리스너를 달 수가 있습니다.
그러면 그 이벤트가 일어나는 것을 감지해서 어떤 특정한 기능을 넣을 수가 있습니다.

이 userInput 이벤트에는 몇가지의 phases가 있습니다.

began: 이 단계는 유저가 스크린에 키보드를 나오게 하는 순간입니다. 이 경우 키보드가 중요한 객체를 가리지 않게 하기 위해 위치를 변경하는 등의 기능을 넣을 수 있습니다.
edited: 이 단계는 유저가 텍스트 필드나 텍스트 박스에 타이핑을 하는 동안 일어납니다.
ended: 텍스트 필드나 텍스트 박스가 focus를 잃는 단계입니다. 예를 들어 다른 텍스트 필드/박스 를 tap할 때 등입니다.
submitted: 유저가 return/enter 키를 눌렀을 때 입니다. 즉 텍스트 필드/박스 의 내용을 submit 할때라고 얘기할 수 있습니다.

아래 userInput 리스너 를 이용하는 예제 코드가 있습니다.

local function onUserInput( event )
    if event.phase == "began" then
        print( "Keyboard has now shown up." )

    elseif event.phase == "edited" then
        print( "User has entered text." )

    elseif event.phase == "ended" then
        print( "We have lost focus." )

    elseif event.phase == "submitted" then
        print( "User is done editing, let's do something with text." )
    end
end

***** Not Normal Display Objects!
확실히 알아둬야 할 것은 native text field나 native text box는 Corona display 객체가 아닙니다.
말 그대로 native입니다. Corona SDK의 object들이 아니라 그 핸드폰의 객체들인거죠. 정확히는 그 핸드폰의 OS의 객체라고 하면 더 정확할 겁니다.
이 native객체들은 다른 Corona SDK의 객체들 처럼 위치나 투명도 같은것을 바꿀수는 있어도 Corona SDK내에서 다른 객체들과 함께 Group화 할 수는 없습니다.
그러면 화면전환등을 할 때 다른 객체들과 같이 움직이지 않을 겁니다. 보기가 조금 어글리 할 겁니다.
이러한 것을 보기 좋게 하는 방법이 있습니다. 다른 객체들처럼 움직이는 것 같이 보이도록 하는 거죠.

아래 몇가지 팁이 있습니다.
- native 객체들을 표현할 때 placeholders처럼 보이도록 text object를 만듭니다. 그리고 그 바탕에 사각형이나 rounded 사각형을 놓구요.
  여기서 text object나 사각형들은 모두 Corona SDK의 객체들입니다.
  사용자가 placeholder를 터치하면 그때 native 객체가 나오도록 합니다. 즉 유저가 editing할 때는 이 native 객체가 나와 있도록 하는 것이죠.
  유저가 입력을 끝내면 다시 native 객체를 없애고 다시 placeholder를 표시합니다. 이 때 물론 유저가 입력한 값이 해당 placeholder에 보이겠죠.
- placeholder objects들에 대해 transitions 효과를 줍니다.
- hasBackground 프로퍼티를 이용해서 텍스트 박스의 백그라운드를 안보이도록 합니다. 그리고 여러분의 백그라운드를 넣습니다.
  이 백그라운드는 일반적인 Corona SDK 객체를 이용합니다. 그래서 그 텍스트 박스를 코로나 내부 객체와 섞이도록 합니다.
 
이러한 방법들은 여러분들이 할 수 있는 여러 방법중에 극히 일부분입니다.
이러한 방법을 기초로 여러분들 나름대로 여러 효과들을 내실 수 있을 겁니다.

마지막으로 한가지 중요한 점은 이 native objects들은 object:removeSelf() 와 nil값을 대입하는 과정을 거치면서 분명히 메모리 관리를 해 주셔야 한다는 점 입니다.

***** Simulator Notes
현재 native text box와  native text field는 Mac Simulator, Xcode Simulator 그리고 디바이스에서 작동을 합니다.
맥 시뮬레이터로 테스트를 할 경우 Xcode 시뮬레이터나 디바이스에서 반드시 테스트를 해 보셔야 합니다.
왜냐하면 맥 시뮬레이터(Mac)에서 보이는 것과 실제 기계(iOS)에서 보이는 것이 다를 수가 있습니다.

맥 시뮬레이터에서는 리스너나 이벤트 처리 같은 것을 테스트 할 수 있어 개발 시간을 save해 주는 잇점이 있지면 실제 display는 다르게 작동되므로 반드시 기계에서 테스트해 보셔야 합니다.
가장 좋은 테스트 도구는 실제 device에 빌드해서 하는 것 입니다.

***** Basic Note App
아래 간단하게 Note를 할 수 있는 Note App을 한번 만들어 보겠습니다.
텍스트 필드나 텍스트 박스를 생성하는 예제 이구요 외부 소스로부터 가져와서 다이나믹하게 내용을 뿌려주는 효과도 보실 수 있을겁니다.
(여기서 외부 소스로는 text 파일이 사용됩니다.)

모든 코드는 하나의 코드파일에  들어갈 겁니다. 즉 main.lua한 파일에 다 들어갈 겁니다.

1. Creating the Interface
첫번째 단계는 아주 단순합니다. 앱의 배경을 만들고 위에 타이틀 바를 만들고 두개의 버튼 위젯을 만듭니다.

display.setStatusBar( display.DefaultStatusBar )

local widget = require "widget"
local sbHeight = display.statusBarHeight
local tbHeight = 44
local top = sbHeight + tbHeight

-- forward declarations
local titleField, noteText, loadSavedNote, saveNote

-- create background for the app
local bg = display.newImageRect( "stripes.jpg", display.contentWidth, display.contentHeight )
bg:setReferencePoint( display.TopLeftReferencePoint )
bg.x, bg.y = 0, 0

-- create a gradient for the top-half of the toolbar
local toolbarGradient = graphics.newGradient( {168, 181, 198, 255 }, {139, 157, 180, 255}, "down" )

-- create toolbar to go at the top of the screen
local titleBar = widget.newTabBar{
top = sbHeight,
gradient = toolbarGradient,
bottomFill = { 117, 139, 168, 255 },
height = 44
}

-- create embossed text to go on toolbar
local titleText = display.newEmbossedText( "NOTE", 0, 0, native.systemFontBold, 20 )
titleText:setReferencePoint( display.CenterReferencePoint )
titleText:setTextColor( 255 )
titleText.x = 160
titleText.y = titleBar.y

-- create a shadow underneath the titlebar (for a nice touch)
local shadow = display.newImage( "shadow.png" )
shadow:setReferencePoint( display.TopLeftReferencePoint )
shadow.x, shadow.y = 0, top
shadow.xScale = 320 / shadow.contentWidth
shadow.yScale = 0.25

-- create load button (top left)
local loadBtn = widget.newButton{
label = "Load",
labelColor = { default={255}, over={255} },
font = native.systemFontBold,
xOffset=2, yOffset=-1,
default = "load-default.png",
over = "load-over.png",
width=60, height=30,
left=10, top=28
}

-- onRelease listener callback for loadBtn
local function onLoadRelease( event )
loadSavedNote()
end
loadBtn.onRelease = onLoadRelease -- set as loadBtn's onRelease listener

-- create save button (top right)
local saveBtn = widget.newButton{
label = "Save",
labelColor = { default={255}, over={255} },
font = native.systemFontBold,
xOffset=2, yOffset=-1,
default = "save-default.png",
over = "save-over.png",
width=60, height=30,
left=display.contentWidth-70, top=28
}

-- onRelease listener callback for saveBtn
local function onSaveRelease( event )
saveNote()
end
saveBtn.onRelease = onSaveRelease -- set as saveBtn's onRelease listener

-- display warning that will show at the bottom of screen
local warning = display.newImageRect( "warning.png", 300, 180 )
warning:setReferencePoint( display.BottomCenterReferencePoint )
warning.x = display.contentWidth * 0.5
warning.y = display.contentHeight - 28



2. Text Box and Text Field
두번째 단계는 텍스트 필드와 텍스트 박스 객체를 생성할 겁니다.
이 두 native text 위젯을 사용할 때 폰트를 지정해주기 위해서 native.newFont()를 어떻게 사용하는지 잘 봐 두세요.
그리고 텍스트 박스는 디폴트가 read only라는 것을 명심해 두시구요.
그래서 텍스트 박스에 유저가 문자를 입력할 수 있도록 하려면 isEditable 프로퍼티를 사용하셔야 합니다.

-------------------------------------------------------------------------------------
-- Create textFields

local textFont = native.newFont( native.systemFont )
local currentTop = sbHeight+tbHeight+shadow.contentHeight+10
local padding = 10

-- create textField
titleField = native.newTextField( padding, sbHeight+tbHeight+shadow.contentHeight+10, display.contentWidth-(padding*2), 28 )
titleField.font = textFont
titleField.size = 14

currentTop = currentTop + 28 + padding

-- create textBox
noteText = native.newTextBox( padding, currentTop, display.contentWidth-(padding*2), 264-currentTop-padding )
noteText.isEditable = true
noteText.font = textFont
noteText.size = 14



여기까지 하면 겉모습은 완성 된 겁니다.

다음은 외부 txt파일로 저장하고 불러오는 부분을 다룰 겁니다.

3. Saving and Loading
이 단계에서는 saving과 loading 기능을 넣을 겁니다. 이 기능들은 유저가 Save 버튼이나 Load 버튼을 누르면 생성하도록 하겠습니다.
그리고 최초에 앱이 시작될 때 loadSavedNote()함수가 불려져서 이전에 저장됐던 내용들이 display되도록 하겠습니다.

-------------------------------------------------------------------------------------
-- Saving and Loading functions

function loadSavedNote()
local title_path = system.pathForFile( "title.txt", system.DocumentsDirectory )
local note_path = system.pathForFile( "note.txt", system.DocumentsDirectory )
local fh_title = io.open( title_path, "r" )
local fh_note = io.open( note_path, "r" )

-- load the title
if fh_title then
titleField.text = fh_title:read()
io.close( fh_title )
end

-- load the note
if fh_note then
noteText.text = fh_note:read( "*a" ) -- '*a' is important to preserve line breaks
io.close( fh_note )
end
end

function saveNote()
local title_path = system.pathForFile( "title.txt", system.DocumentsDirectory )
local note_path = system.pathForFile( "note.txt", system.DocumentsDirectory )
local fh_title = io.open( title_path, "w+" )
local fh_note = io.open( note_path, "w+" )

-- load the title
if fh_title then
fh_title:write( titleField.text )
io.close( fh_title )
end

-- load the note
if fh_note then
fh_note:write( noteText.text )
io.close( fh_note )
end
end

loadSavedNote() -- on app start, load previously saved note



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

아래 파일을 다운 받으시면 Full Souce Code와 이미지 파일 등이 있습니다. 참고하세요.

파일 받으시면서 추천버튼도 꾹 부탁드려요.
질문 있으시면 언제든지 댓글에 남겨 주세요.

반응형