SpinRoleDevelop
SpinRoleDevelop

Reputation: 55

Hi, I am creating a simpleplatformer game with love2d, I got a problem in the collisions

In my player script. I called a function to check is if a tile is collided with the player.

The basic tile collisions has been made, but I got some problems.

  1. When the player jump while colliding with the wall, the player stop.
  2. When the player is falling while colliding with the wall, the player stop.

I think the problem is in the Y collision checking part, but I can't figure out how to solve it.

--------------------- Collision Check ----------------------

local box = Vt2:new(self.pos.x + self.vel.x * dt * self.dirXTemp, 
            self.pos.y + self.vel.y * dt)

for i = 1, #collTile do

    local tile = collTile[i]

    local isColl = BdBoxCollision(box, self.size, tile.pos, tile.size)

    if 
        isColl[1] == true and
        isColl[2] == true and
        isColl[3] == true and
        isColl[4] == true then

        local isOnWall = false

        if self.pos.y + self.size.y > tile.pos.y then -- X Collision 

            if box.x + self.size.x / 2 < tile.pos.x + tile.size.x / 2 then
                
                if box.x + self.size.x > tile.pos.x  then
                    
                    if self.dirX == 1 then
                        self.vel.x = 0
    
                        isOnWall = true
                    end

                end

            end

            if box.x + self.size.x / 2 > tile.pos.x + tile.size.x / 2 then
                
                if box.x < tile.pos.x + tile.size.x then
                    
                    if self.dirX == -1 then
                        self.vel.x = 0
                    
                        isOnWall = true
                    end

                end

            end

        end

        if box.y + self.size.y / 2 < tile.pos.y + tile.size.y / 2 then -- Y Collision

            if box.y + self.size.y > tile.pos.y and
                self.pos.y + self.size.y < tile.pos.y + 8  then

                if isOnWall == false then

                    self.pos.y = tile.pos.y - self.size.y 
                    self.vel.y = 0
                end
            end

        elseif box.y + self.size.y / 2 > tile.pos.y + tile.size.y / 2 then

            if box.y < tile.pos.y + tile.size.y then
                
                self.vel.y = self.gravity

            end

        end

    end 

end

::skip::

self.pos.x = self.pos.x + self.vel.x * dt
self.pos.y = self.pos.y + self.vel.y * dt

Upvotes: 2

Views: 108

Answers (1)

darkfrei
darkfrei

Reputation: 566

Please try this solution, the logic is more clear to read:

--------------------- Collision Check----------------------

local function AABBCollision (x1,y1,w1,h1, x2,y2,w2,h2)
-- Function to check for axis-aligned bounding box (AABB) collision between two rectangles
    return x1<x2+w2 and x2<x1+w1 and y1<y2+h2 and y2<y1+h1
end

local function isOnFloor (y, h, ty, th)
-- Function to check if the player is on the floor
    -- positive y directon is downwards
    -- lower value is vertical higher
    -- y, h - position and heigh of player
    -- ty - position of tile
    -- middle is higher than tile middle and it touch
    return (y+h/2 < ty+th/2) and (y + h >= ty)
end

local function isOnRightWall (x, w, tx, tw)
-- Function to check if the player is on the right wall
    -- tx - x position of tile
    -- x, w - position and width of player
    -- dx, w - horizontal movement of player
    -- middle is lefts than tile middle and it touch
    return (x + w/2 < tx + tw/2) and (x + w >= tx)
end

local function isOnLeftWall (x, w, tx, tw)
-- Function to check if the player is on the left wall
    -- tx - x position of tile
    -- x, w - position and width of player
    -- dx, w - horizontal movement of player
    -- middle is rights than tile middle and it touch
    return (x + w/2 > tx + tw/2) and (x <= tx + tw)
end

local function isRightDirected (dirX)
-- Function to check if the player is moving to the right
    return dirX > 0
end

local function isLeftDirected (dirX)
-- Function to check if the player is moving to the left
    return dirX < 0
end

function Player:update (dt)
-- Current position of the player
    local x, y = self.pos.x, self.pos.y
-- Width and height of the player
    local w, h = self.size.x, self.size.y
-- Gravity affecting the player
    local gravity = self.gravity

    if love.keyboard.isScancodeDown('d') then 
        self.dirX = 1 -- going right
    elseif love.keyboard.isScancodeDown('a') then 
        self.dirX = -1 -- going left
    else -- nothing is pressed: reset dirX:
        self.dirX = 0
    end

-- get delta velocity
    local dvy = dt*gravity

-- get delta movement of player
    local dx = dt*self.dirX*math.abs(self.vel.x)
    local dy = dt*(self.vel.y + dvy/2)

-- update vertical velocity
    self.vel.y = self.vel.y + dvy

    -- check all rectangles:
    for i = 1, #collTiles do
        local tile = collTiles[i]
        local tx, ty = tile.pos.x, tile.pos.y
        local tw, th = tile.size.x, tile.size.y-- width, heigh
        local isColl = AABBCollision(x+dx, y+dy, w, h, tx, ty, tw, th)
        if isColl then -- something collides
            if isOnFloor (y+dy, h, ty, th) then
                -- onFloor
                if stateJumping  then
                    -- keep flying
                else
                    -- not falling, 
                    -- adjust y-position to be on top of the tile
--                  y+dy + h >= ty
                    dy = ty - y - h
                    self.vel.y = 0
                end

                if stateOnPlatform then
                    if tile.vx then
                        local tvx = tile.vx
                        local tdirX = tile.dirX
                        local tdx = dt*tdirX*math.abs(tvx)
                        dx = dx + tdx
                    end
                end

                if isRightDirected (self.dirX) then
                    if isOnRightWall (x+dx, w, tx, tw) then
                        dx = tx - x - w
                        self.vel.x = 0
                    end
                elseif isLeftDirected (self.dirX) then
                    if isOnLeftWall (x+dx, w, tx, tw) then
                        dx = tx + tw - x
                        self.vel.x = 0
                    end
                end
                -- end of onFloor
            else 
                -- not onFloor
                if isRightDirected (self.dirX) then
                    if isOnRightWall (x+dx, w, tx, tw) then
                        -- onWall state
                        -- adjust dx to collision
                        dx = tx - x - w
                        -- no horizontal speed
                        self.vel.x = 0
                        if stateJumping then

                        else
                            -- not falling
                            dy = 0
                            self.vel.y = 0
                        end
                    end
                elseif isLeftDirected (self.dirX) then
                    if isOnLeftWall (x+dx, w, tx, tw) then
                        -- onWall state
                        -- adjust dx to collision
                        dx = tx + tw - x
                        -- no horizontal speed
                        self.vel.x = 0
                        if stateJumping then

                        else
                            -- not falling
                            dy = 0
                            self.vel.y = 0
                        end
                    end
                else
                    -- (not directed)
                end
                -- end of not onFloor
            end
        else
            -- no collision
        end
    end

    self.pos.x = x + dx
    self.pos.y = y + dy
end

Upvotes: 0

Related Questions