help with collisions

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
bobbymcbobface
Prole
Posts: 39
Joined: Tue Jun 04, 2019 8:31 pm

help with collisions

Post by bobbymcbobface » Wed Sep 04, 2019 5:55 pm

Hi all, i need some help introducing collision and collision detection to my game

things you need you might need to know

my game is top down
i need to allow certain tiles to have collision
i need to detect when a tile is collided with
I'm a complete noob at this and have no idea how collision works but i do have basic love2d knowledge :ultraglee:
I make games that run on potatoes :P

User avatar
pgimeno
Party member
Posts: 1827
Joined: Sun Oct 18, 2015 2:58 pm

Re: help with collisions

Post by pgimeno » Wed Sep 04, 2019 8:40 pm

My advice: don't try to come up with your own system. Use the built-in Box2D (love.physics) or a library that handles collisions like Bump or HC.

The simplest collision model is that where the colliding shapes are axis-aligned bounding boxes (AABBs). If you can get away with that in your game, then Bump is highly recommended. But if the shapes can be at an angle, or be non-rectangular, Bump won't help you, and you need either Box2D or HC.

Box2D has the advantages that it's in C/C++, that it's integrated with LÖVE, and that it handles collision response automatically (like Bump). The drawbacks are that it's more heavyweight and harder to manage, especially when you prefer cartoonish movement over physically realistic movement. For those cases, you may prefer HC, but IIRC you need to implement the collision response yourself. Fortunately it provides tools for that.

User avatar
raidho36
Party member
Posts: 1901
Joined: Mon Jun 17, 2013 12:00 pm

Re: help with collisions

Post by raidho36 » Thu Sep 05, 2019 5:50 am

If you want to get a game done, don't reinvent the wheels, find a pre-made tool and use it. If you want to get good, then by all means take your time to reinvent everything, but don't expect to actually make any games any time soon.

Games don't need high quality source code, they just need to function. But not having good programming skills will bottleneck a complicated or computationally intensive project.

User avatar
bobbymcbobface
Prole
Posts: 39
Joined: Tue Jun 04, 2019 8:31 pm

Re: help with collisions

Post by bobbymcbobface » Thu Sep 05, 2019 6:35 am

Ok thanks guys

And raidho36 I understand what you mean and I will admit my source code is a bit messy at the moment but in future when I get a better grasp at löve2d I'll fix it up, sure this may cause complications later on in the code but I don't mind re inventing it. Also does one of you or someone mind giving me an example of bump on a top down map since last time I tried it didn't even spawn the bump script

Thank you.
I make games that run on potatoes :P

User avatar
pgimeno
Party member
Posts: 1827
Joined: Sun Oct 18, 2015 2:58 pm

Re: help with collisions

Post by pgimeno » Thu Sep 05, 2019 1:15 pm

bobbymcbobface wrote:
Thu Sep 05, 2019 6:35 am
Also does one of you or someone mind giving me an example of bump on a top down map since last time I tried it didn't even spawn the bump script
Not sure what you mean by "spawn" the bump script. There's nothing special about a top-down map when it comes to handling collisions. Any example of bump is good. Some examples will apply gravity to some entities if they are a side view (like platformers) but that doesn't change the idea. You can check the "simpledemo" here: http://github.com/kikito/bump.lua/tree/simpledemo

The main idea of Bump is that every collidable surface is a box. If your map is made of tiles, and the tiles are either fully collidable or not collidable at all, then you just add to the Bump world the rectangles that correspond to the collidable tiles. If they are more complex, with some tiles subdivided into more rectangles, you need some way to store that info in the map, so that you can add each individual rectangle to the Bump world.

User avatar
bobbymcbobface
Prole
Posts: 39
Joined: Tue Jun 04, 2019 8:31 pm

Re: help with collisions

Post by bobbymcbobface » Thu Sep 05, 2019 6:25 pm

Ok I've had a look at the demo and a look around the internet and unfortunately I'm still extremely confused i understand how bump works (kind of) but I'm having troubles knowing the code for how i would store the data collisions for the map here's the code for my map i need to add collisions to:

Code: Select all

lobby = {}

function lobby:load()
  love.window.setFullscreen(true, "desktop")
  TileW, TileH = 32,32
  
  Tileset = love.graphics.newImage('mytileset.png')
  
  local tilesetW, tilesetH = Tileset:getWidth(), Tileset:getHeight()

  local quadInfo = {
    { 'o', 64, 0 },
    { 'O', 96, 0},
    
    { '[', 65, 32 },
    { '{', 65, 64 },
    
    { '-', 96, 32 },
    { '_', 96, 64 },
    
    { ']', 125, 32},
    { '}', 125, 64},
    
    { 'p', 224, 32},
    { ';', 224, 64}
  }

  Quads = {}
  for _,info in ipairs(quadInfo) do
    -- info[1] = character, info[2]= x, info[3] = y
    Quads[info[1]] = love.graphics.newQuad(info[2], info[3], TileW, TileH, tilesetW, tilesetH)
  end


  local tileString = [[
[----------]p[----------]
{__________};{__________}
ooooooooooooooooooooooooo
ooooooooooooooOoooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooOoooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooOoooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
oooooooooooOooooooooooooo
ooooooooooooooooooooooooo
]]

  TileTable = {}
  
  local width = #(tileString:match("[^\n]+"))
  
  for x = 1,width,1 do TileTable[x] = {} end

  local rowIndex,columnIndex = 1,1
  for row in tileString:gmatch("[^\n]+") do
    assert(#row == width, 'Map is not aligned: width of row ' .. tostring(rowIndex) .. ' should be ' .. tostring(width) .. ', but it is ' .. tostring(#row))
    columnIndex = 1
    for character in row:gmatch(".") do
      TileTable[columnIndex][rowIndex] = character
      columnIndex = columnIndex + 1
    end
    rowIndex=rowIndex+1
  end
end


function lobby:draw()
  
  for columnIndex,column in ipairs(TileTable) do
    for rowIndex,char in ipairs(column) do
      local x,y = (columnIndex-1)*TileW, (rowIndex-1)*TileH
      love.graphics.draw(Tileset, Quads[char], x, y)
    end
  end

end

return lobby

--- exit to room needed
--- character needed
---                       |
--- remember to use these V
---                      sprite:move_true()
---                      sprite:draw()
---                      menu:allow()
and here's the tile set image:
mytileset.png
mytileset.png (8.87 KiB) Viewed 1515 times
Can anyone help me implement it into my code or just give me a nudge in the correct direction
I make games that run on potatoes :P

User avatar
pgimeno
Party member
Posts: 1827
Joined: Sun Oct 18, 2015 2:58 pm

Re: help with collisions

Post by pgimeno » Thu Sep 05, 2019 8:27 pm

You create a world first with bump.newWorld(size) (I'll talk about size later). Then right after this line:

Code: Select all

TileTable[columnIndex][rowIndex] = character
you need to check if the character is one of the collidable map elements. If it is, you add the tile to the world. For example:

Code: Select all

world:add({x=columnIndex, y=rowIndex}, (columnIndex - 1)*TileW, (rowIndex - 1)*TileH, TileW, TileH)
That's assuming that your player position will be in pixels. If you wish the positions of your entities (e.g. the player) to be in map coordinates, it would be something like this instead:

Code: Select all

world:add({x=columnIndex, y=rowIndex}, columnIndex, rowIndex, 1, 1)
About size: creating the world with something like twice the size of your rectangles is OK, but take into account that the size of a map rectangle is 1 if you're using map coordinates, and 32 if you're using pixels with TileW=TileH=32.

User avatar
bobbymcbobface
Prole
Posts: 39
Joined: Tue Jun 04, 2019 8:31 pm

Re: help with collisions

Post by bobbymcbobface » Fri Sep 06, 2019 3:17 pm

ok thankyou pgimeno, so how would i go on about doing this:

"you need to check if the character is one of the collidable map elements."
I make games that run on potatoes :P

User avatar
pgimeno
Party member
Posts: 1827
Joined: Sun Oct 18, 2015 2:58 pm

Re: help with collisions

Post by pgimeno » Fri Sep 06, 2019 8:29 pm

One straightforward way is:

Code: Select all

 if character == "collidable_tile_1" or character == "collidable_tile_2" or character == "collidable_tile_3" or ... then
But you can define a table near the beginning instead, which is easier to modify later:

Code: Select all

local collidable_chars = { ["collidable_tile_1"] = true, ["collidable_tile_2"] = true, ... }

...

  if collidable_chars[character] then
I'm not sure which characters in your map represent collidable tiles, but assuming for example that 'o' and 'O' are both collidable, one way to start would be:

Code: Select all

local collidable_chars = { ["o"] = true, ["O"] = true, ... }

User avatar
bobbymcbobface
Prole
Posts: 39
Joined: Tue Jun 04, 2019 8:31 pm

Re: help with collisions

Post by bobbymcbobface » Sat Sep 07, 2019 6:31 am

Ah thankyou, I'll try this as soon as I get a chance

EDIT: ok i managed to experiment with the code and so far i have this:

Code: Select all

lobby = {}

local sprite = require('sprite')
local bump = require('bump')

function lobby:load()
  sprite:move_true()
  --sprite:add_collision({x=columnIndex, y=rowIndex}, columnIndex, rowIndex, 1, 1)
  
  print('map check:')
  
  world = bump.newWorld(32)

  TileW, TileH = 32,32
  
  Tileset = love.graphics.newImage('mytileset.png')
  
  local tilesetW, tilesetH = Tileset:getWidth(), Tileset:getHeight()
  
  local collidable_chars = { ["p"] = true, ["p"] = true}
  
  local quadInfo = {
    { 'o', 64, 0 },
    { 'O', 96, 0},
    
    { '[', 65, 32 },
    { '{', 65, 64 },
    
    { '-', 96, 32 },
    { '_', 96, 64 },
    
    { ']', 125, 32},
    { '}', 125, 64},
    
    { 'p', 224, 32},
    { ';', 224, 64}
  }

  Quads = {}
  for _,info in ipairs(quadInfo) do
    -- info[1] = character, info[2]= x, info[3] = y
    Quads[info[1]] = love.graphics.newQuad(info[2], info[3], TileW, TileH, tilesetW, tilesetH)
  end


  local tileString = [[
[----------]p[----------]
{__________};{__________}
ooooooooooooooooooooooooo
ooooooooooooooOoooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooOoooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooOoooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
ooooooooooooooooooooooooo
oooooooooooOooooooooooooo
ooooooooooooooooooooooooo
]]

  TileTable = {}
  
  local width = #(tileString:match("[^\n]+"))
  
  for x = 1,width,1 do TileTable[x] = {} end

  local rowIndex,columnIndex = 1,1
  for row in tileString:gmatch("[^\n]+") do
    assert(#row == width, 'Map is not aligned: width of row ' .. tostring(rowIndex) .. ' should be ' .. tostring(width) .. ', but it is ' .. tostring(#row))
    columnIndex = 1
    for character in row:gmatch(".") do
      TileTable[columnIndex][rowIndex] = character
      
      if collidable_chars['o'] then
        sprite:add_collision({x=columnIndex, y=rowIndex}, (columnIndex - 1)*TileW, (rowIndex - 1)*TileH, TileW, TileH)
        
      end
      columnIndex = columnIndex + 1
    end
    rowIndex=rowIndex+1
  end
end


function lobby:draw()
  for columnIndex,column in ipairs(TileTable) do
    for rowIndex,char in ipairs(column) do
      local x,y = (columnIndex-1)*TileW, (rowIndex-1)*TileH
      love.graphics.draw(Tileset, Quads[char], x, y)
    end
  end
  
  sprite:draw()

end

return lobby

--- exit to room needed
--- character needed
---                       |
--- remember to use these V
---                      sprite:move_true()
---                      sprite:draw()
---                      menu:allow()
---                      themap:load()
---                      love.graphics.draw(tilesetBatch)
and this doesn't seem to sort out any collsion can someone do some debugging on my code and help me out

also for reference here is the code for sprite:add_collision() :

Code: Select all

function sprite:add_collision(item, x, y, w ,h)
    world:add(item, x, y, w, h)
end
thankyou
I make games that run on potatoes :P

Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests