Need help with BUMP collission resolution

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
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Need help with BUMP collission resolution

Post by Imaculata »

I'm just getting started with BUMP, and while the basics seem straight forward, the documentation leaves a little bit to be desired. Specifically regarding collision types, and collision resolution.

I've got a basic 2d tile-based platformer working, with "slide" as the collision resolution. Of course, "slide" is the default, which is probably the only reason it is working at all. But I also want to have ladders, that use the "touch" collision type. The problem is, I have no idea how to actually define what the collision type is for my ladder-tiles (and the documentation makes no mention of it either). So now the player is just blocked by them, just as with any other wall. So obviously the actual collision type is not being registered at all.

I'm currently handling player movement and collision detection with this code in main.lua, which seems right:

Main.lua:

Code: Select all

function movePlayer(playertomove,goalX,goalY,filter)

  -- get the collisions

	local actualX, actualY, cols, len = world:move(playertomove, goalX, goalY, filter)
	
	--Handle collisions
	for i=1, #cols do
		local col = cols[i]
		print(("col.other = %s, col.type = %s, col.normal = %d,%d"):format(col.other, col.type, col.normal.x, col.normal.y))
	end
	
	return actualX, actualY
	
end
And I have the following code for the player collision filter in a separate player script:

Playerfunctions.lua:

Code: Select all

local playerFilter = function(item, other)

print("Checking collisions...")

  if other.isWall or (other.isPlatform and player.Y >= other.y + other.h) then return 'slide'
  elseif object.isItem or object.isBullet or object.isEnemy then return "cross"
  elseif object.isLadder or object.isZone then return "touch"
  elseif object.isLaunch then return "bounce"
  else return nil
  end
  
end
I then call this function to update the player's position:

Code: Select all

player1.X, player1.Y = movePlayer("Player",(player1.X + player1.speed[1]),(player1.Y + player1.speed[2]),playerFilter)
I use the following code to add any wall tiles to BUMP as the map is being loaded:

Main.lua:

Code: Select all

function setupMap() --Set up the map
  --The tile sheet
  tilesetImage = love.graphics.newImage("/sprites/tiles.png")
  collisionReference = {}
  collisionReference = loadCollision("/sprites/collisionreference.lua")
  
  --FORMAT: Mapfilename, Scenarioname, swimmers, lifeguards, police, heroes
  currentlevel = {"royaltomb", "Royal Tomb"} --1: "Filename", 2: "LevelName"
  print("Loading map: "..currentlevel[1])
  newlevel = loadMap("maps/"..currentlevel[1]..".lua") --1:background,2:foreground,3:entities
  
  mapWidth = #newlevel[1][1] --tilesetImage:getWidth()/tileSize
  mapHeight = #newlevel[1] --tilesetImage:getHeight()/tileSize
  print("Mapsize:"..mapWidth*tileSize..","..mapHeight*tileSize)
  cameraBounds = {1,1,(mapWidth-(tilesDisplayWidth*zoomlevel)-(tileSize/2)),(mapHeight-(tilesDisplayHeight*zoomlevel))} --42.5,32
  mapBounds = {mapWidth,mapHeight}
  mapMaxScrollSpeed = 0.5
  mapScrollSpeed = mapMaxScrollSpeed
 
 --Here is where we load the map
 --Create empty placeholders
  map = {}
  collisions = {}
  
  --Fill the map with tiles
	for x=1,mapWidth do
		map[x] = {}
		collisions[x] = {}
		for y=1,mapHeight do
			map[x][y] = (newlevel[1][y][x]) +1 --Copy all background tiles
			
			--Check collision
			--"."=nocollision,"x"=wall,"c"=climb,"s"=spike,"w"=water,"l"=lava,"f"=fake,"h"=hidden,"sr"=stairsright,"sl"=stairsleft,"k"=killzone
			local tiletype1
			local tiletype2
			--print("Checking: "..(math.ceil(newlevel[2][y][x] / (tilesetImage:getWidth()/tileSize))).." | "..(tilesetImage:getWidth()/tileSize) - (((math.ceil(newlevel[2][y][x] / (tilesetImage:getWidth()/tileSize)))*(tilesetImage:getWidth()/tileSize))-newlevel[2][y][x]))
			if ((newlevel[1][y][x])+1 > 0) then
			--(tile )
			tiletype1 = collisionReference[math.ceil((newlevel[1][y][x]+1) / (tilesetImage:getWidth()/tileSize))][(tilesetImage:getWidth()/tileSize) - (((math.ceil((newlevel[1][y][x]+1) / (tilesetImage:getWidth()/tileSize)))*(tilesetImage:getWidth()/tileSize))-(newlevel[1][y][x]+1))]
				if (tiletype1 == "c") then
					--print("Added ladder tile at: "..x..","..y)
				end
			else
			tiletype1 = "."
			end
			
			--Normal player collisions 
			if (tiletype1 == "x" or tiletype1 == "h") then
			collisions[x][y] = "x"
			local Wallblock = {name="Wall"..(x+(y*mapWidth)-mapWidth),isWall}
			addCollision(Wallblock, (x*tileSize), (y*tileSize),tileSize,tileSize)
			else
			--Check for top of ladder
				if (y > 1 and tiletype1 == "c") then
					if ((newlevel[1][y-1][x]+1) > 0) then
						local tileabove = collisionReference[math.ceil((newlevel[1][y-1][x]+1) / (tilesetImage:getWidth()/tileSize))][(tilesetImage:getWidth()/tileSize) - (((math.ceil((newlevel[1][y-1][x]+1) / (tilesetImage:getWidth()/tileSize)))*(tilesetImage:getWidth()/tileSize))-(newlevel[1][y-1][x]+1))]
						if (tileabove == ".") then
							--print("Added top of ladder above tile "..x..","..y..", IMAGE: "..(newlevel[1][y][x]+1))
							collisions[x][y] = "x"
							local Ladder = {name="Ladder"..(x+(y*mapWidth)-mapWidth),isLadder}
							addCollision(Ladder, (x*tileSize), (y*tileSize),tileSize,tileSize)
							--Also add the ladder interact tile here!
						else
							collisions[x][y] = "."
							local Ladder = {name="Ladder"..(x+(y*mapWidth)-mapWidth),isLadder}
							addCollision(Ladder, (x*tileSize), (y*tileSize),tileSize,tileSize)
						end
					else
						collisions[x][y] = "."
					end
				else
					collisions[x][y] = "."
				end
			end
		end
	end
	
end
I suspect the following bit of code is probably crucial:

Code: Select all

local Wallblock = {name="Wall"..(x+(y*mapWidth)-mapWidth),isWall}
addCollision(Wallblock, (x*tileSize), (y*tileSize),tileSize,tileSize)
The above code is how I add my wall tiles to BUMP, and I try to insert the boolean isWall at the end. I'm trying to do the same for ladder tiles, with the difference of adding the boolean isLadder instead. The documentation gives no explanation how to do this, so this is purely me desperately trying to get this to work, and obviously it isn't working.

I've been checking some of the examples that the BUMP documentation refers to, but they all rely completely on the library "middleclass". Which makes it impossible for me to understand how to actually implement collision types without the use of this library. Surely this should be a simple thing to do?

Can anyone help a newb out with this?
User avatar
0x72
Citizen
Posts: 55
Joined: Thu Jun 18, 2015 9:02 am

Re: Need help with BUMP collission resolution

Post by 0x72 »

Code: Select all

bad = { isWall }
print(bad.isWall) -- nil
good = { isWall=true }
print(good.isWall) -- true
User avatar
Smoggert
Prole
Posts: 29
Joined: Thu Nov 10, 2016 11:23 pm

Re: Need help with BUMP collission resolution

Post by Smoggert »

0x72 wrote: Tue Feb 28, 2017 6:22 pm

Code: Select all

local isWall = true
bad = { isWall }
print(bad.isWall) -- nil
print(bad[1]) -- true
good = { isWall=true }
print(good.isWall) -- true
To see what's actually going on
User avatar
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Re: Need help with BUMP collission resolution

Post by Imaculata »

Thanks a lot! I'm going to give that a try first thing tomorrow.
User avatar
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Re: Need help with BUMP collission resolution

Post by Imaculata »

Hmm, it still doesn't seem to be working.

So, first of all, before I move the player, I initialize the playerFilter, like so:

playerfunctions.lua:

Code: Select all

local playerFilter = function(item, other)

print("Checking collisions...")

  if other.isWall or (other.isPlatform and player1.Y >= other.y + other.h) then return 'slide'
  elseif other.isItem or other.isBullet or other.isEnemy then return "cross"
  elseif other.isLadder or other.isZone then return "touch"
  elseif other.isLaunch then return "bounce"
  else return nil
  end
  
end
As you can see, I've added a print command to it, for debugging purposes. But I have yet to see this message. So it doesn't seem like the filter is being used at all.

Whenever I then try to move the player, I run this script:

playerfunctions.lua:

Code: Select all

player1.X, player1.Y = movePlayer("Player",(player1.X + player1.speed[1]),(player1.Y + player1.speed[2]),playerFilter)
This script basically runs every frame. As you can see, I pass the local playerFilter along to main.lua.
This is then received by the following script, which does the actual bump collision detection:

main.lua:

Code: Select all

function movePlayer(playertomove,goalX,goalY,filter)

  -- get the collisions

	local actualX, actualY, cols, len = world:move(playertomove, goalX, goalY, filter)
	
	return actualX, actualY
	
end
Now this should work, but I don't get the impression that the filter is being used at all, since I'm not seeing my print command.

I've also made the changes you've suggested, by changing the code for how blocks are added to bump.world:

main.lua:

Code: Select all

local Wallblock = {name="Wall"..(x+(y*mapWidth)-mapWidth),isWall=true}
addCollision(Wallblock, (x*tileSize), (y*tileSize),tileSize,tileSize)
I'm thinking this should theoretically work. You should be able to check if whatever the player collided with has the boolean "isWall" set to true, and thus respond to it with "slide" behavior. Since "slide" is the default though, of course that works.

Likewise, I've also changed the script for the ladder blocks:

main.lua:

Code: Select all

local Ladder = {name="Ladder"..(x+(y*mapWidth)-mapWidth),isLadder=true}
addCollision(Ladder, (x*tileSize), (y*tileSize),tileSize,tileSize)
Ladder blocks now have the boolean "isLadder" set to true, and should return the "touch" behavior when the player touches them. At least, according to the "playerFilter". But that isn't happening. In fact, there is no indication that the playerFilter is being used at all.
User avatar
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Re: Need help with BUMP collission resolution

Post by Imaculata »

UPDATE! I figured it out I think. It seems the playerFilter, since it is a function, does not like being passed along to another script as if it were a local value. I'm not exactly sure why this doesn't work, but moving the playerFilter to main.lua instantly causes the filter to work.

But the boolean had to be fixed too, so again thanks for pointing out my error. I was doing two things wrong!
User avatar
0x72
Citizen
Posts: 55
Joined: Thu Jun 18, 2015 9:02 am

Re: Need help with BUMP collission resolution

Post by 0x72 »

This cannot be the case, functions are first class in lua.

Difficult to say without full code but I assume you didn't pass the function from playerfunctions.lua to main.lua at all. I.e. you declare:

Code: Select all

-- playerfunctions.lua
local playerFilter = function(item, other) --[[...]] end
and then you import

Code: Select all

-- main.lua
require('playerfunctions')
Don't expect to have access to playerFilter variable - it's local to playerfunctions module, so when you:

Code: Select all

movePlayer("Player",x, y, playerFilter)
print(playerFilter) -- nil
than - again - playerFilters is nil instead of what you intended; bump accepts nil as a filter argument (defaults to no filter)

If that's the case you need too return you functions from playerfunctions.lua. e.g. like that:

Code: Select all

-- playerfunctions.lua
local playerFilter = function(item, other) --[[...]] end

return {
  playerFilter = playerFilter
}
and then in main e.g:

Code: Select all

local playerFilter = require('playerfunctions').playerFilter
-- ...
movePlayer("Player",x, y, playerFilter)
---

Alternatively you could make the function global so it's accessible from anywhere, but this is usually discouraged.

---

You're gonna face more issues like that so to prevent those I suggest: http://metalua.luaforge.net/src/lib/strict.lua.html
User avatar
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Re: Need help with BUMP collission resolution

Post by Imaculata »

Thanks for all the great advise. I've got it working now.

Now its just a matter of cleaning up all the movement rules for the player, so she can smoothly transition between normal movement and climbing ladders. That will just take a bit of trial and error.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 6 guests