Collision grid

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.
florodude
Prole
Posts: 20
Joined: Mon Jul 30, 2012 10:16 pm

Collision grid

Post by florodude »

Hey guys, what I want is a collision map that is set up by adding another variable to my map. For example, grass would have it's collision set to 1, and you wouldn't be able to pass through it. Here is my map code.

Code: Select all

  Tileset = love.graphics.newImage('tileset1.bmp')
  
TileW, TileH = 50,50
tilesetW, tilesetH = Tileset:getWidth(), Tileset:getHeight()

  local tileString = [[
  &&&&&&&  sssss
  &#####&  swwws
  &#####&  swwws
  &&&*&&&  sssss
                
                
]]


local quadInfo = {
  { ' ', 0,  0 , 0 }, -- grass 
  { 'p', 50,  0 , 0 }, -- spess
  { '&', 0, 50 , 1 }, -- wall
  { '*', 50, 50, 1 },  -- door  ##<<<< See the fourth variable here?  This is the one I want to control collision
  { 'w', 100, 0 , 1},  -- water
  { '#', 0, 100 , 0 },  -- tiles
  { 's', 100, 50 , 0 }  -- sand 
}


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

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

columntest = 1
rowtest = 1

function drawmap()
  for columnIndex,column in ipairs(TileTable) do
    for rowIndex,char in ipairs(column) do
      local x,y = (columnIndex-columntest)*TileW, (rowIndex-rowtest)*TileH
      love.graphics.drawq(Tileset, Quads[char], x, y)
    end
  end

end


If it is needed, here's my player movement code.

Code: Select all

gridx = 1
gridy = 1

pdt = dt
gridx = 1
gridy = 1

playerxx = gridx * 50
playeryy = gridy * 50
player = love.graphics.newImage("player.png")
0


function Drawplayer()
love.graphics.draw(player, playerxx, playeryy)
	


end


function playermove()
function love.keypressed(key)
  if key=='right' then
    gridx = gridx + 1
 

  elseif key=='up' then
    gridy = gridy - 1


  elseif key=='down' then
    gridy = gridy + 1
  

  elseif key=='left' then
    gridx = gridx - 1
  end
end
playerxx = gridx * 50
playeryy = gridy * 50
end
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision grid

Post by micha »

You didn't ask a question, so my wild guess is that you want to know how this is done. Correct?
The answer:
In the movement code, replace this

Code: Select all

if key=='right' then
    gridx = gridx + 1
by

Code: Select all

if key=='right' and collision[gridx+1][gridy] == 0 then
    gridx = gridx + 1
which means you check the cell the player is supposed to move to, before you actually move there.

However to make this work you first need to fill the table "collision"

So here:

Code: Select all

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
you add the follwing

Code: Select all

Quads = {}
CharToCollision = {}
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)
  CharToCollision[info[1]] = info[4]
end
If for example you write CharToCollision['p'] you get a 0, which means not-blocked.
Next you extend this part:

Code: Select all

  for character in row:gmatch(".") do
    TileTable[columnIndex][rowIndex] = character
    columnIndex = columnIndex + 1
  end
Like this:

Code: Select all

  for character in row:gmatch(".") do
    TileTable[columnIndex][rowIndex] = character
    collision[columnIndex][rowIndex] = CharToCollision[character]
    columnIndex = columnIndex + 1
  end
Don't forget to initialize the table "collision" before.
florodude
Prole
Posts: 20
Joined: Mon Jul 30, 2012 10:16 pm

Re: Collision grid

Post by florodude »

First of all, you are like an answer to prayers. However I'm having a noob moment, can you show me how you want me to initialize the collision table?
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision grid

Post by micha »

The same as for the TileTable:

Code: Select all

TileTable = {}
for x = 1,width,1 do TileTable[x] = {} end
just substitute "TileTable" with "collision".
florodude
Prole
Posts: 20
Joined: Mon Jul 30, 2012 10:16 pm

Re: Collision grid

Post by florodude »

Alright, putting all that code in now works without errors, but my char doesn't move.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision grid

Post by micha »

Here is a quick and dirty debuggin tip: Use the commant "print" to output some debugging information. For example when the player is supposed to move, you can output the current coordinates, and the value of the collision table, that is checked. That's how I do debugging.

If that doesn't help, the best is to upload your current .love file.
florodude
Prole
Posts: 20
Joined: Mon Jul 30, 2012 10:16 pm

Re: Collision grid

Post by florodude »

User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision grid

Post by micha »

Next time you can upload a love file directly in the forum (no need for mediafire and stuff).

First thing I noticed, your code is not indented correctly. This might sound like extra work for you, but it makes your code more readable.

Second thing, player.lua I found this:

Code: Select all

function playermove()
function love.keypressed(key)
  if key=='right' and collision[gridx+1][gridy] == 0 then
    gridx = gridx + 1
  elseif key=='up' and collision[gridx][gridy + 1] == 0 then
    gridy = gridy - 1
  elseif key=='down' and collision[gridx][gridy-1] == 0 then
    gridy = gridy + 1
  elseif key=='left' and collision[gridx-1][gridy] == 0 then
    gridx = gridx - 1
  end
end
playerxx = gridx * 50
playeryy = gridy * 50
end
Here you have a function declaration inside a function declaration. That means, every time playermove() is called, the function love.keypressed() is defined again. Even though this principally works, this is not what you want. Instead put this in the main file:

Code: Select all

function love.keypressed(key)
  if gamemode == "playing" then
    player.keypressed(key)
  end
end
And in player.lua you write (outside the playermove()!!!)

Code: Select all

function player.keypressed(key)
  if key=='right' and collision[gridx+1][gridy] == 0 then
    gridx = gridx + 1
  -- the other stuff here

  end
end
Once you have that, we go for the actual bug:
The player moving stuff should be like this:

Code: Select all

  if key=='right' and collision[gridx+1][gridy] == 0 then
    gridx = gridx + 1
  elseif key=='up' and collision[gridx][gridy - 1] == 0 then
    gridy = gridy - 1
  elseif key=='down' and collision[gridx][gridy+1] == 0 then
    gridy = gridy + 1
  elseif key=='left' and collision[gridx-1][gridy] == 0 then
    gridx = gridx - 1
  end
In your code you swapped a + with a -. Compare carefully!

Then in map.lua you have to do the initialization of the variable charToCollision OUTSIDE the loop:

Code: Select all

Quads = {}
CharToCollision = {}
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)
    CharToCollision[info[1]] = info[4]
end
Otherwise you delete whatever you have written inside before.

And one last thing. The Tilecoordinate system starts with (1,1) in the upper left corner. The player-coordinate-system starts at (0,0). To correct this you need:

Code: Select all

playerxx = (gridx-1) * 50
playeryy = (gridy-1) * 50
Then it should work.
florodude
Prole
Posts: 20
Joined: Mon Jul 30, 2012 10:16 pm

Re: Collision grid

Post by florodude »

First off, thanks a bunch for taking the time to figure this out. Ok when I do the player.keypressed function, it doesn't seem to work outside of the playermove(). I keep getting an error, and I think the reason is because I'm changing love.keypressed to player.keypressed. Other than that though, I think I fixed everything you told me to. And my player still is not moving.[
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision grid

Post by micha »

Sorry my mistake:
Naming the function

Code: Select all

 player.keypressed(key)
is the problem, because "player" is also the name of the variable for the image (by the way you should better call this playerImage or something).
You can solve this by simple renaming the player.keypressed to any other name, e.g. playerKeypressed(key).

However, just now I found the following is slightly better, because shorter:
You put back everything into the playermove, but this time without the function-within-function:

Code: Select all

function playermove(key)
  if key=='right' and collision[gridx+1][gridy] == 0 then
    gridx = gridx + 1
  elseif key=='up' and collision[gridx][gridy - 1] == 0 then
    gridy = gridy - 1
  elseif key=='down' and collision[gridx][gridy+1] == 0 then
    gridy = gridy + 1
  elseif key=='left' and collision[gridx-1][gridy] == 0 then
    gridx = gridx - 1
  end
	playerxx = (gridx-1) * 50
	playeryy = (gridy-1) * 50
end
In the main.lua you do two things:
First:

Code: Select all

function love.keypressed(key)
  if gamemode == 'playing' then
    playermove(key)
  end
end
Second: In the function love.update you remove the playermove.

I can upload a working .love, but I suggest you try it yourself first.
Post Reply

Who is online

Users browsing this forum: No registered users and 17 guests