오늘 다룰 소스는 Peach Pellen 이라는 개발자가 자기 친구가 앱을 개발한다는 얘기를듣고 도움이 될까 해서 만든 주사위놀이 샘플 코드입니다. 그리고 그 코드를 공개해서 다른 분들도 도움이 되길 바란다고 하네요.
아래 링크로 가시면 관련 글을 보실 수 있습니다.
http://techority.com/2011/11/22/rolling-the-dice/
저 싸이트로 가시면 샘플 코드를 다운 받으실 수 있구요.
아래 저도 그 코드를 올려 놓을 테니까 여기서 곧바로 다운 받으셔도 됩니다.
실행 화면은 아래와 같습니다.
오른쪽 위에 하얀 사각형을 누르면 주사위가 막 돌다가 멈춥니다.
그러면 터미널에 두 주사위의 합이 출력 됩니다.
그런데 이상한건 제가 집에서 이 소스코드를 실행 했을 때는 두 주사위가 항상 같은 숫자만 나왔거든요.
그래서 다른 숫자가 나오도록 소스를 좀 수정했습니다.
그리고 터미널뿐만 아니라 화면에도 합계가 텍스트로 표시 되도록 했구요.
그런데 회사와서 이 코드를 돌려보니까 두 주사위가 항상 같은 숫자가 나오는게 아니더라구요.
집에 있는 컴퓨터는 윈도우고 회사에 있는건 맥이라서 그런가?
하여간 아래 코드는 제가 조금 수정한 코드입니다. 다운 받은 파일에 있는 소스랑은 아주 조금 다를거예요.
--Hide the status bar => 스테이터스 바 감추기
display.setStatusBar(display.HiddenStatusBar)
--Require sprite => 스프라이트 require하기. 스프라이트는 director.lua나 movieclip.lua 처럼 별도의 파일로 제공되는게 아니라 corona sdk 에 내장된 클래스 입니다. 따로 파일을 구하실 필요가 없습니다.
require "sprite"
=> 스크린 너비와 높이 구해 놓기
_W = display.contentWidth;
_H = display.contentHeight;
--The background image => 배경화면 표시하고 합계를 표시할 텍스트 선언하고 위치 정해 줌
local bg = display.newImage( "bg.png" )
local total = display.newText("", _W/2, _H-(_H/7), native.systemFontBold, 30)
--Total sum of dice after a roll => 주사위 합계 담을 변수
local diceTotal = 0
--States whether or not the dice may be rolled => 주사위 돌리기 가능한 상태인지 아닌지 콘트롤 할 변수
local canRoll = true
--Sprite Setup => 스프라이트를 셋업 함
local diceSheet = sprite.newSpriteSheet( "dice.png", 64, 64)
주사위로 사용할 이미지는 이 이미지 입니다.
일단 이 이미지를 diceSheet이라는 이름으로 만듭니다. 이 프레임의 크기는 64X64 입니다.
local diceSet = sprite.newSpriteSet( diceSheet, 1, 6 )
sprite.add( diceSet, "dice", 1, 6, 195, 0)
sprite.add( diceSet, "dice2", 1, 6, 210, 0)
위 diceSheet를 diceSet이라는 스프라이트 세트에 담습니다. 시작하는 프레임은 1 이고 총 6개 프레임이 있습니다.
이 diceSet를 add합니다. 신택스는 아래와 같습니다.
sprite.add( spriteSet, sequenceName, startFrame, frameCount, time, [loopParam] )
첫번째는 diceSet를 dice라는 sequenceName으로 add를 하는데 시작 프레임 1이고 전체 프레임 count는 6 입니다. time은 195입니다. 이것은 195ms에 이 diceSet을 한번 돌린다는 겁니다.
두번째 줄은 dice2인데 dice와 모두 같고 이 time이 210 입니다.
두 주사위가 6개 프레임의 돌아가는 시간이 다르니까 각각 다른 프레임이 나오겠네요.
윈도우에서 항상 똑 같은 주사위 이미지가 나온게 제가 착각한 건가 본데요?
혹시 여러분 윈도우에서 한번 돌려보시구 어떻게 나오나 잘 살펴 보세요.
저도 집에 돌아간 다음에 다시 돌려 봐야 겠네요.
--First Die
local dice = sprite.newSprite( diceSet )
dice.x = 120
dice.y = 200
dice:prepare("dice")
첫번째 sprite를 dice라는 변수에 담고 화면의 위치를 정해 줍니다.
스프라이트 쉬트 사용하는 순서가 이렇게 되네요.
sprite.newSpriteSheet => sprite.newSpriteSet => sprite.add => sprite.newSprite => spriteInstance:prepare => spriteInstance:play => spriteInstance:pause
따로 정리해서 외워도 좋겠는데요.
--Second Die
local dice2 = sprite.newSprite( diceSet )
dice2.x = 200
dice2.y = 300
dice2:prepare("dice2")
두번째 스프라이트 dice2를 선언합니다.
--Roll button
local rollBtn = display.newImage("die.png")
rollBtn.x = 280
rollBtn.y = 40
=> 버튼 이미지를 표시합니다.
--End Roll Function
local function endRoll()
dice:pause()
showTotal();
end
첫번째 주사위 play를 중지시키고 showTotal함수를 실행합니다.
local function endRoll2()
dice2:pause()
showTotal();
end
두번째 주사위 play를 중지시키고 showTotal함수를 실행합니다.
function showTotal()
diceTotal = dice.currentFrame + dice2.currentFrame
print(diceTotal) --Print the result in the terminal
total.text="Total : " .. diceTotal;
canRoll = true --Allow the dice to be rolled again
end
현재 프레임 = 주사위 눈 입니다. dice와 dice2의 현재 프레임을 구해서 더하면 주사위 두 눈의 합이 됩니다.
이것을 터미널에 print하고 스크린에도 표시합니다.
canRoll은 true로 세팅해서 버튼을 누르면 주사위가 돌아갈 수 있도록 합니다.
--Roll function
local function rollDice()
if canRoll == true then
canRoll = false --Prevent dice from being rolled again before the current role is over
dice:play()
dice2:play()
randomTime = math.random(1500, 3500)
timer.performWithDelay(randomTime, endRoll, 1)
randomTime2 = math.random(1500, 3500)
timer.performWithDelay(randomTime2, endRoll2, 1)
end
end
canRoll을 false로 해서 버튼을 눌러도 주사위가 새로 돌지 않도록 막아 놓습니다.
dice와 dice2를 play시킵니다.
랜덤값 (1.5초 ~ 3.5초)를 구해서 timer를 사용해서 그 시간만큼만 돌고 dice를 멈추게 합니다. 다음줄은 dice2를 멈추게 합니다.
rollBtn:addEventListener("tap", rollDice)
버튼에 이벤트 리스너를 달아서 누르면 rollDice가 실행 되도록 합니다.
이렇게 하면 위 그림처럼 화면에 주사위 눈의 합이 출력 됩니다.
원래 소스가 두 주사위의 눈이 각각 다르게 표시되도록 하는 거였다면 제가 수정한 코드는 괜히 수정한 거네요. 이미 원래 소스에 이런 경우를 생각해서 스프라이트에서 프레임 플레이 시간을 각각 다르게 해 준건데......
어쨌든 남의 소스를 보고 나름대로 고쳐보는게 프로그래밍 배우는데 아주 큰 도움이 됩니다.
여러분들도 이 코드를 이용해서 이것저것 고치거나 기능을 덧붙이거나 하면 빨리 실력이 늘고 이 코드도 진짜로 여러분의 코드가 되고 여러분의 자산이 될 거예요.
그럼 다음 시간에 뵐께요......
'Corona SDK > Corona SDK TIPs' 카테고리의 다른 글
Modular Classes in Corona - 모듈과 클래스 이해하기 - (0) | 2011.12.08 |
---|---|
코로나로 책장 넘기는 효과 주기 (0) | 2011.12.06 |
내 코드 모듈화 하기 (modularize) (0) | 2011.12.01 |
드래그 하기 기초 (0) | 2011.11.25 |
화면 전환 클래스(director.lua) 사용하기 와 랜덤 화면 전환 (2) | 2011.11.24 |
ui 버튼이용 하기 ui.newButton (0) | 2011.11.18 |
화면에 시간 표시하기 (스탑와치) (0) | 2011.11.17 |
Screen Transitioning. (화면 전환,이동) (0) | 2011.11.16 |
앱 항상 켜 있게 하기 (system.setIdleTimer( enabled )) (0) | 2011.11.15 |
Animation Speed Control 은 movieClip보다 Sprites로 (0) | 2011.11.14 |
We desperately need a speed control as the animation just play crazy
앱을 쌈박하게 만들기 위해서는 애니메이션 스피드 조절 기능이 완전 필요합니다.
What is the best way to control the speed of the animation?
Would it be a case of using a timer and calling something like
myAnim:nextFrame()
애니메이션의 스피드 조절하는 가장 좋은 방법이 뭐지요?
myAnim:nextFrame() 함수를 타이머를 이용해서 부르는 것이 방법이 될까요?
@Paul – your suggestion would probably work well in some cases, although if you had more than a few clips onscreen, you’d want to test it on target devices to see the performance. I don’t think timers are necessarily that expensive, but they might add up if you had a lot of functions constantly polling the system time.
The movieclip library is primarily designed for a Flash-like model, in which there’s a global framerate for everything. For greater timing control, or for complex animation cases, we’d recommend using Game Edition and the sprite-sheet feature.
In addition to using texture memory much more efficiently (one big image rather than lots of little ones), that feature includes an animated-sprite API that lets you set different animation speeds for different sprites, or even for different sequences within the same sprite. Also, it’s a time-based API rather than frame-based, so the total animation time will remain the same even on slower devices that need to drop frames — the engine automatically handles all this under the hood.
@Paul - 당신의 방법이 잘 적용되는 케이스도 있을 거예요. 아마 무비크립이 적거나 특정한 디바이스에서만 테스트를 원한다면 더 그럴거예요. 하지만 내 생각엔 타이머는 앱을 좀 헤비하게 만들것 같네요.
무비클립은 플래쉬를 모델로 디자인 된 겁니다. 기본적으로 전체 frame rate가 있고 이것이 모든 무비클립에 동일하게 적용됩니다. 좀 더 타이밍 콘트롤을 하고 싶거나 복잡한 애니메이션을 원한다면 Game Edition과 Sprite sheet를 사용하기를 권장합니다.
더군다나 sprite API는 메모리도 효율적으로 운용할 수 있어요. 그리고 각 애니메이션 마다 다른 스피드를 줄 수도 있구요. 스프라이트 애니메이션은 time base 입니다. movieclip은 프레임 베이스이구요. 그래서 사양이 낮은 기계에서도 각 애니메이션별 스피드 차이는 동일하게 나타날 겁니다.
@Chan, You should use the Sprite library instead of the Movieclip library because it gives you better control over the animations. You do have a onComplete listener with Sprites.
@Chan, 무비클립 라이브러리 보다는 스프라이트 라이브러리를 이용해야 애니메이션의 속도 컨트롤이 더 수월합니다. 그리고 스프라이트에는 onComplete리스너도 있습니다.