28

Cart #19162 | 2016-03-10 | Code ▽ | License: CC4-BY-NC-SA
28

I've seen some questions about how to do collision detection in Pico-8, so figured I'd make another bare-bones demo, this one demonstrating collision detection with map tiles and/or world bounds. The function itself is 24 lines and 125 tokens, and includes flags for turning collisions on or off on an object (such as the player). Here's the full function:

 ```function cmap(o) local ct=false local cb=false -- if colliding with map tiles if(o.cm) then local x1=o.x/8 local y1=o.y/8 local x2=(o.x+7)/8 local y2=(o.y+7)/8 local a=fget(mget(x1,y1),0) local b=fget(mget(x1,y2),0) local c=fget(mget(x2,y2),0) local d=fget(mget(x2,y1),0) ct=a or b or c or d end -- if colliding world bounds if(o.cw) then cb=(o.x<0 or o.x+8>w or o.y<0 or o.y+8>h) end return ct or cb end ```

It will return true if a collision is detected, and the object has the flag(s) set for collisions. To set up the function for use, you need the following global variables/properties set:

 ```w -- the width of your map h -- the height of your map [object].cm -- whether the object should collide with map tiles [object].cw -- whether the object should collide with the world bounds (as defined above in w and h) ```

To call the function, simply use: cmap([object]).

P#19163 2016-03-10 12:17 ( Edited 2018-02-04 15:08)

Hey Scathe. Thanks for posting this up, collision is something I've been trying to get my head round for a while. Having worked through the above I think I'm understanding correctly how it is all working.

I wanted to go a bit further with adding collision for things that aren't map tiles or the world bounds though. If for instance there is a sprite generated to the screen either at random or by a monster or similar; how do you set up collision on any sprite with a certain flag, rather than those that exist in the map?

Any guidance would be greatly appreciated.

P#20538 2016-05-13 11:46 ( Edited 2016-05-13 15:46)
1

In the Pico Fanzine #3 there is an article called DOM8VERSE that talks about collision between objects. You basically assign hit box coordinates to the object and then compare. This means you can have an object with a big sprite but a smaller hit zone...or you can make the whole thing a hit zone.

It made a lot of sense to me and was easy to implement and put into a method. I'm using it on my shooter game right now, which doesn't have a map or any tiles.

Here's the method I use and so far it's working great. You give it two objects and it returns TRUE if there is a collision. Just put it the _update() loop for one of the objects.

 ```function collide(obj, other) if other.pos.x+other.hitbox.x+other.hitbox.w > obj.pos.x+obj.hitbox.x and other.pos.y+other.hitbox.y+other.hitbox.h > obj.pos.y+obj.hitbox.y and other.pos.x+other.hitbox.x < obj.pos.x+obj.hitbox.x+obj.hitbox.w and other.pos.y+other.hitbox.y < obj.pos.y+obj.hitbox.y+obj.hitbox.h then return true end end bullet.pos={x=10,y=10} bullet.hitbox={x=0,y=0,w=3,h=3} spaceship.pos={x=15,y=15} spaceship.hitbox={x=0,y=0,w=10,h=5} if collide(spaceship,bullet) then ... end ```
P#20541 2016-05-13 12:54 ( Edited 2016-05-13 16:54)

Thanks for the suggestions.

I have a player that is moving through space and creating a trail behind. Currently I'm achieving this with a draw function.

 ``` if(btnp(0)) then o.x=o.x-8 add(trail,{o.x+8,o.y}) end if(btnp(1)) then o.x+=8 add(trail,{o.x-8,o.y}) end if(btnp(2)) then o.y-=8 add(trail,{o.x,o.y+8}) end if(btnp(3)) then o.y+=8 add(trail,{o.x,o.y-8}) end ```
 ```function _draw() foreach(trail,drawnew) end function drawnew(v) dx=v[1] dy=v[2] map(1,9,dx,dy,1,1) end ```

So rather than a set of projectiles the map gets fuller and fuller with tiles and I'm not sure that hitboxes are going to work for that.

The player shouldn't be able to recross their path and I thought this could be achieved through something similar to the map collision code in Scathe's example. but I can't quite piece together how to specify sprites that are created for Trail rather than appear on the map.

My Trail sprite has the sprite flag set to 0 and the player doesn't have a sprite flag so I thought I could do it that way but struggling to get the correct bits of code together.

P#20545 2016-05-13 13:40 ( Edited 2016-05-13 17:41)

Okay, gotcha...I guess since you asked about collisions for things that aren't tiles or walls, that leaves just normal sprite objects.

I see what you're doing now though...so every move you're just flagging a tile where it previously was. I'm still new-ish to most of this so I'm still thinking in terms of sprite objects and not tiles.

But I think the mget() combined fget() like Scathe has in that first snippet is what you're looking for.

P#20546 2016-05-13 14:12 ( Edited 2016-05-13 18:12)

Thanks, I'll keep plugging away at it but I'm thinking maybe it doesn't work in the way I first thought because I do what I think should be correct using that arrangement and yet i don't get the desired result.

P#20547 2016-05-13 14:52 ( Edited 2016-05-13 18:52)

I guess, looking and assuming what you're trying to do, I would just create a new object+sprite at that point. I would just sit there and update as it needed, waiting for collision or whatever...rather than use a map and tiles. Might be worth a shot to try and see if it gets you closer. Then at least you can refactor from there to make it more efficient. Better to get things working as a hack and then go back than try to optimize up front.

P#20552 2016-05-13 15:50 ( Edited 2016-05-13 19:50)

Your "sprites" are all in a table. Each one is just an ordered table containing two numbers. That, and what you draw on the screen, are the only information you have about said sprites. So you either have to crawl through your sprite table, and double check the X and Y of each one when you're looking for a collision, or take a peek at the screen pixels where the player is trying to go to check for collision.

If your left-behind sprites are doing nothing else, you might consider replacing your table with an ordered two-dimension table that can be directly checked like

 ```if trail[px][py] then collide() ```

edit - though that means nested for loops to draw them all, so there's that.

P#20556 2016-05-13 18:31 ( Edited 2016-05-13 22:35)

i have an error it says:
runtime error
local x1=o.x/8
line 25:attempt toperform arithmetic on field 'x' (a nil value)
in cmap line 25
in move line 50
in _update line 16

P#43341 2017-08-17 14:35 ( Edited 2017-08-17 18:35)

Hi I'm having a problem collisions are detected only in x coordinates if I move my character left into a wall it stops the character like normal but if I move him up into a wall he keeps going

P#48960 2018-02-04 10:08 ( Edited 2018-02-04 15:08)