My goal is to see this collision detection work well.
I don't quite see the relation to collision detection.
But sure, I can sure talk about it. It's actually really easy and fast as long as you don't handle slopes, and don't have things like tiles you can jump up through or tiles you can drop down through.
You only really need to check 6 points to be TOTALLY safe, or 4 if the shape of your character never changes and he is smaller than the size of the collision tile for both X and Y. If he's say... 24 pixels tall with 16x16 collision tiles you have to check one more point. You also need to check more if your character moves more pixels in a frame than the size of your tile. For instance, he's capable of moving 9 pixels in a frame, but your collision tiles are only 8 wide.
Obviously, you first gotta find out whether or not the tile you're working with is collision enabled. I can't especially help with that unless you make a post about your current tile format. Post about that, and I can write a book for you about that.
I personally keep 4 screens of 32x32 metatiles in a page of RAM, which are updated when the game scrolls to a new screen. This means all my screen decompression happens once and only on a frame when the character passes a screen boundary.
The collision detection and parts of my code that tell the PPU what to draw always pull from this RAM, where it is much easier to figure out the math for me than pulling directly from the data in ROM.
I load the 32x32 tile from RAM, I find out the 16x16 tile I want in it. Then I know if I should eject or not.
It works exactly like this:
Code: Select all
;Ignore the <'s, it's a nesasm thing.
lda <xhigh;Zero Page RAM I put any high X position into
ror a;puts the lowest bit of the high x pos into the carry
lda <yhigh;Zero Page RAM I put any high y position into
ror a;puts the lowest bit of the high y pos into the carry
;and puts the x bit into the high bit of the accumulator
ror a;Now the low x and y bits are in the high bits accumulator
and #%11000000;Removes the other junk in the accumulator
sta <reservedE;Temp RAM. The highest bits of it now contain
;which screen I'll read from RAM. Each screen is 64 bytes long, because it contains 8x8 32x32 metatiles.
lsr a;divide by 32, since I'm trying to get a 32x32 metatile.
;The other bits of precision don't matter.
ora <reservedE;This combines my "which screen" bits with the X offset in RAM.
and #%00111000;This takes away all unnecessary bits from
;my y position
ora <reservedE;I know have the offset in RAM that I need to load my 32x32 tile from.
tay;Y contains the address of the 32 x 32 metatile to look up
lda $0500,y;loads 32 x 32
tay;Y contains the 32 x 32 tile number
The tricky part is actually getting the 32x32 tiles into RAM in the first place, but you may not even need to do that depending on how your data is stored.
I then use a series small series of branches to determine which part of the 32x32 tile I'm in. Topleft, Topright, bottomleft, or bottomright. Once I know that, I load the tile and use its format to determine whether it's a collision or not.
Here's how I eject when I know the current tile is collision enabled
Code: Select all
You want to eject left while traveling right. So imagine the right point of your character has just entered the first pixel of a tile. It's anded position would be 0. In this case, you obviously want to eject one. If you're going super fast, you'll end up further in the tile, so the and will be higher and you'll always eject one more than that. Easy. jsr to the routine, subtract offset from your character's position. (It should be set to 0 if the collision routine detects the current tile is not a collision tile.) You can even use the offset variable the routine returns to find out whether or not there WAS a collision if you want to do that to stop a walking animation or something.
Code: Select all
This one is mostly the same, except it has an eor. Say you're traveling left and hit the first pixel of a tile. That's actually pixel $0F, but you only want to eject one! The eor makes $0F equal to one, then it works the same as before! As before, just write a 0 to offset if you've discovered the current tile is not solid. Jsr to routine, then add offset to player's position.
This works for any size tile that's a power of two. Just change the ands and eor to the number of bits your tile takes up.
If you're traveling left, move the player using the current speed value. You may be in a wall. You check the top and bottom left points of your character, and eject right. (add offset) If you're traveling right, check the top and bottom right points of your character and eject left. (subtract offset) you'll never be in the wall for a frame like Mario, and this will certainly be fast enough for how few tiles you'll need to check.
For ejecting up while falling you check the bottom left and right points and subtract offset from the player's position.