简体   繁体   中英

Non-Box2D Physics with Corona SDK

I'm making a tile-based platformer game with Corona SDK. I decided to scrap the built-in Box2D physics engine (for a number of reasons), and I'm attempting to make my own physics system. Again, my game is built on tiles, which makes it easy to collect possible colliders. Also, the only object that needs to collide with tiles is my player, which should make it even easier.

I've got gravity and velocity working, and now I'm starting with collisions. I read on multiple sites how to do it, but it never seems to work for me. The process I've seen goes something like this:

  1. Find possible colliders (easy with tile-based games)
  2. Check for collisions (AABB's in my case)
  3. Calculate penetration depth X and Y
  4. Move object by the penetration amount
  5. Adjust velocity based on penetration

I've got steps 1-3 down, but, for some reason, when I start into steps 4 and 5, nothing works like the tutorials say it should. When colliding with the floor, the player instantly moves to the left. I know why it does that - it's calculating the width of the player as the penetration depth - but when I try to fix it, things get odd.

I call this function for each tile that's colliding with the player (after being found with a simple AABB collision check):

local resolveCollision = function(guy, tile)
    local guyX, guyY, tileX, tileY = guy.x, guy.y, tile.x, tile.y
    local guyHW, guyHH = guy.width * 0.5, guy.height * 0.5
    local tileHW, tileHH = tile.width * 0.5, tile.height * 0.5

    local distX = guyX - tileX
    local minDistX = guyHW + tileHW

    local absDistX = (distX < 0 and -distX) or distX

    -- Calculate X penetration
    local xPen = 0
    if absDistX >= minDistX then
        xPen = 0
    else
        xPen = (distX > 0 and minDistX - distX) or -minDistX - distX
    end

    local distY = guyY - tileY
    local minDistY = guyHH + tileHH
    local absDistY = (distY < 0 and -distY) or distY

    -- Calculate Y penetration
    local yPen = 0
    if absDistY >= minDistY then
        yPen = 0
    else
        yPen = (distY > 0 and minDistY - distY) or -minDistY - distY
    end

    local absXPen = (xPen < 0 and -xPen) or xPen
    local absYPen = (yPen < 0 and -yPen) or yPen

    -- Trim off larger penetration
    if absXPen > absYPen and absYPen ~= 0 then
        xPen = 0
        guy.setYVel(0)
    elseif absYPen > absXPen and absXPen ~= 0 then
        yPen = 0
        guy.setXVel(0)
    end

    guy:translate(xPen, yPen)
end

Does anyone know how to do correct collision response? FYI, my "physics" framework gives the following methods/values (among others):

obj.setXVel(n)         - Set X-velocity
obj.setYVel(n)         - Set Y-velocity
obj.setVelocity(x, y)  - Set both velocities at once
obj.xVel               - Read-only, X-velocity value
obj.yVel               - Read-only, Y-velocity value

I think the problem is that your movement function is frame-based and will get triggered many times in one second.

I suggest you change it to time-based movement. To do this you need to find delta time (elapsed time between a frame and the next) and mutiply it by your move amount. Use this tutorial to get deltaTime: http://coronalabs.com/blog/2013/06/18/guest-tutorial-delta-time-in-corona/

Once you have dT, use it like this:

moveAmount = velocity * deltaTime

This will ensure that your movement speed is constant across devices.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM