Page 1 of 1

[bump] how to detect side collision

Posted: Sat Aug 24, 2019 4:50 pm
by maxtrautwein
Hi, I use bump.lua, the collision library, and i have a small issue :

I can detect when a collision is happening on the down side of my cube, the print is working ->

Code: Select all

player.x, player.y, cols, len = world:move(player, player.x, player.y + player.vy)
for i = 1, len do
    	local col = cols[i]
    	if col.normal.y == -1 then
    		print('DOWN')
    	end	
    end	
But i can't detect any other collision like on the left or right side of my cube, the print is not working ->

Code: Select all

player.x, player.y, cols, len = world:move(player, player.x, player.y + player.vy)
for i = 1, len do
    	local col = cols[i]
    	if col.normal.x == -1 then
    		print('LEFT')
    	end	
    end		
I am new to bump so I am sure it's easy...
If you have any ideas it could help me a lot! thanks!!

Re: [bump] how to detect side collision

Posted: Sat Aug 24, 2019 5:33 pm
by pgimeno
What value do you get for col.normal.x when you expected a collision?

Re: [bump] how to detect side collision

Posted: Sun Aug 25, 2019 1:08 am
by maxtrautwein
everytime i expected a collision the value of col.normal.x stay at 0

Re: [bump] how to detect side collision

Posted: Sun Aug 25, 2019 11:13 am
by pgimeno
Works for me. Can you post your project? Or at least a trimmed down version that still shows the problem, but that we can run.

Here's my test (it doesn't require LÖVE, it can be run with the command-line LuaJIT):

Code: Select all

local bump = require 'bump'
local world = bump.newWorld()

local A = {name = 'A'}
local B = {name = 'B'}
local C = {name = 'B'}
local x, y = 32, 0
world:add(A, x, y, 32, 32)
world:add(B, 0, 0, 32, 32)
world:add(C, 32, 32, 32, 32)

local function moveA(xd, yd)
  local xf, yf, coll, len = world:move(A, xd, yd)
  print(string.format("A is now at %.17g, %.17g", xf, yf))
  for i = 1, len do
    local normal = coll[i].normal
    print(string.format("Normal is %.17g, %.17g", normal.x, normal.y))
  end
  x = xf
  y = yf
end

moveA(x, y+1) -- collision down (negative y)
moveA(x-1, y) -- collision left (positive x)
--[[
Output:

A is now at 32, 0
Normal is 0, -1
A is now at 32, 0
Normal is 1, 0
--]]

Re: [bump] how to detect side collision

Posted: Sun Aug 25, 2019 11:32 am
by maxtrautwein
Here is the entire code, sorry i don't know how to attach a file. You can focus on the 'playerf' functions. I don't know why but col.normal.y seems to work but col.normal.x doesn't work.

Code: Select all

 io.stdout:setvbuf('no')
love.graphics.setDefaultFilter("nearest")

local bump = require('bump')
local world = bump.newWorld()

-- listes fonctions --
local tween = {}
local transition = {}
local cubes = {liste={}}
local menu = {}
local playerf = {}
local game = {}
---
local gravity = 7
local gameScreen = 'game'

function setColor(r,g,b,a) return love.graphics.setColor((r or 255)/255, (g or 255)/255, (b or 255)/255, (a or 255)/255) end 

-- TWEEN --
function tween.quadratic(in_or_out,t,b,c,d)
	if in_or_out == 'in' then 
		local s = t/d
		return c*s*s + b
	elseif in_or_out == 'out' then
		local i = t/d
		return -c * i*(i-2) + b	  
    end	
end	
---

-- TRANSITION --
function transition.load()
	transition.alpha = 0
	transition.alphaMax = 1.2
	transition.vitesse = 4
	transition.state = 1
	transition.play = false
	transition.goal = nil
end	

function transition.to(goal_screen)
	transition.play = true 
	transition.goal = goal_screen
end		

function transition.update(dt)
	if transition.play == true then 
		if transition.state == 1 then 
			transition.alpha = transition.alpha + transition.vitesse*dt
			if transition.alpha > transition.alphaMax then 
				transition.state = 2
			end	
		elseif transition.state == 2 then 
				gameScreen = transition.goal	
				transition.alpha = transition.alpha - transition.vitesse*dt
			if transition.alpha <= 0 then 
				transition.state = 1
				transition.play = false
			end
		end	
	end	
end

function transition.draw()
	love.graphics.setColor(67/255,109/255,118/255,transition.alpha)
	love.graphics.rectangle('fill', 0, 0, largeurScreen, hauteurScreen)
	love.graphics.setColor(1,1,1)
end	
---

-- CUBES --
function cubes.add(x,y,w,h)
	local cube = {x=x,y=y,w=w,h=h}
	cubes.liste[#cubes.liste+1] = cube
	world:add(cube,x,y,w,h)
end 
 
function cubes.draw()
	for _,cube in ipairs(cubes.liste) do
		setColor()
    	love.graphics.rectangle("line", cube.x, cube.y, cube.w, cube.h)
    end
end
---

-- MENU --
function menu.load()
end

function menu.update(dt)
end

function menu.draw(dt)
end

function menu.keypressed(key)
end	
---

-- PLAYER --
function playerf.load()
	player = {x=120,y=100,vx=0,vy=0,w=30,h=30,acceleration=60,decceleration=50,max_speed=8,jump1=false,jump2=false,max_height=12.5}
	world:add(player,player.x,player.y,player.w,player.h)
end	

function playerf.resetVelocity()
	for i = 1, len do
    	local col = cols[i]
    	if col.normal.y == -1 or col.normal.y == 1 then 
    		player.vy = 0
    		print('up and down collision detection ok') 
    	end	
    	if col.normal.y == -1 then
    		player.jump1 = false
    		player.jump2 = false
    	end	

    	if col.normal.x == -1 or col.normal.x == 1 then 
    		print('SIDE COLLISION OK') -- doesn't print anything 
    	end	
    end	
end

function playerf.gravity(dt)
	player.vy = player.vy + tween.quadratic('in',0.01,1,100,100)*dt*50
	player.x, player.y, cols, len = world:move(player, player.x, player.y + player.vy)
   	playerf.resetVelocity()
end	

function playerf.movements(dt)
	if love.keyboard.isDown('right') then 
		player.vx = player.vx + tween.quadratic('in',1,3,3,3)*dt*60 
		if player.vx > player.max_speed then 
			player.vx = player.max_speed
		end
	elseif love.keyboard.isDown('left') then 
		player.vx = player.vx - tween.quadratic('in',1,3,3,3)*dt*60
		if player.vx < -player.max_speed then 
			player.vx = -player.max_speed
		end	
	else 
		if player.vx > 0 then 
			player.vx = player.vx - (player.decceleration*dt)	
			if player.vx < 0 then 
				player.vx = 0
			end	
		elseif player.vx < 0 then 
			player.vx = player.vx + (player.decceleration*dt)	
			if player.vx > 0 then 
				player.vx = 0
			end	
		end	
	end	

	player.x, player.y, cols, len = world:move(player, player.x+(player.vx or 0), player.y+(player.vy or 0))
end

function playerf.update(dt)
	playerf.movements(dt)
	playerf.gravity(dt)
end	

function playerf.draw()
	love.graphics.rectangle('fill',player.x,player.y,player.w,player.h)

	love.graphics.print(player.vx)
end	

function playerf.keypressed(key)
	if key == 'up' then 
		if player.jump1 == false then 
			player.jump1 = true 		
			player.vy = -player.max_height
		elseif player.jump1 == true and player.jump2 == false then 
			player.jump2 = true 		
			player.vy = -player.max_height/1.5
		end	
	end	
end	
---

-- GAME --
function game.load()
	playerf.load()
	cubes.add(100,400,600,30)
	cubes.add(0,0,100,600)
	cubes.add(200,50,200,100)
end

function game.update(dt)
	playerf.update(dt)
end

function game.draw()
	cubes.draw()
	playerf.draw()
end

function game.keypressed(key)
	playerf.keypressed(key)
end	
---

-- MAIN FUNCTIONS --
function love.load()
	love.window.setMode(810, 600)
    largeurScreen, hauteurScreen = love.window.getMode()
    love.graphics.setBackgroundColor(0,0,0)

    game.load()
    transition.load()
end

function love.update(dt)
	if gameScreen == 'game' then 
    	game.update(dt)
    else 
    	menu.update(dt)	
    end

    transition.update(dt)
end

function love.draw()
	if gameScreen == 'game' then 
    	game.draw()
    else 
    	menu.draw()	
    end

    transition.draw()
end	

function love.keypressed(key)
	if gameScreen == 'game' then 
		game.keypressed(key)
	else  
		menu.keypressed(key)
	end
end
---
I want to detect side collisions in order to create wall jumping effects.

Re: [bump] how to detect side collision

Posted: Sun Aug 25, 2019 1:21 pm
by MrFariator
For wall-jumps, in my game I simply use bump's queryRect method: When player presses the jump button while in mid-air, query a couple pixels wide rectangle on either side of the player's collision box for tiles (remember to use an appropriate filter), check if there is a surface the player can jump off of (simply check if len > 0), and act accordingly. This works well enough for a simple quick implementation, unless you want to integrate the wall detection into the regular physics upates for objects.

Re: [bump] how to detect side collision

Posted: Sun Aug 25, 2019 2:42 pm
by pgimeno
maxtrautwein wrote:
Sun Aug 25, 2019 11:32 am
Here is the entire code, sorry i don't know how to attach a file.
You can't attach files in "quick reply" mode. You have to press press "Full editor and preview" to get the interface that allows you to submit attachments. Anyway, the code you posted helped because it's self-contained. Thanks.

maxtrautwein wrote:
Sun Aug 25, 2019 11:32 am
You can focus on the 'playerf' functions. I don't know why but col.normal.y seems to work but col.normal.x doesn't work.
The collision you expect is happening, but in playerf.movements(), and you don't detect it there.

In a certain sense, Bump doesn't report collisions that are already resolved. More specifically, when the objects are touching but one of the objects is not moving towards the other, you don't get a collision. So, the resolution in playerf.movements() detects the contact and places the object touching the wall, but there's no code that checks the resulting collision at that point. When execution reaches playerf.gravity(), the wall and the player are already touching and you don't get the collision for it.

To avoid a problem such as the one you're having, you should call world:move() only once per frame, and check collisions there.