Why does my player bounce back and forth when colliding?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Kasperelo
Party member
Posts: 343
Joined: Fri Apr 13, 2012 1:47 pm
Location: The Milky Way

Why does my player bounce back and forth when colliding?

Post by Kasperelo »

When the player in my game collides with either the left or top wall of a game, the player begins bouncing up and down or back and forth. Anyone know why? The player collision detection is located in player.lua, line 92 until line 155.
Attachments
game.love
(11.57 KiB) Downloaded 50 times
User avatar
Beelz
Party member
Posts: 234
Joined: Thu Sep 24, 2015 1:05 pm
Location: New York, USA
Contact:

Re: Why does my player bounce back and forth when colliding?

Post by Beelz »

As opposed to using keypressed and keyreleased, I would use isDown within the update function.

Code: Select all

function updatePlayer(dt)
	local tx, ty = nil, nil
	if love.keyboard.isDown("up") then
		ty = player.y - player.speed * dt
	elseif love.keyboard.isDown("down") then
		ty = player.y + player.speed * dt
	end

	if love.keyboard.isDown("left") then
		tx = player.x - player.speed * dt
	elseif love.keyboard.isDown("right") then
		tx = player.x + player.speed * dt
	end

	if tx ~= nil or ty ~= nil then
		tx, ty = tx or player.x, ty or player.y
		for i, obj in ipairs(objs) do -- Table of objects to check
			local collide = checkColl(tx, ty, player.w, player.h, obj.x, obj.y, obj.w, obj.h)
			if not collide then
				player.x, player.y = tx, ty
			end
		end
	end
end

-- AABB Collision Check
function checkColl(x1, y1, w1, h1, x2, y2, w2, h2)
	local collided = false
		if x1 <= x2+ w2 and
		x2 <= x1 + w1 and
		y1 <= y2 + h2 and
		y2 <= y1 + h1 then

		collided = true
	end
return collided
end

Code: Select all

if self:hasBeer() then self:drink()
else self:getBeer() end
GitHub -- Website
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Why does my player bounce back and forth when colliding?

Post by pgimeno »

I only see problems when going right.

I think you've got your loops wrong.

This works for me (for the right direction only):

Code: Select all

         local i = math.floor(player.x / 16)+2 -- only one X coordinate to check, no need for a loop
            for j = math.floor(player.y / 16)+1, math.ceil(player.y / 16)+1 do
When going in any direction, there are only one or two squares to check. In case of going right or left, if the Y coordinate is grid-aligned, there's only one square to check; otherwise, there are two.

In both cases, the X coordinate to check for collision is the one that is at a distance of less than a unit from the player.

You could fix the other loops similarly. Try to check only one or two squares every time (from floor to ceil). It should work.
User avatar
Kasperelo
Party member
Posts: 343
Joined: Fri Apr 13, 2012 1:47 pm
Location: The Milky Way

Re: Why does my player bounce back and forth when colliding?

Post by Kasperelo »

Beelz wrote:As opposed to using keypressed and keyreleased, I would use isDown within the update function.

Code: Select all

function updatePlayer(dt)
	local tx, ty = nil, nil
	if love.keyboard.isDown("up") then
		ty = player.y - player.speed * dt
	elseif love.keyboard.isDown("down") then
		ty = player.y + player.speed * dt
	end

	if love.keyboard.isDown("left") then
		tx = player.x - player.speed * dt
	elseif love.keyboard.isDown("right") then
		tx = player.x + player.speed * dt
	end

	if tx ~= nil or ty ~= nil then
		tx, ty = tx or player.x, ty or player.y
		for i, obj in ipairs(objs) do -- Table of objects to check
			local collide = checkColl(tx, ty, player.w, player.h, obj.x, obj.y, obj.w, obj.h)
			if not collide then
				player.x, player.y = tx, ty
			end
		end
	end
end

-- AABB Collision Check
function checkColl(x1, y1, w1, h1, x2, y2, w2, h2)
	local collided = false
		if x1 <= x2+ w2 and
		x2 <= x1 + w1 and
		y1 <= y2 + h2 and
		y2 <= y1 + h1 then

		collided = true
	end
return collided
end
I'd rather not use isDown for moving, for example, if you are moving right you cannot move left if you press the left arrow key, but with this system using keypressed and keyreleased, the player changes direction every time a directional key is pressed.
User avatar
Kasperelo
Party member
Posts: 343
Joined: Fri Apr 13, 2012 1:47 pm
Location: The Milky Way

Re: Why does my player bounce back and forth when colliding?

Post by Kasperelo »

pgimeno wrote:I only see problems when going right.

I think you've got your loops wrong.

This works for me (for the right direction only):

Code: Select all

         local i = math.floor(player.x / 16)+2 -- only one X coordinate to check, no need for a loop
            for j = math.floor(player.y / 16)+1, math.ceil(player.y / 16)+1 do
When going in any direction, there are only one or two squares to check. In case of going right or left, if the Y coordinate is grid-aligned, there's only one square to check; otherwise, there are two.

In both cases, the X coordinate to check for collision is the one that is at a distance of less than a unit from the player.

You could fix the other loops similarly. Try to check only one or two squares every time (from floor to ceil). It should work.
It works, but the problem persists. The player still shakes back and forth when colliding with a wall from the top and from the left.
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Why does my player bounce back and forth when colliding?

Post by pgimeno »

Kasperelo wrote:
pgimeno wrote:I think you've got your loops wrong.

[...]

You could fix the other loops similarly. Try to check only one or two squares every time (from floor to ceil). It should work.
It works, but the problem persists. The player still shakes back and forth when colliding with a wall from the top and from the left.
I think you need to fix the other loops similarly. I don't see the shake here.
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Why does my player bounce back and forth when colliding?

Post by pgimeno »

I think I see now what you mean.

The cause seems to be that you check the tiles based on current player's position, not in the future player's position.

So it's again because of the loops. Instead of math.floor(player.x / 16) ... it should be using math.floor((player.x + dt * player.speed) / 16) ... etc.

I strongly advise you to put these tentative positions in variables, e.g.

Code: Select all

local newX, newY = player.x, player.y
if --[[going right]] then
  newX = newX + dt * player.speed
  --[[check collision with tiles for newX, newY]]
etc.
EDIT: This made it work for me:

Code: Select all

function player.move(dt)
   local newX, newY = player.x, player.y
   local offset = player.speed * dt
   if player.moving then
      if player.moving:sub(1, 1) == "r" then

         newX = newX + offset
         local i = math.floor(newX / 16) + 2
         for j = math.floor(newY / 16) + 1, math.ceil(newY / 16) + 1 do
            if collision.rectangle(newX, newY, 16, 16, (i - 1) * 16, (j - 1) * 16, 16, 16) and map.tilemap[i][j] == 1 then
               newX = (i - 1) * 16 - 16
            end
         end

      elseif player.moving:sub(1, 1) == "l" then

         newX = newX - offset
         local i = math.ceil(newX / 16)
         for j = math.floor(newY / 16) + 1, math.ceil(newY / 16) + 1 do
            if collision.rectangle(newX, newY, 16, 16, (i - 1) * 16, (j - 1) * 16, 16, 16) and map.tilemap[i][j] == 1 then
               newX = (i - 1) * 16 + 16
            end
         end

      end

      if player.moving:sub(2, 2) == "d" then

         newY = newY + offset
         for i = math.floor(newX / 16) + 1, math.ceil(newX / 16) + 1 do 
            local j = math.floor(newY / 16) + 2
            if collision.rectangle(newX, newY, 16, 16, (i - 1) * 16, (j - 1) * 16, 16, 16) and map.tilemap[i][j] == 1 then
               newY = (j - 1) * 16 - 16
            end
         end

      elseif player.moving:sub(2, 2) == "u" then

         newY = newY - offset
         for i = math.floor(newX / 16) + 1, math.ceil(newX / 16) + 1 do
            local j = math.ceil(newY / 16)
            if collision.rectangle(newX, newY, 16, 16, (i - 1) * 16, (j - 1) * 16, 16, 16) and map.tilemap[i][j] == 1 then
               newY = (j - 1) * 16 + 16
            end
         end

      end
      player.x, player.y = newX, newY
   end
end
Last edited by pgimeno on Sat Dec 19, 2015 7:03 pm, edited 1 time in total.
User avatar
Kasperelo
Party member
Posts: 343
Joined: Fri Apr 13, 2012 1:47 pm
Location: The Milky Way

Re: Why does my player bounce back and forth when colliding?

Post by Kasperelo »

I've tried different things, and nothing worked, so I just set the player to draw at math.floor(player.x) and math.floor(player.y), so if the player teleports into a block for a frame, it won't show, because the player moves almost nothing in just one frame. Lazy, I know, but whatever :vamp:
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Why does my player bounce back and forth when colliding?

Post by pgimeno »

See my edit, please.
User avatar
Kasperelo
Party member
Posts: 343
Joined: Fri Apr 13, 2012 1:47 pm
Location: The Milky Way

Re: Why does my player bounce back and forth when colliding?

Post by Kasperelo »

Yeah, I see what you mean, but I was already doing that. That is why the player doesn't bounce back and forth all the time, but it stills does that sometimes.
Post Reply

Who is online

Users browsing this forum: No registered users and 53 guests