2015년 7월 11일 토요일

corona sdk 로 슈팅 게임 만들기(최종회)


* 해야할 것 *

배경스크롤
주인공 이동
무기발사
적 이동
스테이지
점수 처리
시작처리
종료처리
적유닛 생성
이미지 사용할 것:http://m484games.ucoz.com/index/shoot_39_em_up_gfx/0-38
참고 소스:http://www.tandgapps.co.uk/resources/tutorial-space-shooter-in-240-lines/


시작처리,종료처리 
전체적으로 스토리 보드로 만듭니다.
지금까지 모든 소스입니다.

호출관계는 아래와 같습니다.
main.lua -> start.lua -> game.lua -> restart.lua -> game.lua -> restart.lua ....




main.lua
starfield를 만들고 start storyboard를 시작합니다.

display.setStatusBar( display.HiddenStatusBar )
bgGroup = display.newGroup()
g_score = 0

local storyboard = require "storyboard"
local _W = display.contentWidth
local _H = display.contentHeight


local function loadBGImg()
  stars1 = display.newImageRect("star1_480_800.png", 480, 800)
  stars1.x = _W*0.5; stars1.y = _H*0.5
  bgGroup:insert(stars1)
  stars2 = display.newImageRect("star2_480_800.png", 480, 800)
  stars2.x = _W*0.5; stars2.y = _H*0.5-800
  bgGroup:insert(stars2)
end

function moveStarField()
  --Move the starfields.
  stars1:translate(0,2)
  stars2:translate(0,2) 
  if stars1.y >= (_H*0.5)+800 then
    stars1.y = (_H*0.5)-800
  end
  if stars2.y >= (_H*0.5)+800 then
    stars2.y = (_H*0.5)-800
  end
end

function gameLoop(event)
  moveStarField()
end

loadBGImg()
Runtime:addEventListener("enterFrame", gameLoop)

storyboard.gotoScene( "start" )


start.lua
로고를 화면에 출력하고 시작 버튼을 활성화 시킵니다.

local storyboard = require ("storyboard")
local scene = storyboard.newScene()

local _W = display.contentWidth
local _H = display.contentHeight

-------------------------------------------------------
local imgGameStart
local imgTitle

local function startGame(event)
     if event.phase == "ended" then
  storyboard.gotoScene("game")
     end
end
-------------------------------------------------------
function scene:createScene(event)
 local screenGroup = self.view
 imgTitle = display.newImageRect("starfield.png",240,45)
 imgTitle.anchorX = 0.5
 imgTitle.anchorY = 0.5
 imgTitle.x = display.contentCenterX
 imgTitle.y = display.contentHeight*0.2
 screenGroup:insert(imgTitle)

 imgGameStart = display.newImageRect("gamestart.png",240,45)
 imgGameStart.anchorX = 0.5
 imgGameStart.anchorY = 0.5
 imgGameStart.x = display.contentCenterX
 imgGameStart.y = display.contentHeight*0.8
 screenGroup:insert(imgGameStart)
end

function scene:enterScene(event)
 imgGameStart:addEventListener("touch", startGame)
end

function scene:exitScene(event)
 imgGameStart:removeEventListener("touch", startGame)
end

function scene:destroyScene(event)

end

scene:addEventListener("createScene", scene)
scene:addEventListener("enterScene", scene)
scene:addEventListener("exitScene", scene)
scene:addEventListener("destroyScene", scene)

return scene


game.lua
지금까지 대부분의 내용이 들어가 있습니다.
주인공 움직임 부분이 transition.to에서 바뀌었습니다. transition으로 하게되면 동작이 부자연스러운 현상이 벌어집니다.

local storyboard = require ("storyboard")
local scene = storyboard.newScene()
local physics = require ("physics") --Require physics
physics.start(); physics.setGravity( 0, 0 ) --Start physics

-----------------------------------------------
--*** Set up our variables and group ***
-----------------------------------------------
local enemyGroup = display.newGroup()
local weaponGroup = display.newGroup()
local expGroup = display.newGroup()
local playerGroup = display.newGroup()
local fgGroup = display.newGroup()

local _W = display.contentWidth
local _H = display.contentHeight

local stars1, stars2 --Background moving stars
local spawnInt = 0 --Gameloop spawn control
local spawnIntMax = 30 --Gameloop max spawn
local spawned = 0 --Keep track of enemies
local spawnedMax = 10 --Max allowed per level
local enemySpeed = 7 --How fast the enemies are
local wave = 1
local ship
local gameIsActive = true
local fireTimer
local sheetExp
g_score = 0
local goto_x=-1;goto_y=-1

local function loadImgs()
  local sheetOptions =
  {
    width = 20,
    height = 20,
    numFrames = 6
  }
  sheetExp = graphics.newImageSheet( "exp_20_20_6.png", sheetOptions )
end


local function loadTexts()
 scoreText = display.newText("Score: "..g_score, 0,0,"Helvetica",18)
 scoreText:setTextColor(220, 0, 0)
 scoreText.x = _W*0.5; scoreText.y = 10
 fgGroup:insert(scoreText)
 levelText = display.newText("Level: "..wave, 0,0,"Helvetica",18)
 levelText:setTextColor(220, 0, 0)
 levelText.x = _W*0.5; levelText.y = scoreText.y + 20
 fgGroup:insert(levelText)
end

local function moveShip( event )
  local phase = event.phase
  if gameIsActive == false then return end
  print(event.x,event.y,phase)
  goto_x = event.x
  goto_y = event.y
  -- if( event.x > ship.x ) then
  --   transition.cancel( ship )
  --   transition.to( ship, {time = (event.x-ship.x)/0.2, x = event.x} )  -- t = d/k
  -- end
  -- if( event.x < ship.x ) then
  --   transition.cancel( ship )
  --   transition.to( ship, {time = -(event.x-ship.x)/0.2, x = event.x} )  -- t = d/k
  -- end
end

local function registerMoveShip()
  Runtime:addEventListener("touch", moveShip)
end

local function loadPlayer()
  ship = display.newImageRect("my.png", 20, 20) 
  ship.x = _W*0.5; ship.y = _H+30; ship.name = "ship"
  physics.addBody( ship, { isSensor = true } )
  playerGroup:insert(ship) 
  transition.to(ship, {time = 600, y = _H-_H*0.1, onComplete=registerMoveShip})
end

local function loadBullet()
  local function fireNow()
    local bullet = display.newImageRect( "bullet.png", 10, 15 )
    bullet.x = ship.x-5; bullet.y = ship.y-5; bullet.name = "laser"
    physics.addBody( bullet, { isSensor = true } )
    weaponGroup:insert( bullet )

    local bullet = display.newImageRect( "bullet.png", 10, 15 )
    bullet.x = ship.x +5; bullet.y = ship.y-5; bullet.name = "laser"
    physics.addBody( bullet, { isSensor = true } ) 
    weaponGroup:insert( bullet )
  end
  fireTimer = timer.performWithDelay(850, fireNow, 0)
end

local function moveWeapon()
 --Move our lasers up each frame!
  for i = weaponGroup.numChildren,1,-1 do
    local weapon = weaponGroup[i]
    if weapon ~= nil and weapon.y ~= nil then
      weapon:translate(0, -10);
    end
  end 
end

local function loadBlocker()
  local laserBlock = display.newRect(0,-80,_W,2)
  laserBlock.anchorX = 0;laserBlock.anchorY = 0;
  laserBlock.name = "blocker" 
  physics.addBody( laserBlock, { isSensor = true } )
  bgGroup:insert(laserBlock)
 
  local shipBlock = display.newRect(0,_H+_H*0.2,_W,2)
  shipBlock.anchorX = 0;shipBlock.anchorY = 0;
  shipBlock.name = "blocker"
  physics.addBody( shipBlock, { isSensor = true } )
  bgGroup:insert(shipBlock) 
end

local function spawnEnemy()
  local imageInt = math.random(1,3)
  local enemy = display.newImageRect("ship_"..imageInt.."_20_20.png",20,20)

  enemy.x = math.random( 20, _W-20 ); enemy.y = -30; enemy.rotation = 90
  enemy.name = "enemy"; physics.addBody( enemy, { isSensor = true } )
  enemyGroup:insert( enemy )

  if spawned == spawnedMax then 
    wave = wave + 1 --Increase the wave.
    if wave <= 18 then --Limit max speed/spawn
      enemySpeed = enemySpeed + 1 
      spawnIntMax = math.round(spawnIntMax * 0.9)
    end
    spawned = 0 --Reset so that the next wave starts from 0
  end
  spawnInt = 0
end

local function checkNSpawnEnemy()
  --Increase the int until it spawns an enemy..
  spawnInt = spawnInt + 1
  --change spawnIntMax if you want enemies to spawn
  --faster or slower.
  if spawnInt == spawnIntMax then 
    spawnEnemy()
    spawned = spawned + 1
  end
end

local function moveEnemy()
  --Move the enemies down each frame!
  local i
  for i = enemyGroup.numChildren,1,-1 do
    local enemy = enemyGroup[i]
    if enemy ~= nil and enemy.y ~= nil then
      enemy:translate( 0, enemySpeed)
    end
  end 
end

local function updateTexts()
 scoreText.text = "Score: "..g_score
 levelText.text = "Level: "..wave
end

local function movePlayer()
  if( goto_x < 0 or gameIsActive == false ) then return end
  if( ship.x > goto_x ) then ship.x = ship.x - 5 end
  if( ship.x < goto_x ) then ship.x = ship.x + 5 end
end

local function gameLoop(event)
  checkNSpawnEnemy()
  moveStarField()
  moveEnemy()
  moveWeapon()
  movePlayer()
  updateTexts()
end

local function gotoRestart()
  storyboard.gotoScene("restart")
end

local function gameOver()
  gameIsActive = false
  if( fireTimer ~= nil ) then 
    timer.cancel(fireTimer) 
    fireTimer = nil
  end
  timer.performWithDelay(1000, gotoRestart, 1)
end

local function makeExp(x,y)
  local function expListener( event )
    local thisSprite = event.target  -- "event.target" references the sprite
    if ( event.phase == "ended" ) then  
      thisSprite:removeSelf(); thisSprite = nil
    end
  end

  local sequencesExp = {
      {
          name = "exp",
          start = 1,
          count = 6,
          time = 200,
          loopCount = 1,
          loopDirection = "forward"
      }
  }
  local exp = display.newSprite( sheetExp, sequencesExp )
  exp.x = x; exp.y = y
  exp:play()
  exp:addEventListener( "sprite", expListener )
  expGroup:insert( exp )
  print(expGroup.numChildren)
end

local function onCollision(event)
  if event.phase == "began" then
    local obj1 = event.object1; 
    local obj2 = event.object2; 

    if obj1.name == "laser" and obj2.name == "enemy" or obj1.name == "enemy" and obj2.name == "laser" then
      if( obj2.name =="enemy") then 
        makeExp(obj2.x,obj2.y)
      else
        makeExp(obj1.x,obj1.y)
      end
      display.remove( obj1 ); obj1 = nil
      display.remove( obj2 ); obj2 = nil
      g_score = g_score + 100 --Yay points!

    elseif obj1.name == "ship" and obj2.name == "enemy" or obj2.name == "ship" and obj1.name == "enemy" then
      makeExp(obj2.x,obj2.y)
      makeExp(obj1.x,obj1.y)
      display.remove( obj1 ); obj1 = nil
      display.remove( obj2 ); obj2 = nil
      gameOver()--Weve died so call gameover...

    elseif obj1.name == "enemy" and obj2.name == "blocker" or obj2.name == "enemy" and obj1.name == "blocker"then
      if obj1.name == "enemy" then 
        display.remove(obj1); obj1 = nil
      elseif obj2.name == "enemy" then 
        display.remove( obj2 ); obj2 = nil
      end
    elseif obj1.name == "laser" and obj2.name == "blocker" or obj2.name == "laser" and obj1.name == "blocker"then
      if obj1.name == "laser" then 
        display.remove(obj1); obj1 = nil
      elseif obj2.name == "laser" then 
        display.remove( obj2 ); obj2 = nil
      end
    end
  end
end

local function setup()
  loadTexts()
  loadImgs()
  loadBlocker()
  loadPlayer()
  loadBullet()
end

--------------------------------------------------------------------

function scene:createScene(event)
  storyboard.removeScene("start")
  storyboard.removeScene("restart")
  local screenGroup = self.view
  setup()
end

function scene:enterScene(event)
  Runtime:addEventListener("enterFrame", gameLoop)
  Runtime:addEventListener("collision", onCollision )
end

function scene:exitScene(event)

  display.remove( enemyGroup )  ; enemyGroup = nil
  display.remove( weaponGroup ) ; weaponGroup = nil
  display.remove( expGroup )    ; expGroup = nil
  display.remove( playerGroup ) ; playerGroup = nil
  display.remove( fgGroup )     ; fgGroup = nil
  Runtime:removeEventListener("enterFrame", gameLoop)
  Runtime:removeEventListener("collision", onCollision )
  Runtime:removeEventListener("touch", moveShip)
end

function scene:destroyScene(event)

end

scene:addEventListener("createScene", scene)
scene:addEventListener("enterScene", scene)
scene:addEventListener("exitScene", scene)
scene:addEventListener("destroyScene", scene)

return scene


restart.lua


local storyboard = require ("storyboard")
local scene = storyboard.newScene()
local score = require( "score" )

local _W = display.contentWidth
local _H = display.contentHeight

-- background

local function startGame(event)
     if event.phase == "ended" then
  storyboard.gotoScene("game")
     end
end

function showStart()
 scoreTextTransition = transition.to(scoreText,{time=600, alpha=1})
 bestTextTransition = transition.to(bestText,{time=600, alpha=1})
 imgGameStartTransition = transition.to(imgGameStart,{time=600, alpha=1})
end

function removeStart()
 transition.cancel(scoreTextTransition)
 transition.cancel(bestTextTransition)
 transition.cancel(imgGameStartTransition)
end

function loadScore()
 score.init()
 local prevScore = score.load()
 if prevScore ~= nil then
  if prevScore <= g_score then
   score.set(g_score)
   score.save()
  else
   score.set(prevScore) 
  end
 else 
  score.set(g_score) 
  score.save()
 end
 return score.get()
end


---------------------------------------------------------------

function scene:createScene(event)

 local screenGroup = self.view
 scoreText = display.newText("SCORE:"..g_score,display.contentCenterX,
 display.contentCenterY-80, native.systemFont, 20)
 scoreText:setFillColor(100,200,0)
 scoreText.alpha = 0 
   --scoreText.x = _W*0.5; scoreText.y = 10
 screenGroup:insert(scoreText)

 
 bestText = display.newText("HI-SCORE:"..loadScore(),display.contentCenterX,
 display.contentCenterY-40, native.systemFont, 20)
 bestText:setFillColor(100,200,0)
 bestText.alpha = 0
 screenGroup:insert(bestText)

 imgGameStart = display.newImageRect("gamestart.png",240,45)
 imgGameStart.anchorX = 0.5
 imgGameStart.anchorY = 0.5
 imgGameStart.x = display.contentCenterX
 imgGameStart.y = display.contentHeight*0.8
 imgGameStart.alpha = 0
 screenGroup:insert(imgGameStart)
end

function scene:enterScene(event)
 storyboard.removeScene("game")
 imgGameStart:addEventListener("touch", startGame)
 showStart()
end

function scene:exitScene(event)
 imgGameStart:removeEventListener("touch", startGame)
 removeStart()
end

function scene:destroyScene(event)

end


scene:addEventListener("createScene", scene)
scene:addEventListener("enterScene", scene)
scene:addEventListener("exitScene", scene)
scene:addEventListener("destroyScene", scene)

return scene


score.lua
hiscore를 파일에 저장하는 모듈입니다.


-- Score Module
--

local M = {} -- create our local M = {}
M.score = 0

function M.init( options )
 M.filename = "scorefile.txt"
end

function M.set( value )
 M.score = value
end

function M.get()
 return M.score
end

function M.add( amount )
 M.score = M.score + amount
end

function M.save()
 local path = system.pathForFile( M.filename, system.DocumentsDirectory)
    local file = io.open(path, "w")
    if file then
        local contents = tostring( M.score )
        file:write( contents )
        io.close( file )
        return true
    else
     print("Error: could not read ", M.filename, ".")
        return false
    end
end

function M.load()
    local path = system.pathForFile( M.filename, system.DocumentsDirectory)
    local contents = ""
    local file = io.open( path, "r" )
    if file then
         -- read all contents of file into a string
         local contents = file:read( "*a" )
         local score = tonumber(contents);
         io.close( file )
         return score
    end
    print("Could not read scores from ", M.filename, ".")
    return nil
end

return M


전체소스입니다.
https://drive.google.com/file/d/0B9vAKDzHthQIeHY3M25qTGNMWUU/view?usp=sharing

댓글 없음:

댓글 쓰기