SNES programming tutorial. Example 9.
https://github.com/nesdoug/SNES_09
I made this with SPEZ version 2. Although SPEZ version 3 is out, it has different sprite code (see example in the SPEZ folder).
This time we are going to make a collision map, and make a sprite collide with the background. The actual graphics are not that important.
I took some pictures of some blocks (and a sketch of a cube with eyes) and resized them in GIMP to 16×16 sized blocks. Then I imported everything into my M1TE tool. From there I made a 3 metatiles, green, red, and yellow. Red will be the collision blocks (1 = wall). This is what it looks like in M1TE.
You can save the map screen as a image (File/Export Image). That was then loaded into Tiled Map Editor as the tileset.
Tiled Map Editor is a free game design tool. The entire purpose of this is to export a .csv file of our collision map… which is that collision array I was talking about.
The CSV file exported from Tiled.
I added some .byte directives so it can be loaded as a byte array into the asm code. 0 is blank, 1 is red wall, 2 is the yellow square. Now we can .include it into our ASM file.
But how did I draw the map? Back when I was programming NES games, I had a whole metatile system worked out. I am doing a similar thing here, but I manually typed out each tile needed to construct a block. In metatiles.asm.
Metatiles:
;tile 0
.byte $02, TILE_PAL_0
.byte $03, TILE_PAL_0
.byte $12, TILE_PAL_0
.byte $13, TILE_PAL_0
;tile 1
.byte $04, TILE_PAL_1
.byte $05, TILE_PAL_1
.byte $14, TILE_PAL_1
.byte $15, TILE_PAL_1
;tile 2
.byte $02, TILE_PAL_5
.byte $03, TILE_PAL_5
.byte $12, TILE_PAL_5
.byte $13, TILE_PAL_5
And in main, it does a loop, converting each byte of the collision map (HIT_MAP) into 4 screen tiles. And copying them one by one to the VRAM on the map. The key thing is that we again use the HIT_MAP to stop movements of the sprite.
Our code calculates where our guy is on the map, and if we are over a 1, cancel the movement. That makes him collide with the red walls.
How does it do that? Let’s go over the code. So our byte array has each block 16×16. We need to divide x and y pixel coordinates by 16 (the same as shift right 4x). But we also need to multiply the y by 16 to get to the correct row in our array, which cancels out the divide 16. So the algorithm is (Y & 0xf0) + (X >> 4). If we look at that index in the byte array, it will tell us if a point is in a wall or not. This is the code, with X and Y registers holding the X and Y coordinates…
tya and #$f0 sta temp1 txa lsr a lsr a lsr a lsr a ora temp1 tax lda HIT_MAP, x rts
I handled each direction separately. First do the X move, then see if any of the corners of our sprite are inside a wall. If yes, revert to previous X position. Then do the Y move, see if any of the corners of our sprite are inside a wall. If yes, revert to previous Y position.
This code would need to be a little more complex if we move more than 1 pixel per frame. If we are moving 2-3 pixels per frame, and the distance to the wall is 1 pixel, we should allow 1 pixel movement toward the wall… and not be stuck 1 pixel away from the wall. So, this code will need to be improved.
.
Touching the yellow square will darken the screen. We are just looking if 1 point (the middle of our guy) is over a 2 in the collision map, and changing the screen brightness variable. Remember that the $2100 register is the screen brightness. I am writing to it every frame, during v-blank. Full brightness is $0f. Half brightness is $07.
If we were scrolling in a larger world, the collision map would have to be the size of the world. You could have it compressed, and decompress it to the WRAM. You would have to keep track of X and Y movements with 2 byte variables. One thing I would not recommend is trying to read from the VRAM to see what kind of tile you are standing over. The visuals of the level should probably be separate from the collision map.
One more thing. It wouldn’t be too much trouble to turn this simple example into a platformer. You would just need to add gravity, which is adding a little bit to the Y speed every frame, and then cancelling that if your feet touch the floor. Jumping would be a sudden negative Y speed.
This is a really cool page that explains collision maps in more detail.
http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/
.
TODO – I need to write some code to automate generating metatile tables, or come up with some other kind of BG object system. Especially for a larger world… hand editing data tables will get very tedious.
.