I've only ever done really minimal/logical collision stuff in games, so more general collision strategies are still sort of mystery meat to me. I'm working on a little test idea with a ship flying near uneven terrain that the player will need to avoid colliding with, and I'm trying to work out a good approach to doing that per-update collision test between the ship and nearby terrain.
If I've got a ship sprite, and a given nearby sprite of map where only a portion of the sprite is solid ground (say, a diagonal chunk of hill), how might I approach writing a collision detection routine for the two? Something using pget for the ship and terrain sprites and appropriate x/y offsets to check for any case where both pixels are non-transparent?
you might want to do a first pass just with the bounding boxes of the actors before you do a pixel collision test. That way when you are nowhere near the hill you aren't burning cycles checking pixels. Then I would maintain a bitmap of the terrain sprites and the ship sprites, so that you don't have to do pget every time. That said, I run out of memory, so maybe pget is quick enough?
Yes, you can use pget on the sprite you got from the map where collision happend and you can check any number of pixels you want.
When your ship moves, it does not move in 8x units I guess. Instead it moves depending on the speed.
Normally you calculate the map coordinates with:
mx = flr(ship.x/8) |
The difference between the map cell corner position and the ship position is what you need to get the pixel position inside the sprite:
px = ship.x - mx*8 |
same for y.
With px (and py) you can then use pget to see if the pixel is black (transparent) or not.
I hacked together a fairly simple one based purely on what's been drawn on-screen already. It uses a buffer of the ship's shape. A neat side effect is if I don't want the ship to collide with a graphic I can draw it after I do the check, so I could add particles and stuff. I think I need to make a game with this, guys. :L
Note to self: If I change it to make an array of x,y values which are the solid pixels of the sprite, I can do EVEN FEWER PGETS.
I ended up getting something together last night; I've created a new Collab post with a demo cart that shows off box and pixel collision in a little interactive setup, which is totally open for anyone inclined to iterate on if they like.
So of course I made one too. I think it can handle large sprites.
It calculates the intersection rectangle then iterates over that, mapping coordinates back into the sprite sheet for both sprites to see if they both have non-zero values set. Kinda the same thing really. I used the weird little MID() function to make finding the bounding rectangle not a mess of IFs and less thans and greater thans.
I think it's better if the collision check be done at _update() time, not at _draw() time.
edit: the checkered background is just to show it's not doing PGETs.
@cheepicus: in your demo the guy turns red one pixel higher than he should, in the blue house area. Is that a bug?
also, the orange collision works but the x and y are handled together, so if you're on ground (pressing down) and press left/right or on a wall and press up/down, you get stuck to it. Personally, those are things that I would change.
Thanks! That is a bug. I just cut out the part where it's finding the bounding rect of a sprite; that part doesn't add much and just confuses the issue I think.
Non getting stuck on walls is more about movement than collision.. Also it should probably be checking the map sprites too; this is not a complete system.
@cheepicus: I did the check in _draw because I was checking everything that had been drawn up to that point rather than using the map/sprites. Basically it's very rudimentary, but it works.
@erryone: Thanks for all the examples! I'll take a look at them and maybe work on my own project with pixel collisions.
[Please log in to post a comment]