반응형
오늘은 벽돌 깨기 게임 만들기 마지막회가 될것 같은데요.
어제까지 일단 화면에 표시할 모든 객체들은 다 표시했습니다.
그리고 화면에서는 공만 여기저기 튀면서 움직이고 있습니다.
이제 남은 일은 밑에 있는 paddle을 유저가 좌우로 움직일 수 있도록 해야 하고,
공이 벽돌에 맞으면 벽돌이 없어지게 해야 하고,
공이 bottom Wall에 맞으면 공이 없어지고 새로 시작하도록 해야 합니다.
그럼 우선 첫번째 paddle을 움직이는 것 부터 해 볼까요?
지난 시간 까지 했던 paddle 생성 함수는 아래와 같습니다.
function createPaddle()
local paddleWidth = 100
local paddleHeight = 10
local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
physics.addBody(paddle, "static", {friction=0, bounce=1})
end
자 touch 이벤트 리스너를 달겠습니다.
Runtime:addEventListener("touch", movePaddle)
paddle에 달지 않고 Runtime에 달았습니다. 유저가 paddle에 닿았을 때만 움직일 수 있도록 하려면 Runtime을 paddle로 바꾸면 됩니다.
하지만 여기선 유저가 움직일 수 있는 객체가 paddle밖에 없고 화면 전체에서 이 이벤트 리스너를 받는게 더 효과적이기 때문에 Runtime에 이벤트 리스너를 달았습니다.
이 이벤트 리스너는 화면 아무곳이나 touch하면 movePaddle 함수가 실행 되도록 하라는 의미 입니다.
이 이벤트 리스너 앞에 movePaddle 함수를 만듭니다.
그리고 event.x를 paddle.x에 대입하면 이 paddle의 위치가 좌우로 움직입니다.
local movePaddle = function(event)
paddle.x = event.x
end
자 이제 유저가 paddle을 움직일 수 있습니다.
그 다음은 공이 벽돌에 맞으면 그 벽돌이 없어지도록 할께요.
addBody를 할 때 공은 dynamic으로 설정하고 나머지 객체들은 모두 static으로 설정했습니다.
이 dynamic으로 설정한 공에 충돌(collision)을 체크하는 로직을 적용하도록 하겠습니다.
function createBall()
ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
ball:setLinearVelocity(75, 150)
end
지난 시간까지 한 소스코드 입니다.
이제 ball에 collision 이벤트 리스너를 답니다.
ball:addEventListener("collision", ball)
공이 어딘가에 충돌했을 때 ball.collision 함수가 실행 됩니다.
여기서 어딘가는 physics.addBody 가 적용된 객체들을 말합니다.
그럼 ball.collision함수를 만들어 보겠습니다.
ball.collision = function(self, event)
if(event.phase == "ended") then
if(event.other.type == "destructible") then
event.other:removeSelf()
end
end
end
벽돌을 만들 때 각각의 벽돌에 type을 destructible 이라고 주었었습니다.
여기서 event.other는 충돌의 상대편을 말합니다. event.target은 충돌 당사자를 말합니다. 그러므로 event.other는 벽돌이고 event.target은 ball 이겠죠.
event.other.type이 destructible이면 즉 벽돌이면 event.other:removeSelf() 합니다. 즉 그 벽돌을 없앱니다.
아주 간단하죠?
이제 벽돌 깨기의 주요 기능이 다 구현 됐습니다.
여기서 보너스로 한가지만 더 한다면 공이 bottom wall에 부딪혔을 때 공이 없어지고 새로 시작하도록 하겠습니다.
이것도 공이 collision 이벤트를 일으켰을 때 일어나는 현상이기 때문에 아까 만들었던 ball.collision 함수 안에 아래 코드를 넣습니다.
if(event.other.type == "bottomWall") then
self:removeSelf()
local onTimerComplete = function(event)
createBall()
end
timer.performWithDelay(500, onTimerComplete , 1)
end
이걸 넣고 실행해 보시면 공이 바닥에 닿으면 없어지고 가운데에서 다시 생성 되는 것을 보실 수 있을 겁니다.
이 경우 collision 이벤트가 발생했을 때 event.other.type이 bottomWall 이면 self:removeSelf()를 해 줍니다. other가 아니라 자신이 없어지는 겁니다.
그리고 timer로 0.5초의 시간을 두고 onTimerComplete 함수를 한번 호출하도록 만듭니다.
이 함수에서는 createBall()을 호출합니다.
그러면 공이 바닥에 부딪혀서 없어지고 0.5초 후에 새 공이 가운데에서 만들어져서 움직이기 시작할 겁니다.
전체 소스는 아래와 같습니다.
require ("physics")
function main()
setUpPhysics()
createWalls()
createBall()
createPaddle()
createBricks()
end
function setUpPhysics()
physics.start()
physics.setGravity(0,0)
end
function createBall()
ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
ball:setLinearVelocity(75, 150)
ball.collision = function(self, event)
if(event.phase == "ended") then
if(event.other.type == "destructible") then
event.other:removeSelf()
end
end
if(event.other.type == "bottomWall") then
self:removeSelf()
local onTimerComplete = function(event)
createBall()
end
timer.performWithDelay(500, onTimerComplete , 1)
end
end
ball:addEventListener("collision", ball)
end
function createWalls()
local wallThickness = 10
-- Left wall
local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Top wall
wall = display.newRect(0,0, display.contentWidth, wallThickness)
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Right wall
wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Bottom wall
wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
physics.addBody(wall, "static", {friction=0, bounce = 1})
wall.type = "bottomWall"
end
function createPaddle()
local paddleWidth = 100
local paddleHeight = 10
local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
physics.addBody(paddle, "static", {friction=0, bounce=1})
local movePaddle = function(event)
paddle.x = event.x
end
Runtime:addEventListener("touch", movePaddle)
end
function createBricks()
local brickWidth = 40
local brickHeight = 20
local numOfRows = 4
local numOfCols = 6
local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}
local row
local col
for row = 0, numOfRows - 1 do
for col = 0, numOfCols - 1 do
-- Create a brick
local brick = display.newRect( topLeft.x + (col * brickWidth), topLeft.y + (row * brickHeight), brickWidth, brickHeight )
brick:setFillColor(math.random(50, 255), math.random(50, 255), math.random(50, 255), 255)
brick.type = "destructible"
physics.addBody(brick, "static", {friction=0, bounce = 1})
end
end
end
main()
원본 소스는 ball:setLinearVelocity(75, 150) 를 startGame()에 넣고 사용했는데 저는 하다 보니까 그냥 createBall에 넣었네요. 두개 다 똑 같습니다.
다만 나중에 게임에 여러 기능을 추가하다 보면 startGame()을 따로 Call할 일이 많이 생길 수 있는데 그 때는 원본 소스 같이 따로 함수로 관리하는게 더 낫겠죠.
이 소스는 Corona SDK를 만든 회사인 Ansca Mobile에서 제공한 샘플 소스입니다.
아래 유튜브로 가시면 이 샘플 코드에 대한 강좌를 들으실 수 있습니다.
제가 설명했던 것과는 조금 다르게 설명하겠죠?
이것도 들어보시면 도움이 될 거예요.
그럼 다음시간에 뵐께요.
어제까지 일단 화면에 표시할 모든 객체들은 다 표시했습니다.
그리고 화면에서는 공만 여기저기 튀면서 움직이고 있습니다.
이제 남은 일은 밑에 있는 paddle을 유저가 좌우로 움직일 수 있도록 해야 하고,
공이 벽돌에 맞으면 벽돌이 없어지게 해야 하고,
공이 bottom Wall에 맞으면 공이 없어지고 새로 시작하도록 해야 합니다.
그럼 우선 첫번째 paddle을 움직이는 것 부터 해 볼까요?
지난 시간 까지 했던 paddle 생성 함수는 아래와 같습니다.
function createPaddle()
local paddleWidth = 100
local paddleHeight = 10
local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
physics.addBody(paddle, "static", {friction=0, bounce=1})
end
자 touch 이벤트 리스너를 달겠습니다.
Runtime:addEventListener("touch", movePaddle)
paddle에 달지 않고 Runtime에 달았습니다. 유저가 paddle에 닿았을 때만 움직일 수 있도록 하려면 Runtime을 paddle로 바꾸면 됩니다.
하지만 여기선 유저가 움직일 수 있는 객체가 paddle밖에 없고 화면 전체에서 이 이벤트 리스너를 받는게 더 효과적이기 때문에 Runtime에 이벤트 리스너를 달았습니다.
이 이벤트 리스너는 화면 아무곳이나 touch하면 movePaddle 함수가 실행 되도록 하라는 의미 입니다.
이 이벤트 리스너 앞에 movePaddle 함수를 만듭니다.
그리고 event.x를 paddle.x에 대입하면 이 paddle의 위치가 좌우로 움직입니다.
local movePaddle = function(event)
paddle.x = event.x
end
자 이제 유저가 paddle을 움직일 수 있습니다.
그 다음은 공이 벽돌에 맞으면 그 벽돌이 없어지도록 할께요.
addBody를 할 때 공은 dynamic으로 설정하고 나머지 객체들은 모두 static으로 설정했습니다.
이 dynamic으로 설정한 공에 충돌(collision)을 체크하는 로직을 적용하도록 하겠습니다.
function createBall()
ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
ball:setLinearVelocity(75, 150)
end
지난 시간까지 한 소스코드 입니다.
이제 ball에 collision 이벤트 리스너를 답니다.
ball:addEventListener("collision", ball)
공이 어딘가에 충돌했을 때 ball.collision 함수가 실행 됩니다.
여기서 어딘가는 physics.addBody 가 적용된 객체들을 말합니다.
그럼 ball.collision함수를 만들어 보겠습니다.
ball.collision = function(self, event)
if(event.phase == "ended") then
if(event.other.type == "destructible") then
event.other:removeSelf()
end
end
end
벽돌을 만들 때 각각의 벽돌에 type을 destructible 이라고 주었었습니다.
여기서 event.other는 충돌의 상대편을 말합니다. event.target은 충돌 당사자를 말합니다. 그러므로 event.other는 벽돌이고 event.target은 ball 이겠죠.
event.other.type이 destructible이면 즉 벽돌이면 event.other:removeSelf() 합니다. 즉 그 벽돌을 없앱니다.
아주 간단하죠?
이제 벽돌 깨기의 주요 기능이 다 구현 됐습니다.
여기서 보너스로 한가지만 더 한다면 공이 bottom wall에 부딪혔을 때 공이 없어지고 새로 시작하도록 하겠습니다.
이것도 공이 collision 이벤트를 일으켰을 때 일어나는 현상이기 때문에 아까 만들었던 ball.collision 함수 안에 아래 코드를 넣습니다.
if(event.other.type == "bottomWall") then
self:removeSelf()
local onTimerComplete = function(event)
createBall()
end
timer.performWithDelay(500, onTimerComplete , 1)
end
이걸 넣고 실행해 보시면 공이 바닥에 닿으면 없어지고 가운데에서 다시 생성 되는 것을 보실 수 있을 겁니다.
이 경우 collision 이벤트가 발생했을 때 event.other.type이 bottomWall 이면 self:removeSelf()를 해 줍니다. other가 아니라 자신이 없어지는 겁니다.
그리고 timer로 0.5초의 시간을 두고 onTimerComplete 함수를 한번 호출하도록 만듭니다.
이 함수에서는 createBall()을 호출합니다.
그러면 공이 바닥에 부딪혀서 없어지고 0.5초 후에 새 공이 가운데에서 만들어져서 움직이기 시작할 겁니다.
전체 소스는 아래와 같습니다.
require ("physics")
function main()
setUpPhysics()
createWalls()
createBall()
createPaddle()
createBricks()
end
function setUpPhysics()
physics.start()
physics.setGravity(0,0)
end
function createBall()
ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})
ball:setLinearVelocity(75, 150)
ball.collision = function(self, event)
if(event.phase == "ended") then
if(event.other.type == "destructible") then
event.other:removeSelf()
end
end
if(event.other.type == "bottomWall") then
self:removeSelf()
local onTimerComplete = function(event)
createBall()
end
timer.performWithDelay(500, onTimerComplete , 1)
end
end
ball:addEventListener("collision", ball)
end
function createWalls()
local wallThickness = 10
-- Left wall
local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Top wall
wall = display.newRect(0,0, display.contentWidth, wallThickness)
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Right wall
wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
physics.addBody(wall, "static", {friction=0, bounce = 1})
-- Bottom wall
wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
physics.addBody(wall, "static", {friction=0, bounce = 1})
wall.type = "bottomWall"
end
function createPaddle()
local paddleWidth = 100
local paddleHeight = 10
local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
physics.addBody(paddle, "static", {friction=0, bounce=1})
local movePaddle = function(event)
paddle.x = event.x
end
Runtime:addEventListener("touch", movePaddle)
end
function createBricks()
local brickWidth = 40
local brickHeight = 20
local numOfRows = 4
local numOfCols = 6
local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}
local row
local col
for row = 0, numOfRows - 1 do
for col = 0, numOfCols - 1 do
-- Create a brick
local brick = display.newRect( topLeft.x + (col * brickWidth), topLeft.y + (row * brickHeight), brickWidth, brickHeight )
brick:setFillColor(math.random(50, 255), math.random(50, 255), math.random(50, 255), 255)
brick.type = "destructible"
physics.addBody(brick, "static", {friction=0, bounce = 1})
end
end
end
main()
원본 소스는 ball:setLinearVelocity(75, 150) 를 startGame()에 넣고 사용했는데 저는 하다 보니까 그냥 createBall에 넣었네요. 두개 다 똑 같습니다.
다만 나중에 게임에 여러 기능을 추가하다 보면 startGame()을 따로 Call할 일이 많이 생길 수 있는데 그 때는 원본 소스 같이 따로 함수로 관리하는게 더 낫겠죠.
이 소스는 Corona SDK를 만든 회사인 Ansca Mobile에서 제공한 샘플 소스입니다.
아래 유튜브로 가시면 이 샘플 코드에 대한 강좌를 들으실 수 있습니다.
제가 설명했던 것과는 조금 다르게 설명하겠죠?
이것도 들어보시면 도움이 될 거예요.
그럼 다음시간에 뵐께요.
반응형
'Corona SDK > 샘플 코드 분석' 카테고리의 다른 글
코로나로 뱀 기어디니는 효과 내기 (0) | 2012.02.28 |
---|---|
간단하게 눈발 흩날리는 느낌 주기 (2) | 2012.02.16 |
돈 넣고 돈 먹기(야바위) 모바일 게임 만들기 2 (11) | 2012.01.04 |
돈 넣고 돈 먹기(야바위) 모바일 게임 만들기 1 (2) | 2012.01.03 |
내가 그린 선으로 떨어지는 공 받아내기 (2) | 2011.12.31 |
Corona SDK 화면전환 API (Story Board) (4) | 2011.12.23 |
Level 별 Lock 기능 걸고 푸는 법 (0) | 2011.12.15 |
벽돌 깨기 게임 만들기 -2 (2) | 2011.11.30 |
벽돌 깨기 게임 만들기 -1 (3) | 2011.11.29 |
스티브 잡스 추모 앱 (0) | 2011.11.21 |