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

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형
어제 했던 소스는 아래와 같습니다.

require ("physics")

function main()
    setUpPhysics()
    createBall()
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)
end

main()


정리하자면 공을 만들고 그 공에 physics 엔진을 적용하고 움직이는 것 까지 했습니다.

오늘은 벽을 만들어서 그 벽에 공이 튀게 만들겠습니다.

일단 함수 이름은 createWalls()로 하고 사각형으로 그려보겠습니다.

function createWalls()
    local wallThickness = 10
    -- Left wall
    local wall = display.newRect( 0, 0, wallThickness, display.contentHeight )
    -- Top wall
    wall = display.newRect(0,0, display.contentWidth, wallThickness)
    -- Right wall
    wall = display.newRect(display.contentWidth - wallThickness, 0, wallThickness, display.contentHeight)
    -- Bottom wall
    wall = display.newRect(0, display.contentHeight - wallThickness, display.contentWidth, wallThickness)
end

벽 두께는 10픽셀로 합니다.

그리고 main()함수에서 이 createWall() 함수를 Call 하세요.


이제 사방에 벽이 생겼습니다.
실행하면 공이 벽을 지나쳐서 갑니다.
저 벽에 공이 튀게 만드려면 이 wall들에 addBody를 해 주면 됩니다.

지금까지의 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createWalls()
    createBall()
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)
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

main()

이제 실행하면 공이 계속 벽면에 튀게 됩니다.

여기서 유심히 볼 점은 벽면 모두 변수 이름이 wall입니다. 이 변수를 한번 만들어서 계속 재활용 한 겁니다.
그리고 맨 마지막에 bottom Wall을 만들었고 type을 bottomWall이라고 명명했습니다.
이는 다른 세 벽은 공이 맞고 튀기만 하면 되고 아래 벽엔 맞으면 다른 핸들링을 하기 위해서 이렇게 한 겁니다.

이 부분은 나중에 구현 해 보겠습니다.

이제 아래에 paddle을 한번 만들어 볼까요?
밑에 적당한 위치에 적당한 길이의 사각형을 만들겠습니다.

function createPaddle()
    local paddleWidth = 100
    local paddleHeight = 10
    local paddle = display.newRect( display.contentWidth / 2 - paddleWidth / 2, display.contentHeight - 50, paddleWidth, paddleHeight )
end

보시는 대로 왼쪽 오른쪽 길이(Width)는 100픽셀이고 높이는 10픽셀인 사각형을 그리고 이것을 가운데에 위치시킵니다.
실행 시키면 아직까지 paddle에 physics를 적용하지 않았기 때문에 공은 그냥 통과합니다.
여기에 physics를 아래와 같이 적용하세요.
physics.addBody(paddle, "static", {friction=0, bounce=1})

이러면 공이 지나가다가 이 paddle에 맞으면 튀게 됩니다.

여기에 유저가 paddle을 움직일 수 있도록 하는 기능을 다뤄야 하는데요.
이 기능은 다음 강좌에서 하게 될 겁니다.

이번엔 벽돌들을 만들어 볼까요?
createBricks() 함수를 만드세요.

그리고 사각형을 만들께요. Width는 40 Height는 20으로 하겠습니다.
    local brickWidth = 40
    local brickHeight = 20
local brick = display.newRect( 50, 50, brickWidth, brickHeight )
brick:setFillColor(50, 250, 100, 255)

전체 소스는 아래와 같습니다.
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)
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})
end

function createBricks()
    local brickWidth = 40
    local brickHeight = 20
    local brick = display.newRect( 50, 50, brickWidth, brickHeight )
    brick:setFillColor(50, 250, 100, 255)
end

main()

이제 벽돌이 하나 생겼습니다.
저 벽돌에 공이 맞았을 때 튀게하려면 지금까지 다른 객체에 했던 식으로 addBody를 하면 됩니다.

그런데 여기서 생각해야 할 점은 벽돌은 1개가 아니라 수십개가 만들어 져야 합니다.
저런식으로 하나하나 각각 위치와 색을 지정해서 벽돌을 만들어도 됩니다.
그런데 그러면 프로그램 답지가 않습니다.

for문을 사용해서 간단하게 벽돌들을 만들겠습니다.

저런 벽돌을 좌우로 6개씩 4줄 총 24개를 만드는 로직을 구현하겠습니다.
아까 벽돌의 두께와 높이는 40,20으로 정했구요.
numOfRows=4, numOfCols = 6 을 추가하겠습니다.

그리고 첫 시작점은 아래와 같이 잡습니다.
local topLeft = {x= display.contentWidth / 2 - (brickWidth * numOfCols ) / 2, y= 50}

이 벽돌은 처음 1줄 6개를 그리고 그 다음 줄 6개 그리는 식으로 4번 작업을 할 겁니다.
그 로직은 아래와 같습니다.
    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)
        end
    end


벽돌색은 Random하게 지정했습니다.
여러분 취향대로 라인별로 색을 지정해도 되고 열 별로 지정해도 되고 마음대로 바꾸셔도 됩니다.

여기에 이 벽돌을 맞고도 공이 튀어나오게 하려면 각 벽돌에 addBody를 하면 됩니다.
그리고 type은 destructible로 명명합니다.
나중에 무딪히면 없애야 되거든요.

벽돌에 addBody를 한 오늘의 최종 소스코드는 아래와 같습니다.

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)
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})
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()

이제 공이 벽돌에 부딪히면 벽돌이 없어지고 아래 벽에 부딪히면 게임이 새로 시작하고 paddle을 유저가 좌우로 움직이도록 하는 작업이 남았습니다.

내일은 이 작업에 대해 알아보겠습니다.

반응형


반응형

오늘서 부터 코로나 SDK로 간단한 벽돌깨기 게임을 만들어 보도록 하겠습니다.
몇회 정도 할지는 잘 모르겠습니다. 처음 코로나를 접하시는 분들도 만드실 수 있도록 그리고 프로그래밍 경력이 거의 없으신 분들도 따라올 수 있도록 하나하나 순서대로 코딩하고 화면으로 확인하고 하면서 진행하려고 합니다.
이 강좌는 소스분석 카테고리에 넣을 강좌로 준비했습니다.
벽돌깨기 게임 공개 소스를 분석 하는데, 그냥 공개된 소스만 갖고 분석하는 것 보다 실제 게임을 만드는 순서로 코드를 하나하나 완성해 가면서 해 보려구요.

게임을 완료하게 되면 아래와 같은 화면이 실행 됩니다.


모두 알고 있듯이 저 공은 계속 움직이면서 물체에 부딪히면 튕기게 됩니다.
그리고 공이 벽돌에 맞으면 벽돌은 없어지게 되구요.
바닥에 맞으면 공은 없어지게 됩니다. 다만 아래에 있는 스틱에 맞으면 없어지지 않고 튕겨서 다시 위로 올라가구요.

이 강좌에서는 여기까지만 구현 해 보겠습니다.
이외에 점수 올라가고 공 갯수 제한하고 하는 것은 각자 쉽게 하실 수 있을 겁니다. 이번에 진행되는 강좌를 잘 숙지하시면요...

일단 공이 움직이고 튕기는 것은 코로나 SDK의 physics 엔진을 사용하겠습니다.
그리고 각 객체와 움직임 그리고 이벤트에 대한 핸들링은 함수를 사용해서 구현할 거구요.

일단 여기서 객체들을 그 그룹별로 한번 나눠보죠..
벽, 벽돌들, 공, 공을 튀어내는 stick(paddle)
이렇게 4가지 정도 눈에 보이는 객체 그룹이 있습니다.
그리고 physics엔진을 이용한다고 했구요.
그러면 대충 함수들을 나눠보면
setUpPhysics(),createWalls(),crateBricks(),creatBall(),createPaddle() 이렇게 나눌 수 있습니다.
이 함수들을 만들거구요. 이 함수들은 main()함수에 넣어서 한꺼번에 Call을 할 겁니다. 앱을 많이 만들다 보면 아시겠지만 각 객체별로 함수를 만들고 필요에 따라 이 함수들을 Call하는 함수를 만들어서 구현하도록 디자인 하면 나중에 각 객체들을 콘트롤 하는데 좋습니다.

자 그럼 이렇게 대충 디자인을 하고 개발에 들어갈까요?
제일 먼저 각자 적당한 폴더를 만들고 그 폴더 안에 main.lua파일을 만드세요.
그리고 그 파일 안에 코딩을 시작하겠습니다.

각자 스타일에 따라 다르겠지만 저는 우선 뭔가 눈에 보이는 것 부터 하고 싶네요.
제일 중요한 공부터 만들어 보죠.

일단 createBall() 함수를 만듭니다.
function createBall()

end
이렇게 함수 선언을 하고 닫기 까지 합니다.
그리고 공을 그립니다.
function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

이렇게 하고 실행을 하면 화면에 아무것도 안 나옵니다. 저 함수를 call한 곳이 없기 때문이죠.

앞으로 만드는 함수들은 main()함수에 넣어서 관리를 할 테니까 main()함수를 만들어서 이 createBall()함수를 call 하세요.
function main()
    createBall()
end
그리고 main.lua 맨 아래에서 이 main() 함수를 call 하세요.
function main()
    createBall()
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

main()

자 이러면 화면 한 가운데에 반지름이 10픽셀인 하얀 공이 나올 겁니다.


여기까지 됐구요. 그러면 이제 공을 움직여 보겠습니다.
공을 움직이는 것은 코로나의 physics엔진을 사용하기로 했습니다.
이 물리엔진을 사용하려면 우선 physics를 require해야 합니다.
require ("physics")
그리고 physics를 시작합니다.
physics.start()
Corona DOC 카테고리에 있는 physics강좌를 보시면 아시겠지만 기본적으로 코로나 물리엔진은 디폴트 값으로 (0,9.8)의 중력 값을 가집니다.
벽돌깨기 게임은 중력값이 필요 없으므로 이를 0,0 으로 세팅합니다.
physics.setGravity(0,0)
여기서 physics setUp도 함수로 따로 관리하겠습니다.
require만 빼놓고 나머지 두라인을 setUpPhysics() 함수 안에 넣고 이 함수를 main()함수에서 Call 하겠습니다.
require ("physics")

function main()
    setUpPhysics()
    createBall()
end

function setUpPhysics()
    physics.start()
    physics.setGravity(0,0)
end

function createBall()
    ball = display.newCircle( display.contentWidth / 2, display.contentHeight / 2, 10 )
end

main()
이제 이 공에 addBody를 하고 움직여 보겠습니다.
createBall()안에 공을 addBody 하는 코드를 아래와 같이 집어 넣습니다.
physics.addBody(ball, "dynamic", {friction=0, bounce = 1, radius=ballRadius})

그리고 실행하면 아무 변화가 없습니다. 여기서 setGraivity값을 0,0에서 0,9.8로 바꿔볼까요?

그러면 공이 아래로 떨어질 겁니다. y 좌표에 9.8의 중력값이 적용 됐기 때문입니다.
이 중력값 적용 대신에 공을 움직일 수 있는 방법은 뭘까요?
setLinearVelocity를 이용하면 됩니다.
다시 중력값을 0,0으로 고치고 createBall() 안에 ball:setLinearVelocity(75, 150) 코드를 추가로 집어 넣습니다.

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

그러면 이 공이 오른쪽 아래 방향으로 움직이게 됩니다.


지금은 공이 화면 밖으로 나가버리고 끝이 납니다.
오늘 소스는 아래와 같습니다.
require ("physics")

function main()
    setUpPhysics()
    createBall()
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)
end

main()

벽을 만들어 놓고 이 벽에 튕기게 하면 공이 화면안에서 계속 튀면서 다니겠죠?

다음 시간엔 벽을 만들고 이 벽들을 addBody해서 공이 튕기도록 하겠습니다.
벽뿐만 아니라 block과 paddle도 만들어서 이 앱에서 필요한 모든 객체들을 화면에 나타나도록 하겠습니다.

그럼 다음 시간에 뵈요.
반응형

드래그 하기 기초

2011. 11. 25. 01:23 | Posted by 솔웅


반응형

오늘은 Thanks Giving day라서 휴일입니다.

사무실에 안 가고 집에서 글을 쓰게 됐네요.
근데 여유있게 글을 쓸 상황은 아니군요.

점심 초대를 받아서 좀 있다 나가야 하거든요.

오늘은 간단하면서도 아주 자주 쓰이는 테크닉을 정리하겠습니다.

앱을 만들 때 특히 게임 같은 앱을 만들 때 드래깅 기술을 많이 사용하게 됩니다.
가장 기본적으로 알아 둬야 할것은 아래와 같습니다.
touch 이벤트 리스너를 사용하기
began에서 현재 위치 저장하기
moved에서 현재 위치 바꿔주기

이 정도만 확실하게 알아 두시면 됩니다.


스크린에 사각형을 그리고 저 사각형을 드래그 하는 앱입니다.
아래 소스코드 참조하세요.
-- create object
local myObject = display.newRect( 0, 0, 100, 100 )
myObject:setFillColor( 255 )

-- touch listener function
function myObject:touch( event )
    if event.phase == "began" then

        self.markX = self.x -- store x location of object
        self.markY = self.y -- store y location of object

    elseif event.phase == "moved" then

        local x = (event.x - event.xStart) + self.markX
        local y = (event.y - event.yStart) + self.markY
       
        self.x, self.y = x, y -- move object based on calculations above
    end
   
    return true
end

-- make 'myObject' listen for touch events
myObject:addEventListener( "touch", myObject )

우선 흰색 사각형을 그리구요.
그 다음 touch 이벤트 리스너에서 호출할 함수를 만듭니다.
맨 아래 부터 부시면 이 myObject라는 객체에 touch 이벤트 리스너를 달았다는 것을 잘 보세요.

이제 myObject라는 함수를 보겠습니다.

began 일 때 해당 객체(myObject)의 위치를 정합니다.
moved일 때 began일 때의 위치 event.xStart 를 현재 위치에서 빼고 그러니까 이동 거리를 구하고 객체의 위치 self.markX를 더해 줍니다.
그리고 그 위치값을  myObject 객체의 위치값으로 대입합니다.
그러면 이동하게 됩니다.

아주 간단합니다. 하지만 반드시 알고 있어야 하는 겁니다.

반응형