This is my second published Pico-8 cartridge. It shows a near-perfect (in collision detection, not in the way it works) tiny collision detection function for a square. It can be expanded to any arbitrarily-sized rectangle. A square was chosen for simplicity.
There is no doubt in my mind that this can be improved upon. You know what, there's probably a way better, super obvious way that I glanced over.
I don't recommend using this for any of your games, as it has a blazingly obvious issue: You can't go into anything that isn't a black pixel. Also, due to the way it detects the pixels, it cannot detect sprites/map tiles that are smaller then a square.
The only reason I made this was to see if I could make a collision detection system that didn't use:
- Rocket science
- Quantum physics
- Carts that use coding like this video
- just kidding about most of those
I included the code so you can see how short it is (yes this is the entire cartridge's code)px=64 py=64 function collision() collr1=pget(px+8,py) collr2=pget(px+8,py+7) colll1=pget(px-1,py) colll2=pget(px-1,py+7) collu1=pget(px,py-1) collu2=pget(px+7,py-1) colld1=pget(px,py+8) colld2=pget(px+7,py+8) end function _update() cls() map(0,0,0,0,16,16) collision() spr(1,px,py) if btn(0) and colll1==0 and colll2==0 then px-=1 end if btn(1) and collr1==0 and collr2==0 then px+=1 end if btn(2) and collu1==0 and collu2==0 then py-=1 end if btn(3) and colld1==0 and colld2==0 then py+=1 end end
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/42638/JL Logo.png)
Well, here's a version that's a little more efficient (though it's a little longer than it could be because I drew the shapes with rectangles so I wouldn't have to upload a cart). It basically just streamlines the button controls and uses some loops instead of spelling out each individual case. Hope it's not too hard to read. As for getting tabs to show up, I think you have to use tab in Pico-8, then copy over to your post, at least, that works for me.
x,y,r=60,60,rectfill function _update60() cls() b=btn() dx=b%4\2-b%2 dy=b%16\8-b%8\4 r(8,8,56,56,5)r(16,16,48,48,0)r(40,8,56,24) for i=0,7,7 do if(pget(x+3.5+4.5*dx,y+i)>0) dx=0 if(pget(x+i,y+3.5+4.5*dy)>0) dy=0 end x+=dx y+=dy rect(x,y,x+7,y+7,7) end |
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/41031/avapourwok.png)
The cart embed already includes a button to show source code, showing tabs and syntax highlighting.
Since you asked for improvement suggestions: the big one would be to not use global variables but take function arguments for inputs (like collision(px,py)
) and return the result instead of setting global variables.
Typical collision functions return true/false (depending on the function name: can_move(px,py)
would return false if there is a collision, collides(px,py)
would return true), but I like that your function checks directions independently. A function can return more than one value so you could use that!
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/47512/screenshot1594325233.jpg)
@JadeLombax
Thanks! Yours improves it quite a lot. The only part I don't understand are the backslashes here.
dx=b%4\2-b%2 dy=b%16\8-b%8\4
What do they do? I took a quick look through the Lua manual and couldn't find anything being used like that.
@merwok 1) I forgot about that, thanks!
2) PX and PY were supposed to be PlayerX and PlayerY and so would be global variables any way. But that was assuming that this function would only be used for player collision, so in any normal case, yes, you are right.
3) Yes, it checks directions independently but it does so very inefficiently and requires a lot of code that is very inflexible (i.e. is a nightmare to edit). I had previously tried (and am still trying) to get a fget(mget(flr(playerx/8),flr(playery/8))) based function to work, but I couldn't wrap my head around it. Once I get it, it'll be easy to figure out the rest, though. You see, I have an excess of hubris and want to figure it all out by myself, without any tutorials, but so far it's not been working too well (obviously).
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/14590/2_2bitchuck.png)
@Einstein2 The \ is for integer division (so something like 9\2 will return 4 as opposed to 9/2 returning 4.5). Saves you a flr() call, basically.
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
![](/media/42638/JL Logo.png)
Yeah, the backslashes are the floor divide function. The smallest and lowest-token way to implement directional control that I've found is by using the raw numeric output from the button function, and separating out the power-of-2 values for each button. I've seen other people do this with bitwise operators, but just using regular math is actually more compact (though probably a tiny bit slower).
Oh, also, I improved my code by making a couple small tweaks. It now uses slightly fewer tokens and is capable of detecting collisions with a single pixel. If you hit a pixel at just the right diagonal angle, though, you can go through it, I'll have to think about how to fix that.
x,y=60,60 function _update60() cls() b=btn() dx=b%4\2-b%2 dy=b%16\8-b%8\4 srand() for i=1,60 do pset(rnd(128),rnd(128),rnd(15)) end for i=0,7 do if(pget(x+3.5+4.5*dx,y+i)>0) dx=0 if(pget(x+i,y+3.5+4.5*dy)>0) dy=0 end x+=dx y+=dy rect(x,y,x+7,y+7,7) end |
[Please log in to post a comment]