2015년 12월 12일 토요일

corona sdk, Million Tile Engine 로 만드는 게임(2)


지난번에 이어 주인공을 생성하고 이동하도록 하겠습니다.

일단 dpad를 만들고 move 터치 이벤트 리스너를 등록합니다.

Dpad:addEventListener("touch", move)

그리고 move 함수는 누른 위치에 따라 player.thismovement 변수에 각도값이 들어갑니다. 여기에서는 0,90,180,270이 들어갑니다.
해당소스는 mte sample코드에서 가져왔습니다.

local function move( event )
 print("move")
 if event.phase == "began" then
  display.getCurrentStage():setFocus(event.target, event.id)
  event.target.isFocus = true
 end
 if event.phase == "began" or event.phase == "moved" then
  local dirX = event.x - event.target.x
  local dirY = event.y - event.target.y 
  local angle = math.deg(math.atan(dirY/dirX))
  if dirX < 0 then
   angle = 90 + (90 - (angle * -1))
  end
  angle = angle + 90
  angle = math.round(angle / 90) * 90
  if angle == 360 then
   angle = 0
  end
  if angle % 90 ~= 0 then
   player.thismovement = nil
  else
   player.thismovement = tostring(angle)
  end
 elseif event.phase == "ended" or event.phase == "cancelled" then
  player.thismovement = nil
  display.getCurrentStage():setFocus( event.target, nil )
  event.target.isFocus = false
 end
 return true
end

주인공의 이동은 gameloop에서 이루어집니다. 실제 이동은 mte.moveSpriteTo  함수를 이용하게 되고 이동 가능한지 확인하는 함수는 obstacle 함수를 이용합니다.


local gameLoop = function(event)

...
 eObject = player
 if not eObject.isMoving then

  --MOVE eObject CHARACTER
  if eObject.thismovement then
   local result
   local xTile, yTile
   xTile, yTile = eObject.locX + atlas[eObject.thismovement][1], eObject.locY + atlas[eObject.thismovement][2]
   result = obstacle( eObject.level, xTile, yTile )
   if( result=="stop" ) then
    eObject:pause()
   end

   if not result then
    if eObject.sequence ~= eObject.thismovement then
     eObject:setSequence( eObject.thismovement )
    end
    eObject:play()
    mte.moveSpriteTo( { sprite = eObject, locX = xTile, locY = yTile, time = eObject.moveTime, transition = easing.linear } )
   end
  else
   eObject:pause()
  end
 end
...

아래는 실행 화면입니다.



전체 소스입니다.


--------------------------------------------------------------------------------
display.setStatusBar(display.HiddenStatusBar)
--------------------------------------------------------------------------------
-- TODO
-- [o] Move enemy with AI
-- [o] Player
-- [o] DPAD
-- [o] Camera
-- [x] Move enemy with AI adv
-- [x] Collision
-- [x] dig
-- [x] score
-- [x] level
-- [x] main screen
--------------------------------------------------------------------------------
-- Localize
--------------------------------------------------------------------------------
local mte = require('mte').createMTE()        --Load and instantiate MTE.
local physics = require ("physics")
local LD = require("lib.LD_LoaderG2")
system.activate( "multitouch" )

local myLevel = {}
local math_ceil = math.ceil
local math_abs = math.abs
local math_random = math.random
local table_insert = table.insert
local map
local player = {}
local dir = 0
local drill = false
local gravity = 1
local speed = 60
local printMemUsageCount = 0
local usePhysics = false
local TileSize = 32
local enemyProperty = {}
enemyProperty["red"] = {}
enemyProperty["red"].enemyMoveTime = 300
enemyProperty["red"].chanceChangeDir = 0 -- 움직이면서 방향전환할 확률 0 전환하지 않음 

enemyProperty["green"] = {}
enemyProperty["green"].enemyMoveTime = 300
enemyProperty["green"].chanceChangeDir = 50 -- 움직이면서 방향전환할 확률 0 전환하지 않음 

local enemyTable = {}
local enemySize = 0;
local atlas = {}
atlas["0"] = {0, -1}
atlas["90"] = {1, 0}
atlas["180"] = {0, 1}
atlas["270"] = {-1, 0}
atlas["360"] = {0, -1}
math.randomseed( os.time() )

--------------------------------------------------------------------------------
-- Functions
--------------------------------------------------------------------------------
local distanceBetween = function(x1, y1, x2, y2) return (((x2 - x1) ^ 2) + ((y2 - y1) ^ 2)) ^ 0.5 end
local getPointsAlongLine = function(x1, y1, x2, y2, d) local points = {} local diffX = x2 - x1 local diffY = y2 - y1 local distBetween = math_ceil(distanceBetween(x1, y1, x2, y2) / d) local x, y = x1, y1 local addX, addY = diffX / distBetween, diffY / distBetween for i = 1, distBetween do table_insert(points, {x, y}) x, y = x + addX, y + addY end return points end
local clamp = function(v, l, h) return (v < l and l) or (v > h and h) or v end

--------------------------------------------------------------------------------
-- Physics
--------------------------------------------------------------------------------
if usePhysics then
 physics.start()
 physics.setGravity(0, 9.8)
 mte.enableBox2DPhysics()
end

--------------------------------------------------------------------------------
-- Load Map
--------------------------------------------------------------------------------

mte.loadMap("resource/hitnrun.tmx")            --Load a map.
myLevel = LD:loadLevel("LoadRes")

--------------------------------------------------------------------------------
-- Physics
--------------------------------------------------------------------------------
--physics.setDrawMode( "hybrid" )


--------------------------------------------------------------------------------
-- SETUP D-PAD
--------------------------------------------------------------------------------
local controlGroup = display.newGroup()
local Dpad = display.newImageRect(controlGroup, "resource/ui_dpad.png", 256, 256)
Dpad.x = 120
Dpad.y = display.viewableContentHeight - 120
Dpad:toFront()

--------------------------------------------------------------------------------
-- Engine dependency code
--------------------------------------------------------------------------------
------------------------------------
local function spawnObject(pname,px,py,passetName,physicsTrue)
------------------------------------
 local function mteSpriteSetup(object,pname,px,py)
  local setup = {
   kind = "sprite", 
   layer = mte.getSpriteLayer(1), 
   levelPosX = px, 
   levelPosY = py,
   name = pname,
   level = 1
   }
  mte.addSprite(object, setup)
 end

 local objProps = 
 {
  name  = pname, 
  x  = px,
  y  = py,
  xScale  =  1,
  yScale  =  1,
  assetName = passetName,
 }
 -- For LD
 -- createObject param nil need not remove object.
 -- That is changed.
 local object = myLevel:createObject(nil, objProps).view 
 -- For Map Engine
 mteSpriteSetup(object,pname,px,py);
 if usePhysics then
  if( physicsTrue ~= nil ) then
   if( physicsTrue == true ) then
    physics.addBody(object, "dynamic", { density=10.0, friction=0.1, bounce=0.1 })
    object.isFixedRotation = true
   end
  end
 end
 return object
end

local function removeObject(displayObject)
 -- body
 mte.removeSprite(displayObject, true)
 -- For Dust map.layer["Object Layer 1"]:remove(displayObject)
end

local function getTileInfo( screenX, screenY, layer )
 local loc = mte.convert("levelPosToLoc", screenX, screenY, layer)
 print("Tile Loc",loc.x, loc.y)
 local tile = mte.getTileObj(loc.x, loc.y, layer)
 -- For Dust 
 --map.layer["Tile Layer 1"].tileByPixels(screenX, screenY)
 return tile
end

local function engineLoop(track)
 -- For MTE
 --mte.setCamera({sprite = track, scale = 1})
 mte.update() --Required to process the camera and display the map.
 mte.debug()  --Displays onscreen position/fps/memory text.

 -- For Dust 
 --map.updateView()
end

local function getTileId(tile)
 local id = tile.index
 return id
end

local function getTileXY(tile)
 local x = tile.locX
 local y = tile.locY
 return x , y
end

local function removeTile( tileX, tileY )
 mte.updateTile({locX = tileX, locY = tileY, layer = 1, tile = 0})
 -- For Dust
 --map.layer["Tile Layer 1"].lockTileErased(tile.tileX, tile.tileY)
end

local function setCamera(track)
 mte.constrainCamera({})
 mte.setCamera({sprite = track, scale = 1})
 mte.setCameraFocus(track)
 -- For Dust map.setCameraFocus(track,true,true)
end

local function setLocalCamera()
 local mapObj = mte.setCamera({locX = 15, locY = 15, scale = 1}) 
end

--DETECT OBSTACLES ------------------------------------------------------------
local obstacle = function(level, locX, locY)
 local detect = mte.getTileProperties({level = level, locX = locX, locY = locY})
 for i = 1, #detect, 1 do
  if detect[i].properties then
   if detect[i].properties.solid and i == 2 then
    detect = "stop"
    return detect
   end
  end
 end
end
--------------------------------------------------------------------------------
-- Engine dependency code END
--------------------------------------------------------------------------------





------------------------------------
local monitorMem = function()
------------------------------------
 collectgarbage()
 print( "MemUsage: " .. collectgarbage("count") )
 local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000
 print( "TexMem: " .. textMem )
end


local function move( event )
 print("move")
 if event.phase == "began" then
  display.getCurrentStage():setFocus(event.target, event.id)
  event.target.isFocus = true
 end
 if event.phase == "began" or event.phase == "moved" then
  local dirX = event.x - event.target.x
  local dirY = event.y - event.target.y 
  local angle = math.deg(math.atan(dirY/dirX))
  if dirX < 0 then
   angle = 90 + (90 - (angle * -1))
  end
  angle = angle + 90
  angle = math.round(angle / 90) * 90
  if angle == 360 then
   angle = 0
  end
  if angle % 90 ~= 0 then
   player.thismovement = nil
  else
   player.thismovement = tostring(angle)
  end
 elseif event.phase == "ended" or event.phase == "cancelled" then
  player.thismovement = nil
  display.getCurrentStage():setFocus( event.target, nil )
  event.target.isFocus = false
 end
 return true
end

------------------------------------
------------------------------------
------------------------------------
------------------------------------
local gameLoop = function(event)
------------------------------------
------------------------------------
------------------------------------
------------------------------------
 local eObject
 local inputDir
 
 for i=1, enemySize-1 do
  eObject = enemyTable[i]
  inputDir = tonumber(eObject.thismovement)%360
  if not eObject.isMoving then
   if math_random(100) < enemyProperty[eObject.enemyType].chanceChangeDir then
    if math_random(4)<=2 then
     eObject.thismovement = tostring((tonumber(eObject.thismovement)+90+(math_random(2)-1)*180)%360)
    end
   end

   --MOVE eObject CHARACTER
   if eObject.thismovement then
    local result
    local xTile, yTile
    for i=1,4 do
     xTile, yTile = eObject.locX + atlas[eObject.thismovement][1], eObject.locY + atlas[eObject.thismovement][2]
     result = obstacle( eObject.level, xTile, yTile )
     if( result ~= "stop" ) then
      break
     end
     eObject.thismovement = tostring(math_random(4)*90)
     if( inputDir%180 == tonumber(eObject.thismovement)%180 ) then
      eObject.thismovement = tostring(math_random(4)*90)
      if( inputDir%180 == tonumber(eObject.thismovement)%180 ) then
       eObject.thismovement = tostring(math_random(4)*90)
       if( inputDir%180 == tonumber(eObject.thismovement)%180 ) then
        eObject.thismovement = tostring(math_random(4)*90)
       end
      end
     end
    end
    if not result then
     if eObject.sequence ~= eObject.thismovement then
      eObject:setSequence( eObject.thismovement )
     end
     eObject:play()
     mte.moveSpriteTo( { sprite = eObject, locX = xTile, locY = yTile, time = enemyProperty[eObject.enemyType].enemyMoveTime, transition = easing.linear } )
    end
   else
    eObject:pause()
   end
  end
 end

 eObject = player
 if not eObject.isMoving then

  --MOVE eObject CHARACTER
  if eObject.thismovement then
   local result
   local xTile, yTile
   xTile, yTile = eObject.locX + atlas[eObject.thismovement][1], eObject.locY + atlas[eObject.thismovement][2]
   result = obstacle( eObject.level, xTile, yTile )
   if( result=="stop" ) then
    eObject:pause()
   end

   if not result then
    if eObject.sequence ~= eObject.thismovement then
     eObject:setSequence( eObject.thismovement )
    end
    eObject:play()
    mte.moveSpriteTo( { sprite = eObject, locX = xTile, locY = yTile, time = eObject.moveTime, transition = easing.linear } )
   end
  else
   eObject:pause()
  end
 end

 engineLoop(player)

 printMemUsageCount = printMemUsageCount + 1;
 if( printMemUsageCount > 100 ) then
  printMemUsageCount = 0
  --monitorMem()
 end
end


local function spawnEnemyNPlayerObject()
 enemyTable = {}
 enemySize = 1;
 local objects = mte.getObject({})
 for key,value in pairs(objects) do
  --print(value.name, value.type, value.x, value.y, value.properties)
  if( value.type=="red" )then
   local enemy = spawnObject("red",value.x+TileSize/2,value.y+TileSize/2,"enemy_32_1_red.png")
   enemy:setSequence("move")
   enemy:play()
   enemy.enemyType = "red"
   enemy.thismovement = tostring(math_random(4)*90)
   enemyTable[enemySize] = enemy;
   enemySize=enemySize+1
  end
  if( value.type=="green" )then
   local enemy = spawnObject("green",value.x+TileSize/2,value.y+TileSize/2,"enemy_32_1.png")
   enemy:setSequence("move")
   enemy:play()
   enemy.enemyType = "green"
   enemy.thismovement = tostring(math_random(4)*90)
   enemyTable[enemySize] = enemy;
   enemySize=enemySize+1
  end
  if( value.type=="player" )then
   player = spawnObject("player",value.x+TileSize/2,value.y+TileSize/2,"player32_1.png")
   player.moveTime = 300
   player:setSequence("180")
   player:play()
  end
 end
end


------------------------------------
local function spawnPlayerObject()
------------------------------------

end
--------------------------------------------------------------------------------

spawnEnemyNPlayerObject()

setCamera(player)

Runtime:addEventListener("enterFrame", gameLoop)

Dpad:addEventListener("touch", move)


소스 링크
https://drive.google.com/file/d/0B9vAKDzHthQIeFlpMmt4aDhZOWc/view?usp=sharing

댓글 없음:

댓글 쓰기