So I'm working on a tile-based movement engine, and I was having some trouble figuring out how to handle collisions with objects that are "solid." Here is what I have so far for the collision detection:
function getPreviousPos() --This is ran before moving positions, at keypress player.xprevious = player.x player.yprevious = player.y end function isCollide() if (player.x == solid.x and player.y == solid.y) then player.x = player.xprevious player.y = player.yprevious end end |
This is just a rough markup since I'm away from my computer. But I'm basically trying to find out how I can replaced solid.x and solid.y with a reference for a specific sprite. (So that this check is not just for a single, individual sprite, but that sprite as a whole.)
I hope I'm being clear enough, thanks!



Have a good look at the collide demo (shipped with pico-8).
(it should be somewhere in the pico banner :)
install_demos |
Unless your player can only move by whole increment, your code won't work.
You need to separate axis and accomodate for player width.



So you're currently checking if the player is EXACTLY at the same position as the solid. But what you want to check for is if the solid and player overlap. So you need to take the with and height into consideration.
I made a video that walks you through what you need to do here:



@freds72 Yeah the movement is grid-based, so the player moves 8 pixels per keypress, using btnp(). I'll check that out once I get home
@Krystman Yeah it was a quick and easy way to check collision, so if the player is on the same exact spot as the solid, it just moves the player back. It actually looks quite good in practice, you don't even see the player move. But I'll check out your video for sure!



But more to what I'm looking for is how I can check if the player is on top of a particular sprite (i.e 002). I read about using flags possibly, but I'm stumped on how to implement that.



@HoofedEar Well then it sounds like it really depends on the rest of your code. It's unclear if x and y are pixel coordinates or map coordinates.
If you're working with a map, here is a small sample code showing off a basic way of how to do it:
https://www.lexaloffle.com/bbs/?tid=28277



@Krystman yeah I apologize about that, I'll post the source as soon as I get home (about 6 more hours.) So far all I have done to get the sprite on the screen is use SPR() and set the solid.x and solid.y which is used by SPR(). I haven't got much farther than that. But thank you for the example! I'll check that out as well.



Okay so here is the code for my engine:
function _init() player = {} player.x = 32 player.y = 32 player.xprevious = 1 player.yprevious = 1 solid = {} solid.x = 16 solid.y = 16 end function _update() function isCollide() --Check if the player is on top of something. if (player.x == solid.x and player.y == solid.y) then player.x = player.xprevious player.y = player.yprevious end end function getPrevPos() --Get the previous coordinates before moving player.xprevious = player.x player.yprevious = player.y end if (btnp(0) and player.x > 0) getPrevPos(); player.x -= 8 --getPrevPos() is ran before movement. if (btnp(1) and player.x < 120) getPrevPos(); player.x += 8 if (btnp(2) and player.y > 0) getPrevPos(); player.y -= 8 if (btnp(3) and player.y < 120) getPrevPos(); player.y += 8 isCollide() --At the end of the step, check if the player is on top of the object. end function _draw() cls() spr(1,player.x,player.y) spr(2,solid.x,solid.y) spr(2,solid.x+64,solid.y+64) print(player.xprevious) end |
I'd like to figure out how I can check if the player is on top of a kind of sprite, rather than just checking an arbitrary variable I created for just one sprite on the screen.



@Krystman it looks like your maze collision example is probably the best place for me to start, by using flags and such. Thank you for that!



Yeah, since your game is tile-based, it's pretty easy. Either check the sprite number with mget(player.x/8, player.y/8) or the flags with fget(mget(player.x/8, player.y/8)



@tobiasvl Exactly what I was looking for, thank you! That's neat that I can check for either flags or sprite numbers. I think I'll use flags, more flexibility.



From what I've read, it looks like you're trying to make a rogue-like engine. I've made a few in the past, this is pretty much the basis of what I've done:
function _init() player = {} player.x = 3 player.y = 3 player.s = 1 player.hp = 100 m = {} for i = 0, 15 do m[i] = {} for j = 0, 15 do m[i][j] = {} m[i][j].id = 0 end end m[3][4].id = 1 m[3][4].s = 2 m[4][4].id = 1 m[4][4].s = 2 m[5][4].id = 1 m[5][4].s = 2 m[6][6].id = 2 m[6][6].s = 3 end function _update() local dx = player.x local dy = player.y local press_left = btnp(0) local press_right = btnp(1) local press_up = btnp(2) local press_up = btnp(3) if press_left then dx = dx - 1 elseif press_right then dx = dx + 1 elseif press_up then dy = dy - 1 elseif press_down then dy = dy + 1 end o = m[dx][dy] if o.id == 0 then player.x = dx player.y = dy elseif o.id == 0 then player.x = dx player.y = dy player.hp = player.hp + 10 end end function _draw() cls() for i = 0, 15 do for j = 0, 15 do if m[i][j].id > 0 then spr(m[i][j].s, i * 8, j * 8) end end end spr(player.s, player.x * 8, player.y * 8) end |
To put it in a nutshell, there's 2 main objects: player and m (the map). The player object stores all the information for the player including stuff like its x and y position, sprite information and hp. In the update, it checks if a move button has been pressed. If it has, it then sets "destination x" and "destination y" positions. It then checks the map to see if there's something in the position the player wants to move to. If there is nothing (id 0) then it simply moves there, if there's a potion (id 2) then it'll move there and increase the hp of the player. But, if there's a wall (id 1) it won't move.
I know that this little engine is inefficient, if I was making an actual game there would be more that I would do but I think this is a fairly easy to read example that's scalable for whatever project you need.
And yes, there is a reason why I didn't use the in-built map. It's because my map object can contain a lot more information than just x, y and a flag. Also in roguelikes, it's pretty easy to make your own camera. You can simple set an offset and only draw from the offset to offset + 15 tiles. If you don't know what I mean, I'm happy to provide an example of how I've handled it in the past.
[Please log in to post a comment]