https://github.com/anthonymoralez/lime-tutorials/tree/master/tutorial-15
README.md
NOTE: This tutorial is copied from the original at OutlawGameTools.com
15 – Building a Platform Game with Corona and Lime (플랫폼 만들기)
Difficulty: Intermediate
Duration: 30 minutes
이번껀 시간이 무지 길고 (30분) 이미지도 없어서 무슨 말하는지 제대로 알기가 힘듭니다.
일단 위에 있는 소스 가지고 실행시켜 보시기 바랍니다. 내용은 지금까지 했던걸 모두 적당히 합해놓은 느낌이나 좀 어딘가 모르게 joystick 부분도 그렇고 부자연 스럽습니다.
일단 위에 있는 소스 가지고 실행시켜 보시기 바랍니다. 내용은 지금까지 했던걸 모두 적당히 합해놓은 느낌이나 좀 어딘가 모르게 joystick 부분도 그렇고 부자연 스럽습니다.
Description:
In this tutorial I will be walking you through the code needed to create a platform game. I will be using the Corona SDK and Lime. Lime is a nice library for use with Corona that makes it easy to create tile based games with Tiled. If you don’t know what Tiled is, check it out.
지금까지 Lime 과 Corona SDK를 같이 해놓고 갑자기 쌩뚱맞은 소리를 하고 있네요. Tild 라던가 링크에서 받으라네요.
If you load the map into Tiled you will see two layers. The top layer is called “Physics”. This is the layer that will define all our objects. The bottom layer is called “Background” and will hold all the tiles that create the visual aspect of the map.
First thing to do is set up the main entry point for the game. In the main.lua file I have the following code. This will do a bit of setup for the app and create our platform world.
--Hide the status bar
display.setStatusBar( display.HiddenStatusBar )
--Enable multitouch
system.activate( "multitouch" )
--Include platform.lua
local platform = require("platform")
--Call the loadMap function in platform.lua
platform.loadMap("map.tmx")
Next is the initial setup of our platform.lua file.
플랫폼 게임이라는게 platform.lua를 사용해서 그렇게 이름을 붙인것 같습니다. 여기에서는 mutitouch 부분이 추가되었습니다. multitouch를 안하면 점프하면서 방향이동이 안됩니다.
main.lua에서는 간단하게 map정보만 넘기고 모든 처리는 platform에서 하도록 작업이 되어있습니다.
--Include physics and start the physics simulation
require("physics")
physics.start()
--Load lime and assign to a variable
local lime = require("lime")
local Platform = {}
function Platform.loadMap(tmx)
-- Create a sky blue background
local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight)
bg:setFillColor(0.31,0.67,1.0)
--Load the map into our instance of lime
map = lime.loadMap(tmx)
--Add a listener so we know when the player object has been loaded from the map
map:addObjectListener("Player", onPlayerLoaded)
--Tell lime to create the visual aspect of the world
visual = lime.createVisual(map)
--Tell lime to create the physics bodies needed for the world
local physical = lime.buildPhysical(map)
end
Now that the map is loaded we can move on to the listener function referenced in the loadMap function. This method will get passed the player object defined in Tiled. Most of the properties are simply stored for use later. The object.sheet property is used to load the image used to represent the main character.
아래내용은 tiled에 설정한 값을 변수에 넣기위한 작업들입니다. 실제값들은 tiled에서 설정 해주어야 합니다.function onPlayerLoaded(object)
--Store properties for later use
topSpeed = tonumber(object.topSpeed)
floatForce = tonumber(object.floatForce)
walkForce = tonumber(object.walkForce)
jumpForce = tonumber(object.jumpForce)
jumpDrag = tonumber(object.jumpDrag)
wallJumpPower = tonumber(object.wallJumpPower)
wallDrag = tonumber(object.wallDrag)
--Create our player display object
player = display.newImage(object.sheet)
--Grab the layer display object and add the player to it
local layer = map:getObjectLayer("Physics")
layer.group:insert(player)
--Add a collision listener and set the initial position of the player
player:addEventListener( "collision", onPlayerCollision )
player.x = object.x
player.y = object.y
--Create a physics body to represent the player and stop it from rotating
physics.addBody(player, { density = object.density, friction = object.friction, bounce = object.bounce })
player.isFixedRotation = true
--Player is ready, setup the joystick
setupJoystick()
end
Before I get into the collision detection I would like to step back and go over touch events and the main loop. Here is how those event listeners are defined.
Runtime:addEventListener("touch", onTouch)
Runtime:addEventListener("enterFrame", onPlatformLoop)
The first is the “touch” event. What I am going to do is use a joystick for left and right movement and a tap anywhere else on screen for the jump. The onTouch Method simply sets a variable to indicate whether the user has touched the screen anywhere. When a touch begins I am also calling a resetJump method. More on that part later though.
local function onTouch(event)
if event.phase == "began" then
resetJump()
elseif event.phase == "ended" then
touchDown = false
end
end
Next up is the main loop. This gets called once every frame, so we can use it for updating our map position among other things.
local function onPlatformLoop(event)
--If the player has been created set the map to center around the player
if player then map:setPosition(player.x, player.y) end
--If the user is touching the screen I will call this method
if touchDown then onTouchIsDown() end
--For the sake of clean code all player updates will be in another function
updatePlayer()
end
Next step is to get the joystick controls in. For this I found a nice class for use in Corona SDK here. We setup the joystick when our player is loaded and ready to control. You can consult the joystick class for details on how to use it. I have a simple setup here since it is only used for left and right movement.
--Include joystick.lua
local joystickClass = require( "joystick" )
function setupJoystick()
joystick = joystickClass.newJoystick{
outerAlpha = 0.5,
outerRadius = 20,
innerAlpha = 1.0,
innerRadius = 10,
position_y = display.contentHeight - (display.contentHeight/4),
onMove = onWalk
}
joystick:joystickStart()
end
One thing to note about the joystick is the onMove property points to the onWalk function. The onWalk function will test if the player can walk and apply a force to make the player move. The joystick updates its internal state based on touch events on it. The onMove callback is registered as a listener of the "enterFrame" Corona
function onWalk( event )
--Make sure the joystick is not in the neutral position
if joystick.joyX ~= false then
--Get the current velocity of the player
vx, vy = player:getLinearVelocity()
--Make sure we don't keep speeding up past the topSpeed
local belowSpeed = vx > -topSpeed and vx < topSpeed;
--Set a different speed for horizontal movement in the air
local force = playerOnGround and walkForce or floatForce
--Apply force to move the player
if belowSpeed then player:applyForce( joystick.joyX * force, vy, player.x, player.y) end
end
end
Back in our game loop we called a function named onTouchIsDown. Right now all this does is call the updateJump function. It may do more in the future but that’s for another day.
function onTouchIsDown()
updateJump()
end
function updateJump()
--Set the current force for the jump, will reset when user taps
currForce = currForce - jumpDrag
--Make sure the force is never negative
if currForce < 0 then currForce = 0 end
--If on the ground apply a horizontal force
if playerOnGround then player:applyForce( 0, -currForce, player.x, player.y ) end
--If the player is on the wall make him jump off
if playerOnGround == false and playerOnWall then wallJump() end
end
function resetJump()
--Set current force back to its initial value
currForce = jumpForce
end
In our game loop I was also calling a function named “updatePlayer”. This is meant to adjust movement in different directions based on the state of the player.
function updatePlayer()
-- Stop movement on the x axis in the air
if joystick.joyX == false and playerOnGround == false then
vx, vy = player:getLinearVelocity()
player:setLinearVelocity(0, vy)
end
--Slide down walls slowly when pushing towards the wall
if joystick.joyX ~= false and playerOnWall and wallJumping == false then
player:setLinearVelocity(0, wallDrag)
end
end
The wall jump function will allow our player to jump of walls. This is a fun feature in my opinion. I like wall jumping to reach high places.
function wallJump()
--Only wall jump if joystick is not in the neutral position
if joystick.joyX then
--Don't try to wall jump if I am already wall jumping
if wallJumping ~= true then
--Get the side the wall is on to set our jump direction
local xPower = wallOnLeft and wallJumpPower or -wallJumpPower
local xPower = wallOnLeft and wallJumpPower or -wallJumpPower
--Make the player jump
player:setLinearVelocity(xPower, -(wallJumpPower*2))
end
end
end
Last up is collision detection. The physics engine in Corona handles all the real collision detection. What it won’t tell us is what side of an object the player hit. This is important if we want to wall jump. We need to know if we are hitting the ground or a wall. The following function is the listener that was set up when the player was created. In this function event.other refers to the physics body that our player has collided with. If the body has the property IsGround (which was set in the map) then we call hitGround or offGround based on whether the collision began or ended. We pass the collision object along since we will need to know its location and size later.
function onPlayerCollision(event)
if event.phase == "began" then
if event.other.IsGround then hitGround(event.other) end
end
if event.phase == "ended" then
if event.other.IsGround then offGround(event.other) end
end
end
When we call the hitGround function we need to test what side was hit and whether the collision was valid.
function hitGround(ground)
--The player is no longer wall jumping if it hit a new ground object
wallJumping = false
--Check which side of the ground the player hit
local hitSide = getCollisionSide(ground, player)
--activeWall tracks the wall currently in contact with the player
if activeWall == nil then
playerOnWall = hitSide == 3 or hitSide == 4
--If the player is on the wall set the active wall
if playerOnWall then
activeWall = ground
wallOnLeft = hitSide == 3
end
end
--activeGround tracks the ground currently in contact with the player
--If not already touching the ground test for the ground
if activeGround == nil then
playerOnGround = hitSide == 2
--If the player is on the ground then set the active ground and unset wall
if playerOnGround then
activeGround = ground
activeWall = nil
playerOnWall = false
end
end
end
The offGround function is more simple. If a collision ended and the wall is active then deactivate the wall. the same goes for the ground.
function offGround(ground)
if ground == activeWall then
activeWall = nil
playerOnWall = false
end
if ground == activeGround then
activeGround = nil
playerOnGround = false
end
end
Here is the method that checks which side of the ground object the player collided with. This is just a simple rectangle rectangle collision detection. The varaible names should make it self explanatory.
function getCollisionSide(ground, player)
local groundX, groundY = ground.x - (ground.width / 2), ground.y - (ground.height / 2)
local playerX, playerY = player.x - (player.width / 2), player.y - (player.height / 2)
local groundLeft = groundX
local playerLeft = playerX
local groundRight = groundX+ground.width
local playerRight = playerX+player.width
local groundTop = groundY
local playerTop = playerY
local groundBottom = groundY+ground.height
local playerBottom = playerY+player.height
if groundBottom < playerTop then return 1 end
if groundTop > playerBottom then return 2 end
if groundRight < playerLeft then return 3 end
if groundLeft > playerRight then return 4 end
end
That about wraps it up. As always please feel free to ask questions.
Resources:
Completed Project:
git clone https://github.com/anthonymoralez/lime-tutorials
Tileset: Download
댓글 없음:
댓글 쓰기