✨기본 형식

widget.newButton( options )

 

✨문법( options 부분에 들어갈 것들 )

  • 이하의 요소를 등호(=)로 할당해준다.
  • ( ) 괄호 안에 { } 괄호로 묶어서 작성한다. (응용 예시 참고)
  • 각 요소를 병기할 때는 콤마(,)로 나눈다. 엔터로 행을 바꿔도 잘 인식된다.
  • id :: 이 오브젝트를 가리키는 고유한 이름. (예: id = "button1")
  • width, height :: 이 오브젝트의 가로 · 세로 길이
  • defaultFile :: 버튼을 누르지 않았을 때 보여줄 이미지
  • overFile :: 버튼을 눌렀을 때 보여줄 이미지
  • onPress :: 리스너(주로 함수)를 할당해준다. 이 버튼이 눌리는 순간 실행될 작업.
  • onRelease :: 리스너(주로 함수)를 할당해준다. 이 버튼을 눌렀다가 떼는 순간 실행될 작업.
  • onEvent :: 리스너(주로 함수)를 할당해준다. 이 버튼을 누르는 동안 실행될 작업. (onPress+onRelease)

 

✨응용

-- 코드 최상단에 "widget" 라이브러리를 불러와야 함

local widget = require( "widget" ) -- 새로 불러온 widget 라이브러리
local composer = require( "composer" ) -- 기본적으로 있는 부분
local scene = composer.newScene()     -- 기본적으로 있는 부분
.
.
.

-- function scene:create( event ) 아래 본인이 원하는 위치에 작성

local button = widget.newButton({ 
defaultFile = "image/buttonDown.PNG", 
width = 700, height = 400, 
overFile = "image/buttonDown.PNG", 
onRelease = panEvent })

-- 이 버튼의 경우, 눌렀다가 뗄 때 panEvent라는 함수를 실행시킨다. (별도로 작성)

 

✨그 외

name의 사용법

  • 오브젝트이름.name = "이름"
  • 주로 배열 요소 하나하나에 유의미한 명칭을 붙일 때 사용한다. (예: button[1]은 "left", button[2]는 "right")
  • if 문에서 배열 요소를 처리하기가 용이해진다.
  • 만약 클릭된 오브젝트의 이름을 리턴받고자 한다면 event.target.name으로 받아온다.

개요

게임개발동아리에서 약 3~4주간 Lua언어와 Solar 2D 사용법을 학습하였다.

점검 차원으로 그동안 학습한 내용들을 토대로 자신만의 미니게임을 만들어 보는 시간을 가졌다.

나는 쥬니버 플래시게임에서 흔히 볼 수 있는 날아다니는 장애물 피하기 + 떨어지는 아이템 수집 형식을 골랐다.

 

프로젝트 기간

2019.01.03~2019.01.19

 

✨플레이 영상

실패 영상으로 촬영하였다.

 

✨구현 내용 및 코드

좌우 화살표(◀, ▶) 버튼을 클릭하여 캐릭터를 움직인다.

벽을 맞고 튕겨다니는 가시열매에 맞으면 점수가 20점 깎이고,

캐릭터가 하늘에서 떨어지는 사과를 받으면 100점이 추가된다.

제한 시간(1분) 내에 1500점 이상을 달성하면 클리어.

가시열매와 사과가 충돌하면 사과는 사라져버리니 주의.

 


선언부

  • 이 게임을 구현하는 데 가장 중요한 역할을 하는 physics 라이브러리를 호출한다.
  • physics 물리엔진을 사용하는 객체들은 모두 시뮬레이션 구동 후 자동으로 상호작용한다.
  • 모든 physics 시뮬레이션을 실행하기 앞서, 반드시 physics.start() 함수를 호출해야 한다.
math.randomseed( os.time() )

local widget = require( "widget" )
local composer = require( "composer" )
local physics = require("physics")
physics.start()
physics.setGravity(0, 9.8*0.75) //중력가속도

local scene = composer.newScene()
local i, j, score = 0, 0, 0

-- GUI
local background
local gameUI = {} //게임에 필요한 UI 오브젝트를 배열에 담아서 사용

//가시열매가 맞고 튕겨나갈 수 있는 벽을 생성하는 함수
function createWalls() 
    local wallThickness = 10

    //Left wall
    local wall = display.newRect(0, display.contentHeight/2, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=0, bounce = 1})
    //Top wall
    wall = display.newRect(display.contentWidth/2, 0, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=1, bounce = 1})
    //Right wall
    wall = display.newRect(display.contentWidth - wallThickness + 10, display.contentHeight/2, wallThickness, display.contentHeight)
    physics.addBody(wall, "static", {friction=1, bounce = 1})
    //Bottom wall
    wall = display.newRect(display.contentWidth/2, display.contentHeight - wallThickness + 10, display.contentWidth, wallThickness)
    physics.addBody(wall, "static", {friction=1, bounce = 1})

    // bounce 값이 한 쪽 벽에서만 커지면 가속도가 붙는다 ==> 속도 무한대로 증가!
    // 따라서 bounce 값은 4면에서 모두 일정하게 유지
end

 

CreateApple() 함수

  • 임의의 위치에 사과를 생성하여 드롭한다.
  • 오브젝트 간의 충돌효과를 위해 physics.addBody를 적용한다.
  • 사과는 땅으로 가까워질 수록 투명해진다.
  • 사과에 collision이라는 EventListner를 추가해주었다. 이제 충돌을 인식할 수 있다.
function createApple() // 새로운 사과 생성

        local apple = display.newImageRect("Fruit/나며꾼사과.png", 70, 70)
        apple.x, apple.y = player.x + math.floor(math.random(-500, 500)), player.y/8 // 위치는 랜덤
        apple.alpha = 1

        physics.addBody(apple, "dynamic", {friction = 0, bounce = 1.25})
        apple:addEventListener("collision", apple)

        // 만약 사과가 플레이어와 충돌(collision)한다면? ==> 점수 획득

        apple.collision = function(self, event)
            if(event.other.type == "destructible") then
                self:removeSelf() // 사과 사라짐
                score = score + 100 // 점수 증가
                gameUI[7].text = string.format("%05d", score) // 점수를 다섯자리로 표시
            end
        end

        local moveApple = transition.to( apple, { time=2500, alpha=0.2, y=(player.y+500), onComplete = createApple } )
    end

    local onTimerComplete = function(event)
        createApple()
    end

 

Main 함수

  • 플레이어 캐릭터와 장애물(가시열매)를 배치하고, 오브젝트 간의 충돌효과를 위해 physics.addBody를 적용한다.
  • 사과와의 collision 이벤트를 관리하기 위해 플레이어 캐릭터에 destructible타입을 지정해주었다.
  • 이렇게 type을 지정해주면 오브젝트가 무슨 타입인지 식별하고, 타입별로 다른 액션을 취할 수 있게 된다.
  • 가시 열매에 collision이라는 EventListner를 추가해주었다. 이제 충돌을 인식할 수 있다.
    local player = display.newImageRect("Fruit/나며꾼.png", 300*0.6, 480*0.6)
    player.x, player.y = display.contentWidth/2-100, display.contentHeight/2+200
    player.alpha = 1

    physics.addBody(player, "static", {friction = 0, bounce = 1})
    player.type = "destructible"

    local thorn = display.newImageRect("Fruit/나며꾼가시.png", 90, 90)
    thorn.x, thorn.y = player.x+200, player.y/8
    thorn.alpha = 1

    physics.addBody(thorn, "dynamic", {friction = 0, bounce = 1})
    thorn:addEventListener("collision", thorn)

    // 만약 플레이어가 가시열매와 충돌한다면?

    thorn.collision = function(self, event)
        if(event.other.type == "destructible") then
            score = score - 20 // 점수 감소
            gameUI[7].text = string.format("%05d", score) // 점수를 다섯자리로 표시
        end
    end

 

✨소감

아무튼 이런 느낌

좋았던 점

  • 학부생 1학년 과정을 막 마친 수준에서 만들게 된 첫 게임이다. 루아 문법이 간단해서 진입장벽이 높지는 않았다.
  • 이제 겨우 C 문법 기초를 떼고 Java를 드문드문 배우는 수준이었던지라 API라는 것 자체에 익숙하지 않았다. 그렇기에 Solar 2D API Reference 사이트를 열심히 뒤져가며 한땀한땀(...) 만든 경험은 굉장히 값지다고 생각한다.
  • 캐릭터와 오브젝트, 시작화면과 결과화면까지 직접 그려서 게임에 적용해보는 과정이 큰 성취감을 느끼게 해주었다. 
  • 이 경험을 바탕으로 Unity 게임 제작에도 도전해볼 용기를 얻었다. (하지만 C# 앞에서 처참하게 패배했다.)

아쉬운 점

  • 다시 말하지만 막 Java를 배운지 얼마 되지 않은 시기에 만든 게임이다. 객체 지향 프로그램을 구현하지 못했던 탓에 Main 스크립트 파일에 모든 기능을 때려넣었고, Main 파일이 불필요하게 길고 복잡했다.
  • 자료구조데이터베이스 관련 지식이 없었기 때문에, 단순한 미니게임 이상의 수준을 구현할 수는 없었다.
  • 실력 부족으로 인해 누락된 기능이 몇 가지 있다. (결과 화면에서 처음으로 돌아가기, 키보드로 이동하기 등)
  • 이제는 이 기능들을 구현할 수 있을 정도의 실력은 되었으니, 기회가 된다면 부족한 부분을 보완해서 한 번 더 만들어보고싶다.  

+ Recent posts