SNES programming tutorial. Example 8.
https://github.com/nesdoug/SNES_08
I made this with SPEZ version 2. Although SPEZ version 3 is out, it has different sprite code (see example in the SPEZ folder).
So, this isn’t so complicated. I’m using the Example 4 backgrounds, and scrolling them with the controllers. I’m not going to go over the process of making backgrounds again. We will just talk about the scrolling code.
If you press A, B, X, or Y, you will toggle which background is selected. Visible by the sprite in the corner (1,2,3). This is the map_selected variable, which has a value 0-2.
The up/down/left/right functions will do a case switch style check on the map_selected variable. Normally, you would do CMP #1, CMP #2, CMP #3, etc. But you don’t actually need to do a CMP #0. This is something I see new 6502/65816 programmers do. The previous line “lda map_selected” already sets the z flag if map_selected is zero. Lot’s of instructions set the z (zero) and n (negative) flags. LDA, LDX, LDY, TAX, TXA, TXY, PLA, PLX, PLY, etc. If a register is loaded with zero, the z flag is set and BEQ will work.
Right_Handler: .a16 .i16 php A8 lda map_selected bne @1or2 @0: ;BG1 dec bg1_x bra @end @1or2: cmp #1 bne @2 @1: ;BG2 dec bg2_x bra @end @2: ;BG3 dec bg3_x @end: plp rts
Let’s follow this for each value. If map_selected is zero, the BNE won’t branch, it goes to the @0, dec bg1_x and then exits. If map_selected is 1, the first BNE will branch to @1or2. A is still loaded with map_selected, we compare it to #1, the BNE won’t branch, so we do @1, dec bg2_x and exit. If map_selected is 2, the first BNE branches to @1or2, cmp #1 is false, so the bne @2 branches us to th @2 dec bg3_x line.
Notice, moving the map right means decreasing the horizontal scroll variable. Moving it left means increasing it. Likewise, moving a screen down is decreasing the vertical scroll, and moving it up is increasing it.
Scrolling registers are write twice (8 bit) each. Always write twice. You can actually write to these registers any time, but we want to do it during v-blank so we don’t get any shearing of the background in the middle for 1 frame. Near the top of the game loop, we have jsr set_scroll. Let’s look at set_scroll.
lda bg1_x sta BG1HOFS ;$210d stz BG1HOFS lda bg1_y sta BG1VOFS ;$210e stz BG1VOFS lda bg2_x sta BG2HOFS ;$210f stz BG2HOFS lda bg2_y sta BG2VOFS ;$2110 stz BG2VOFS lda bg3_x sta BG3HOFS ;$2111 stz BG3HOFS lda bg3_y sta BG3VOFS ;$2112 stz BG3VOFS
bg1_x is a 1 byte variable, because our maps are set to 1 screen only (32×32 map and 8×8 tiles). If you made the tilemap bigger (or made the tile size larger), you would need 2 bytes for each scroll variable. With 64×32 our x needs 9 bits. If you also increase tilesize to 16×16 then we need 10 bits.
You can move each layer independently. Usually, you would have BG1 be the foreground and BG2 be the background and BG3 be either the far background or the HUD (scoreboard) always fixed in one place in the front.