11월 23일(토) 벌레게임 만들기 - 게임 기획


토요일 아침 다윤이와 함께 게임 기획을 시작하였다. 만들고 싶은 게임이 있으면 아빠가 만들어 줄테니 그림을 그려보라고 시켰다. 그랬더니 뭔가 쓱싹쓱삭 A4용지 위에 그림을 그린다.

다윤이왈 :


“게임 제목은 벌레게임 이야. 거북이도 나오고 파리지옥 같은 식물도 나와. 그리고 물고기는 걸어다녀서 걸어 물고기야. 콩콩이는 콩콩 뛰어다녀. 그리고 총을 쏠수도 있어. 그러면 총알이 나가. 방귀도 뿡뿡 낄수도 있고. 색연필을 먹으면 파워가 생겨. 4개의 생명이 있어.”


이렇게 게임 기획을 끝났다.


구현은 을이면서 아빠인 나의 몫이다.


잠시 바쁘다는 핑계로 접어두고 있었는데, 요즘들어 계속해서 왜 안만들어 주냐면서 빨리 만들어라고 협박을 한다. 그래서 생각난김에 다시 시작하기로 한다.


횡스크롤의 레이싱 게임 형태로 만들면 될 것 같다. A4 용지를 스캔을 해서 최대한 이미지를 살려서 약간의 색을 입히고 만들면 될 것 같다. 글자도 최대한 살려서 폰트로 사용하고. :-)


누군가에게는 뻘짓이지만, 나에게는 엄청난 행복이다.

저작자 표시 비영리
신고
Posted by KraZYeom

회사 커피숍 스마트 테이블에 있던 게임을 얼핏 보고 생각이 들었던건 "와 게임 만들기 쉽겠다." Corona를 한번 접하고 부터는 간단한 게임은 대충 머릿속에 그려졌다. 물론 난 게임 개발자가 아니여서 3D 게임 같은거나 복잡한 것에 대한 개발은 전혀~ 생각이 떠오르질 않는다.


일단 많은 사람들에게 "만들기가 이렇게 쉬워요!" 라고 말해주고 싶다.  


기본 적인 게임 로직은 아주 간단하다. 노란 공이 통통 튀고 구멍난 곳을 피해서 빨간공을 먹으면 된다. 


코드도 나름 간단하다. 공과 벽을 만들고 물리성질을 부여한다. 그리고 전체 화면의 왼쪽이냐 오른쪽이냐에 따라서 공의 x축 왼쪽방향 또는 오른쪽으로 힘을 약간 준다. 


여기서 삽질한 것이 Object:applyForce()그냥 힘을 주면 되는데, transition.to() 함수로 힘에 따라서 위치값을 주고 떨어지는거 계산을 수시간 했다. transition.to()로 강제로 이동시키면 충돌과 같은 물리현상을 무시해 버린다. 벽을 뚫고 공이 지나간다던지... 


암튼 코드는 엄청 간단하다. 


Score 부분은 튕기면 1씩 증가하게 그냥 샘플로 만들었다. 


레벨 개념, 블럭의 성질을 고무, 나무, 유리(깨지는 것) 등등으로 나누고 로직화 하면 진정한 게임이라고 할 수도 있을 것이다. 



display.setStatusBar(display.HiddenStatusBar)

local physics = require("physics")
physics.start()
physics.setGravity(0, 9.8)
physics.setDrawMode("hybrid") 

local ball = display.newCircle(100, 100, 20)
ball:setFillColor(255, 255, 0)
physics.addBody(ball, "dynamic", {density=1.0, friction=0.3, bounce=1.0, radius = 20})
ball.myName = "ball"

local target = display.newCircle(860, 330, 20)
target:setFillColor(255, 0, 0)
physics.addBody(target, "static", {radius = 20})
target.myName = "target"

local blockMaterial = {density=1.0, friction=0.3, bounce=0.0}

local wall = display.newRect(-90, 240, 200, 20)
physics.addBody(wall, "static", crateMaterial)
wall.rotation = 90
wall.myName = "wall"

local block = display.newRect(0, 350, 200, 20)
physics.addBody(block, "static", crateMaterial)
block.myName = "block"

local block2 = display.newRect(350, 450, 200, 20)
physics.addBody(block2, "static", crateMaterial)
block2.myName = "block"

local block3 = display.newRect(700, 350, 200, 20)
physics.addBody(block3,  "static", crateMaterial)
block2.myName = "block"

local wall2 = display.newRect(790, 240, 200, 20)
physics.addBody(wall2, "static", crateMaterial)
wall2.rotation = 90
wall2.myName = "wall"

local score = 0
local scoreLabel = display.newText("Score : " .. score, 10, 10, display.contentWidth, display.contentHeight * 0.5, native.systemFont, 32)

local function updateScore()
    scoreLabel.text = ("Score : " .. score)
end

local function onCollision( event )
    if ( event.phase == "began" ) then
        score = score + 1
        updateScore()
        if event.object2.myName == "target" then
            print("success!!!")
        end
    elseif ( event.phase == "ended" ) then
    end
end

local function moveBallLeftRightTouch( event )
    if event.phase == "began" then
        if event.x < 430 then
            ballx =  -50
        elseif event.x > 430 then
            ballx =  50
        end
        ball:applyForce( ballx, 0, ball.x, ball.y )
        -- transition.to(ball, {time = 1000, x = ballx, onStart=isTest, onComplete=listener1 })
    end
end

Runtime:addEventListener( "collision", onCollision )
Runtime:addEventListener("touch", moveBallLeftRightTouch )


저작자 표시 비영리
신고
Posted by KraZYeom

Cocos2D 또는 Sprite Kit으로 아래 컨셉앱을 개발한다면 어느정도 개발시간이 필요할 것이다. 그런데 Corona를 사용해서 만들면 아주 단순하고 쉽고 명확하다. 주석으로 간단하게 설명을 하도록 하겠다. 1~13까지 하나 하나씩 복사&붙여넣기로 따라해보면 변화되는 모습을 살펴볼 수 있다.





-- 1. 스테이터스 바 숨기기
display.setStatusBar(display.HiddenStatusBar)

-- 2. Box2D를 사용하여 물리현상 적용 
require("physics")
-- 3. 물리 현상을 실행한다. 
physics:start()
-- 4. 중력값을 적용한다. x, y축. 작성하지 않으면 기본 0, 9.8 중력이 적용됨
physics.setGravity(0, 9.8)    

-- 5. 원을 생성해서 화면에 보여준다. display.newCircle([parentGroup,], xCenter, yCenter, radius)
local ball = display.newCircle(30, 200, 20)
-- 6. 원의 색상을 변경한다. 
ball:setFillColor(255, 255, 0)
-- 7. ball에 물리현상을 적용.  움직이므로 dynamic 타입. physics.addBody(object, [bodyType,], {density=d, friction=f, bounce=b, [,radius=r], [,filter=f], })
physics.addBody(ball, "dynamic", {density=1.0, friction=0.3, bounce=0.2, radius=20})

-- 8. 사각형을 생성해서 화면에 보여준다. display.newRect([parentGroup,], left, top, width, height)
local plate = display.newRect(-100, 700, 3000, 20)
-- 9. plate에 물리현상을 적용. 고정된 것은 static 타입. physics.addBody(object, [bodyType,], {density=d, friction=f, bounce=b, [,radius=r], [,filter=f], })
physics.addBody(plate, "static", {density=1.0, friction=0.3, bounce=0.2})

-- 10. for문으로 산모양으로 블럭을 쌓는다. 위치값은 잘 알아서. 색상은 math.random()을 사용하여 랜덤값으로 설정.
for i=0, 4 do
    for j=1, i do
        local block = display.newRect(1000 - i * 100 + j * 40, 700 - j * 100 - j * 30 + 20, 30, 100)
        block:setFillColor(math.random(200, 255), 0, 0)
        physics.addBody(block, "dynamic", {density=1.0, friction=1.0, bounce=0.0})

        if j < i then
            local slate = display.newRect(1000 - i * 100 + (j+1) * 40 + 10 , 700 - (j+1) * 100 - j * 20, 30, 100)
            slate.rotation = 90
            slate:setFillColor(0, math.random(255), math.random(255))
            physics.addBody(slate, "dynamic", {density=1.0, friction=1.0, bounce=0.0})

        end
    end
end

-- 11. 터치 이벤트 함수를 만든다. 추후 이벤트 리스너에서 콜백으로 사용한다. 
-- touch 이벤트 사용 예. 참조. http://docs.coronalabs.com/api/event/touch/phase.html 
function circleTouchEvent( event )
    if event.phase == "began" then
            print( "began phase" )

        display.getCurrentStage():setFocus( ball )
        ball.isFocus = true

    elseif ball.isFocus then
        if event.phase == "moved" then

            print( "moved phase" )

        elseif event.phase == "ended" or event.phase == "cancelled" then
            print( "ended phase" )

            display.getCurrentStage():setFocus( nil )
            ball.isFocus = false
            -- 12. http://docs.coronalabs.com/api/type/Body/applyLinearImpulse.html 참조 
            ball:applyLinearImpulse( event.xStart - event.x, event.yStart - event.y , ball.x, ball.y )
            -- ball:applyForce( event.xStart - event.x, event.yStart - event.y , ball.x, ball.y )

        end
    end

    return true
end

-- 13. 터치 이벤트 함수를 만든다. 추후 이벤트 리스너에서 콜백으로 사용한다. 
ball:addEventListener("touch", circleTouchEvent )


저작자 표시 비영리
신고
Posted by KraZYeom

이 문서는 하루 패드 마크 다운 에디터를 사용해서 작성하고 있습니다.


코로나

코로나 설치

코로나 SDK를 다운로드 하기위해 다운로드 페이지로 이동한다. 코로나는 Mac OS X과 윈도우를 지원한다. 자신의 플랫폼에 맞는 것으로 다운로드 한다. 다운로드 후 이동하는 페이지에 설치 방법을 동영상으로 자세하게 설명하고 있다.

dmg파일을 열어서 안에 있는 폴더를 통째로 Application 폴더로 복사하면 된다.

코로나 실행

Corona Simulator.app을 실행하거나 print() 함수를 사용하여 로그를 보고 싶다면 Corona Terminal을 실행한다.

에디터

코로나를 위한 무료 IDE는 딱히 없다. 그냥 맥과 윈도우에서 모두 사용할 수 있는 Sublime Text 2를 사용하는 것을 추천한다. Sublime Text 2용 Autocomplete 플러그인이 있다. TextMate 용으로 잘 만들어 놓은 Corona SDK 자동완성 번들이 오픈소스로 있다. 다운로드 (개발자님 감사합니다) Sublime Text 2 사용법에 대해서는 다루지 않을 것이다.

사용 방법은 아래와 같다.

  1. 일단 다운로드 받아서 압축을 푼다.
  2. Finder 에서 Cmd + Shift + G (Go)를 눌러서 ~/Library/Application Support/Sublime Text 2/Packages/Lua 위치로 이동한다.
  3. Corona-SDK.tmbundle 디렉토리의 Syntaxes 와 Snippets 디렉토리 안의 모든 파일을 위의 디렉토리로 복사 또는 옮기기를 한다.
  4. 그리고 Sublime Text 2를 재시작 한 후, Cmd+Shift+P 를 눌러서 syntax를 lua로 변경한다.

이후 아래 그림 2, 그림 3과 같이 자동완성 기능을 사용 할 수 있다.

그림 1

[그림 1]. lua로 syntax 변경 

그림 2

[그림 2] 그림 3

[그림 3] 

프로젝트 만들기

Corona Simulator.app로 실행을 하면 [그림 4]과 같이 코로나 SDK 툴이 나타난다. 새로운 프로젝트를 생성하기 위해서는 ‘New Project‘ 버튼을 클릭한다. [그림 5] 처럼 Create New App 팝업 창이 뜨고 App Name에는 앱 이름을 ‘Cat Runner‘으로 넣고, Choose a Template에서는 ‘Blank‘를 선택한다. Screen Size는 고해상도 iPhone에 맞게 ‘640x960‘으로 변경한다. Default Orientation은 가로화면 모드인 ‘Sideways‘로 선택한다. Next 버튼을 클릭하면 [그림 6] 처럼프로젝트가 성공적으로 만들어졌다는 메세지가 나타나고, 파인더에서 생성한 파일을 볼지, 에디터에서 바로 편집을 할지 선택을 한다. Open in Editor…를 선택해서 바로 편집에 들어가도록 하자.


[그림 4]

[그림 5]

[림 6]

프로젝트를 생성하면 기본적으로 3개의 파일이 생성된다. 빌드를 위한 build.settings, 애플리케이션의 기본 설정을 위한 config.lua, 그리고 구현을 위한 main.lua가 있다. main.lua가 애플리케이션의 기본 시작하는 곳이다.

배경화면

많은 러너 게임들이 그렇듯이 플레이어 케릭터가 앞으로 나가는 것 처럼 보이지만, 자세히 살펴보면 케릭터는 고정되어 있고 배경화면이 움직인다. 더 완벽하게 보이기위해서 가까이에 있는 배경은 빨리 움직이고, 멀리 있는 배경은 조금 더 천천히 움직인다.

배경화면 넣기

화면에 불피요한 status bar를 제거하기 위해 아래 코드를 넣자.

display.setStatusBar( display.HiddenStatusBar )

저장을 하면 바로 시뮬레이터에서 변경된 것을 확인 할 수 있다. 코로나에서는 파일 편집을 하고 저장하는 순간에 다시 실행해서 바로 반영 한다. Lua가 스크립트언어여서 따로 빌드 과정이 필요없다.

-- 이미지를 추가하는 함수는 아래와 같다. 

--display.newImage( [parentGroup], "filename", [baseDirectory], left, top, isFullResolution )
--아래 처럼 이미지 파일만 넣고 위치 값을 따로 설정 할 수 있습니다.

-- 배경화면 하늘
local background = display.newImage( 'images/background.png', true)
background.x = 400
background.y = 270

-- 배경화면 산
local background21 = display.newImage( 'images/background2.png', true )
background21.x = 600
background21.y = 450

local background22 = display.newImage( 'images/background2.png', true )
background22.x = 1800
background22.y = 450

-- 배경화면 나무
local background31 = display.newImage( 'images/background3.png', true )
background31.x = 600
background31.y = 540

local background32 = display.newImage( 'images/background3.png', true )
background32.x = 1800
background32.y = 540

고정된 하늘은 하나의 배경화면만 있고, 산과 나무는 2개씩 한쌍으로 준비한다. [그림 2]와 같이 하나의 배경화면을 화면 밖에 위치시키고 동시에 움직이고 첫 번째 배경화면이 화면 영역밖으로 벗어나면 다시 두 번째 배경화면의 뒤에 위치시킨다. 이것을 계속해서 반복하면 배경이 무한 반복으로 움직이는 것 처럼 보인다.

배경화면 무한대로 움직이기

cocos2d에서 update() 함수로 스케줄러를 호출하는 것 처럼 코로나에서도 비슷하게 구현하면 된다.

아래와 같이 update() 함수를 하나 생성하고 타이머를 하나 만들어서 만들어진 update() 함수를 무한반복으로 호출 하면 된다.

function update()
    updateBackgrounds()
end

local speed = 1

function updateBackgrounds()
    background21.x = background21.x - (5 * speed)
    background22.x = background22.x - (5 * speed)
    background31.x = background31.x - (15 * speed)
    background32.x = background32.x - (15 * speed)

    if background21.x < -600 then
        background21.x = 1800
    end

    if background22.x < -600 then
        background22.x = 1800
    end    

    if background31.x < -600 then
        background31.x = 1800
    end

    if background32.x < -600 then
        background32.x = 1800
    end    

end

--타이머로 1ms에 한번 씩 update 함수를 무한반복(-1)해서 호출한다. 
timer.performWithDelay(1, update, -1)
  1. 우선 update() 함수를 생성해서 배경화면 변경을 updateBackgrounds() 함수를 호출한다.
  2. updateBackgrounds() 함수에서는 배경화면 각각에 다른 속도 가중치를 빼준다. 멀리있는 산은 천천히 움직이게 작은 값을 할당하고, 가까이 있는 나무는 빨리 움직이게 큰 값을 할당한다. 그리고 추후에 레벨에 따른 속도 변경을 위해서 speed 변수 값을 곱해서 뺀다.
  3. 각각의 배경화면이 기기에서 보이는 화면 영역을 벗어나면 가장 뒤로 보낸다. 이것을 반복한다.
  4. 타이머를 하나 만들어서 1ms에 한번 씩 update() 함수를 무한반복(-1)해서 호출한다.

이렇게 하면 [동영상 1] 처럼 배경화면이 무한반복되서 움직이는 것을 확인할 수 있다.


[동영상 1]


저작자 표시 비영리
신고
Posted by KraZYeom

이 문서는 하루 패드 마크 다운 에디터를 사용해서 작성하고 있습니다.

들어가며

올해 초에 블로그에 cocos2d로 드래곤 라이더 만들기를 연재 후, 책으로 만들어져서 곧 출판을 합니다. 뭔가 다음 삽질을 하기 위해서 코로나(corona) 삽을 들었습니다.

cocos2d는 iOS으로만 빌드를 할 수 밖에 없었고(물론 cocos2d-x로 만들면 되긴만), 물리 게임을 만들기 위해서는 많은 삽질이 필요합니다. SpriteKit이 나와서 간편하게 iOS용 간단한 물리 게임을 만들수도 있습니다. 또 iOS용으로만 빌드가 되지 않는 단점이 여전히 남아 있습니다. 그래서 스크립트 언어 기반의 멀티플랫폼 빌드를 지원하는 corona로 정하고 삽을 들었습니다.

물론 저는 게임의 ‘ㄱ’도 모르는 개발자 탈을 쓴 개발자 입니다. Lua도 모르고, corona로 모릅니다. 게임 개발 방법론(?)은 더더욱 모릅니다. 삽질을 하면서 개발 과정을 블로깅 할 것이며, 틀린점이 있으면 언제나 지적 부탁드립니다. 조언도 좋습니다. 사운드 효과, 배경 음악, 이미지 등등 많은 도움을 주셔도 상관 없습니다.

카카오톡 게임의 인기를 받고 있는 ‘러너’ 시리즈 종류의 게임을 한 번 만들어 보도록 하겠습니다.

Lua 기초

루아는 가벼운 스크립트 언어이다. ‘달’을 뜻하는 포루투칼어의 단어이며, 1993년 브라질의 리우 데자네이로에 있는 교황청 대학교의 컴퓨터 그래픽 기술 그룹 회원인 Luiz Henrique de Figueiredo, 호베르투 이에루잘림스시와 Waldemar Celes가 만들었다.

코로나 SDK에서는 루아 언어를 사용한다. 루아 언어를 전부 몰라도 상관없다. 그때 그때 필요할 때만 찾아 사용해도 괜찮다. 필수적인 부분만 집고 넘어가도록 하자. 더 많은 것을 살펴보고 싶으면 루아 공식 페이지를 참고하자. 아래 기본 문법만 알고 있어도 크게 문제가 되지 않을 것이다.

기본적으로 괄호()와 세미콜론(;)을 사용하지 않는다. 물론 사용해도 상관은 없다.

-- 이것은 주석이다
print("디버그 등을 위한 콘솔 출력")

a = 1 -- 글로벌 변수
local b = 1 -- 로컬 변수


-- 반복문
for 1, 10, 1 do -- 1부터 10까지 1씩 증가한다

    --code

end

-- 비교문
if i == 1 then

    --code

elseif then

    --code

else

    --code

end


-- 함수
function name( arg )

end

math.randomseed(os.time()) -- 랜덤 시드값 설정
math.random() -- float
math.random(maxNum) -- 1부터 maxNum까지 정수 생성
math.random(minNum, maxNum) -- 최소, 최대값의 범위에서 임의의 정수를 생성한다


저작자 표시 비영리
신고
Posted by KraZYeom