How to use bump.lua
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
-
- Prole
- Posts: 10
- Joined: Thu Sep 04, 2014 7:38 pm
How to use bump.lua
I have been reading guides and documentation, and frankly it makes no sense how to use bump.lua. I know how to declare two objects with colliders, but I don't really understand how they detect collision. I am making a top down (zelda styled) rpg, and I want the character to stop moving when they collide with the edges of the map (along with props in the world). How would this be done? I'm seriously confused.
- Lacotemale
- Citizen
- Posts: 75
- Joined: Sat Mar 08, 2014 9:01 pm
Re: How to use bump.lua
I also posted in my own thread about this. I don't know how to use the damn thing and I will have to consider using something else soon. T_T
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: How to use bump.lua
Hi there!
------
Let me try to explain how bump works in steps. I recommend you to follow each step and test it in an empty main.lua. I am not trying all the tests myself so I might make typos.
STEP 1:
The first thing you have to do is downloading the bump.lua file and putting it somewhere in your game folder (people usually put it inside a lib/ folder).
Then, require it wherever you use it. For example, if you put bump.lua next to main.lua, you can require it like this from main.lua:
STEP 2:
The next thing you must do is creating a world with bump.newWorld. The simplest think I can think of is making it local in main.lua:
STEP 3:
In bump, a world is just a place where you put items. Items are everything which participates in collisions in your game: the player, the blocks, bullets, powerups, etc. Every item will have an associated rectangle. Generally, items are tables.
In order to add items to a world, you use world:add. Let's start with the player. Imagine that our player character is a 32x32 image that starts in {100, 100}. You need to create a table for it, and then tell the world about it.
- Note that for simplicity I am going to use x and y on this example, but in bump those variables are called l (for left) and t (for top). This is because sometimes x,y is the center of the rectangle, not its left-top corner -
STEP 4:
Now, when you move the player with the arrow keys, you must do two things: You must change the values of x and y in the player table, and also update the bounding box associated with the player in the world. You do this with world:move. This is one possible way to do it:
STEP 5:
We need to add some blocks now. Blocks are easy because they don't move. I am going to store them in a variable called blocks. To make things a bit easier, I am going to use a function called addBlock. I am going to create only two blocks; you can create more if you need.
STEP 6:
But now the player does not interact with the blocks at all; it moves through them. We must check for collisions. The way we check for collisions in bump is by calling world:check. It works as follows: we pass it an item (in this case, the player) and the coordinates where it wants to go. world:check returns a list of collisions and its length. If the way is free, then the list of collisions is empty, and its length will be 0.
So we can do a rough collision detection phase like this:
STEP 7:
The thing is, this is not enough. There are two problems:
In our case, we're going to use the "slide" resolution, so our player can "move diagonally and still go up" when facing a wall. collision:getSlide returns "the coordinates of the player who wanted to go to future_x and future_y after he collided with a block, sliding over it" (plus more things, like the coordinates where the player started touching the block, and the contact normal).
Here is a better (but still not perfect) approach to resolution, using the first collision:
STEP 8:
This solves the first problem (there is no invisible barrier any more). But it makes some things worse. There are some occasions when the player collides simultaneously with more than 1 block (for example, when moving diagonally up-right to the up-right corner of a room). This code handles collisions with 1 block only, so when the player hits more than 1, it only collides with the nearest one, ignoring the rest.
Since the number of colliding blocks is unknown, we can't solve it with if-elses; we must use a loop, so we collide with the first block, then slide over it, then collide with the second, etc. There is a problem though: after sliding over the first block, the other collisions are not valid and must be recalculated. Also, sliding over more than 1 block will give bad results - we must slide only on the "last block colliding". For the rest, the player must act as a bullet, "getting stuck".
This all gives us the following code:
That's it. Now it should work more or less like Zelda.
Incidentally, this code is almost a copy from bump's simple demo. Launch it up if you want to see it in action (the only thing that demo adds is debugging info).
There are more advanced stuff to do from here: filtering collisions, colliding with different kinds of items, and spatial queries. But I hope this explanation gets you started.
I didn't see it, sorry. Can you give me a link? EDIT: Found it. For the record, I never browse "kitchen sink" threads that ask about everything and anything. Next time, consider creating a new thread per question/subject, with a descriptive title, like crystalheartstudios did; you will get more attention.Lacotemale wrote:I also posted in my own thread about this.
------
Let me try to explain how bump works in steps. I recommend you to follow each step and test it in an empty main.lua. I am not trying all the tests myself so I might make typos.
STEP 1:
The first thing you have to do is downloading the bump.lua file and putting it somewhere in your game folder (people usually put it inside a lib/ folder).
Then, require it wherever you use it. For example, if you put bump.lua next to main.lua, you can require it like this from main.lua:
Code: Select all
local bump = require 'bump'
The next thing you must do is creating a world with bump.newWorld. The simplest think I can think of is making it local in main.lua:
Code: Select all
local bump = require 'bump'
local world
function love.load()
world = bump.newWorld()
end
In bump, a world is just a place where you put items. Items are everything which participates in collisions in your game: the player, the blocks, bullets, powerups, etc. Every item will have an associated rectangle. Generally, items are tables.
In order to add items to a world, you use world:add. Let's start with the player. Imagine that our player character is a 32x32 image that starts in {100, 100}. You need to create a table for it, and then tell the world about it.
- Note that for simplicity I am going to use x and y on this example, but in bump those variables are called l (for left) and t (for top). This is because sometimes x,y is the center of the rectangle, not its left-top corner -
Code: Select all
local bump = require 'bump'
local world
local player
function love.load()
world = bump.newWorld()
player = {x=100, y=100, w=32, h=32}
world:add(player, player.x, player.y, player.w, player.h)
end
function love.draw()
love.graphics.rectangle(player.x, player.y, player.w, player.h)
end
Now, when you move the player with the arrow keys, you must do two things: You must change the values of x and y in the player table, and also update the bounding box associated with the player in the world. You do this with world:move. This is one possible way to do it:
Code: Select all
...
function love.update(dt)
local player_speed = 60
-- update the player if the keys are pressed
if love.keyboard.isDown('up') then
player.y = player.y - player_speed * dt
elseif love.keyboard.isDown('down') then
... (repeat with down, left and right)
end
-- update the player associated bounding box in the world
world:move(player, player.x, player.y) -- player.w and player.h remain the same if not passed
end
We need to add some blocks now. Blocks are easy because they don't move. I am going to store them in a variable called blocks. To make things a bit easier, I am going to use a function called addBlock. I am going to create only two blocks; you can create more if you need.
Code: Select all
local bump = require 'bump'
local world
local player
local blocks
local function addBlock(x,y,w,h)
local block = {x=x,y=y,w=w,h=h}
blocks[#blocks + 1] = block
world:add(block, x,y,w,h)
end
function love.load()
world = bump.newWorld()
player = {x=100, y=100, w=32, h=32}
world:add(player, player.x, player.y, player.w, player.h)
addBlock(50, 100, 200, 32)
addBlock(150, 100, 100, 32)
end
function love.draw()
love.graphics.rectangle(player.x, player.y, player.w, player.h)
for i=1, #blocks do
local b = blocks[i]
love.graphics.rectangle(b.x, b.y, b.w, b.h)
end
end
But now the player does not interact with the blocks at all; it moves through them. We must check for collisions. The way we check for collisions in bump is by calling world:check. It works as follows: we pass it an item (in this case, the player) and the coordinates where it wants to go. world:check returns a list of collisions and its length. If the way is free, then the list of collisions is empty, and its length will be 0.
So we can do a rough collision detection phase like this:
Code: Select all
...
function love.update(dt)
local player_speed = 60
local future_x, future_y = player.x, player.y
-- update future_x and future_y variables if the keys are pressed
if love.keyboard.isDown('up') then
future_y = future_y - player_speed * dt
elseif love.keyboard.isDown('down') then
... (repeat with down, left and right)
end
-- get the collisions
local collisions, len = world:check(player, future_x, future_y)
-- If there where no collisions, we can move the player safely
if len == 0 then
player.x, player.y = future_x, future_y
world:move(player, player.x, player.y)
end
end
The thing is, this is not enough. There are two problems:
- It is not possible to do "partial steps". If the player goes fast enough, it will seem that he stops before he touches the blocks - there will be "phantom borders" around blocks sometimes. Plus, this depends on lots of things (like the speed of the computer)
- The player doesn't "slide over blocks" when going diagonally; the moment a collision is detected, it stops.
In our case, we're going to use the "slide" resolution, so our player can "move diagonally and still go up" when facing a wall. collision:getSlide returns "the coordinates of the player who wanted to go to future_x and future_y after he collided with a block, sliding over it" (plus more things, like the coordinates where the player started touching the block, and the contact normal).
Here is a better (but still not perfect) approach to resolution, using the first collision:
Code: Select all
function love.update(dt)
... (same as before)
-- get the collisions
local collisions, len = world:check(player, future_x, future_y)
-- If there where no collisions, we can move the player safely
if len == 0 then
player.x, player.y = future_x, future_y
world:move(player, player.x, player.y)
elseif len == 1 then
local _,_,_,_,slide_x, slide_y = collisions[i]:getSlide()
player.x, player.y = slide_x, slide_y
world:move(player, player.x, player.y)
end
end
This solves the first problem (there is no invisible barrier any more). But it makes some things worse. There are some occasions when the player collides simultaneously with more than 1 block (for example, when moving diagonally up-right to the up-right corner of a room). This code handles collisions with 1 block only, so when the player hits more than 1, it only collides with the nearest one, ignoring the rest.
Since the number of colliding blocks is unknown, we can't solve it with if-elses; we must use a loop, so we collide with the first block, then slide over it, then collide with the second, etc. There is a problem though: after sliding over the first block, the other collisions are not valid and must be recalculated. Also, sliding over more than 1 block will give bad results - we must slide only on the "last block colliding". For the rest, the player must act as a bullet, "getting stuck".
This all gives us the following code:
Code: Select all
function love.update(dt)
... (same as before)
-- get the collisions
local collisions, len = world:check(player, future_x, future_y)
-- If there where no collisions, we can move the player safely
if len == 0 then
player.x, player.y = future_x, future_y
world:move(player, player.x, player.y)
else
local col, tx, ty, sx, sy
while len > 0 do
col = cols[1]
tx,ty,_,_,sx,sy = col:getSlide()
-- Move the player so that it "touches" the block
player.l, player.t = tx, ty
world:move(player, tx, ty)
-- See if it collisions on anything else while "sliding" over the block
cols, len = world:check(player, sx, sy)
if len == 0 then -- If not colliding with anything else, slide. Otherwise, touch the next block and try sliding over it
player.l, player.t = sx, sy
world:move(player, sx, sy)
end
end
end
end
Incidentally, this code is almost a copy from bump's simple demo. Launch it up if you want to see it in action (the only thing that demo adds is debugging info).
There are more advanced stuff to do from here: filtering collisions, colliding with different kinds of items, and spatial queries. But I hope this explanation gets you started.
When I write def I mean function.
-
- Prole
- Posts: 10
- Joined: Thu Sep 04, 2014 7:38 pm
Re: How to use bump.lua
Well the information is nice, but what I'm trying to do doesn't seem to fit in what you are describing. For example, I am making a zelda/pokemon-esque game and I need to set up colliders around the edge of the map so that my character cannot move out of the boundaries of the map, along with not being able to pass through different objects (say trees). I just feel like there has to be a simpler way.
- Lacotemale
- Citizen
- Posts: 75
- Joined: Sat Mar 08, 2014 9:01 pm
Re: How to use bump.lua
I have attached a love file here of my work in progress (or not very good progress you might say) x)
I think my main problem with bump is the coords of the player collision box are not actually the coords of the player. I don't know how to explain what is going on except that the box isn't following the player but something else.
Any ideas how I can fix this?
I think my main problem with bump is the coords of the player collision box are not actually the coords of the player. I don't know how to explain what is going on except that the box isn't following the player but something else.
Any ideas how I can fix this?
- Attachments
-
- WhiteGuardian.L2D.love
- (1.13 MiB) Downloaded 395 times
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: How to use bump.lua
The simplest way to do that is: create one block per border, and one block per unwalkable object. Make sure that the basic rectangles work as expected. Then, draw nice graphics instead of drawing rectangles. To do the first part, you just need to call addblock more times, with different parameters. The basic demo is a zelda like with squares instead of graphics.\\crystalheartstudios wrote:I need to set up colliders around the edge of the map so that my character cannot move out of the boundaries of the map, along with not being able to pass through different objects (say trees).
I gave this a quick look so I am not sure I found all the issues.Lacotemale wrote:Any ideas how I can fix this?
1- You are moving the player before checking for collisions.
Code: Select all
-- see if A is colliding with anything
world:move(A, player.x, player.y)
local collisions, len = world:check(B)
2- Use the real objects of your game in world:add, don't create "extra objects with a name"
Instead of this:
Code: Select all
-- create two rectangles
A = {name="A"}
B = {name="B"}
-- insert both rectangles into bump
world:add(A, player.x, player.y, 100, 100) -- left, top, width, height
world:add(B, item.x, item.y, 100, 100)
...
-- see if A is colliding with anything
world:move(A, player.x, player.y)
Code: Select all
-- insert both rectangles into bump
world:add(player, player.x, player.y, 100, 100) -- left, top, width, height
world:add(item, item.x, item.y, 100, 100)
...
-- see if player is colliding with anything
world:move(player, player.x, player.y)
3- You are moving item instead of moving the player when keys are pressed:
Code: Select all
if down("w") or down("up") then
item.y = item.y + speed * dt
sprite.y = sprite.y - speed * dt
walkDown:stop()
walkUp:play()
walkUp:update(dt)
end
That's all I could find in a quick look.
I recommend you to remove the graphical part and start with drawing just rectangles. Once you get the rectangles working, get the graphics on top of them. Doing it the other way around makes it more difficult to find bugs like this.
When I write def I mean function.
Re: How to use bump.lua
Hey, I have been trying to learn bump since yesterday, I'm starting to understand :getSlide() and :move, :check. I have followed the examples up until step 7 where local _,_,_,_, is and I don't understand what I should put there. Up until step 6 I followed as well, the player doesn't move, why?
I have attached .love file.
Bindie
I have attached .love file.
Bindie
- Attachments
-
- Bump.love
- (7.04 KiB) Downloaded 353 times
Re: How to use bump.lua
The example in this thread is old. Follow the example / documentation on the github instead.Bindie wrote:Hey, I have been trying to learn bump since yesterday, I'm starting to understand :getSlide() and :move, :check. I have followed the examples up until step 7 where local _,_,_,_, is and I don't understand what I should put there. Up until step 6 I followed as well, the player doesn't move, why?
I have attached .love file.
Bindie
Basically, what you'll want here for the player's collision detection is this:
Code: Select all
-- update the player associated bounding box in the world
local newX, newY, cols, len = world:move(player, player.x, player.y)
player.x, player.y = newX, newY
Code: Select all
local bump = require 'bump'
local world
local player
local blocks = {}
local function addBlock(x,y,w,h)
local block = {x=x, y=y, w=w, h=h}
blocks[#blocks+1] = block
world:add(block, x,y,w,h)
end
function love.load(arg)
world = bump.newWorld()
player = {x=100, y=200, w=32, h=32, speed = 60, col = 0, len = 0}
world:add(player, player.x,player.y, player.w, player.h)
addBlock(50,100,200,32)
addBlock(150,100,100,32)
end
function love.update(dt)
-- update the player.x and player.y when arrow keys are pressed
if love.keyboard.isDown('up') then
player.y = player.y - player.speed * dt
elseif love.keyboard.isDown('down') then
player.y = player.y + player.speed * dt
elseif love.keyboard.isDown('left') then
player.x = player.x - player.speed * dt
elseif love.keyboard.isDown('right') then
player.x = player.x + player.speed * dt
end
-- update the player associated bounding box in the world
local newX, newY, cols, len = world:move(player, player.x, player.y)
player.x, player.y = newX, newY
end
function love.draw(dt)
love.graphics.rectangle('fill', player.x, player.y, player.w, player.h)
for i=1, #blocks do
local b = blocks[i]
love.graphics.rectangle('line', b.x, b.y, b.w, b.h)
end
end
Re: How to use bump.lua
Thanks, awesome.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: How to use bump.lua
Hey, I got here but Kingdaro had already answered. Thanks a lot, buddy!
When I write def I mean function.
Who is online
Users browsing this forum: Bing [Bot] and 6 guests