Scrolling means moving the background around. It does not affect sprites.
The NES PPU has 1 scroll register, 2005. You write to it twice, first the X scroll, and then the Y scroll. This is another thing that needs to happen during v-blank, and is handled automatically by neslib. neslib has this function scroll(x,y), you pass it the shift amounts. Adding to X scroll, shifts the screen left. Adding to the Y scroll shifts the screen up.
But, I decided that I didn’t like the way it handled Y scrolling. Y scrolling is a bit odd anyway, since values 0-$ef are real positions, and $f0 – ff are treated as negative values, and not what you want. neslib subtracts $f0 if the Y value is > $ef, and assumes that you are going to manage the maximum at $1df.
So, long story short, I do things differently than everyone else using C. I made 2 functions called set_scroll_x(x) and set_scroll_y(y). You can pass the set_scroll_y any int value, and the high byte will tell you which nametable you are in. Even means top, odd means bottom. If you have 2 collision maps, you know even = use the first one, odd = use the second one. Simple. Well, not perfect.
Our code still has to adjust each change in Y to skip over the $f0-ff region of the byte, because our screen is only 240 pixels high. Luckily, I wrote some functions to do this for us.
add_scroll_y(add,old y) to add to the y scroll.
sub_scroll_y(add, old y) to subtract from the y scroll.
Each returns a value, which will have to be passed to set_scroll_y(), to change the screen scroll. But before we show that, lets talk about mirroring. Examples…
Old scroll_y = 0xef, add 5. Returns 0x104, new scroll_y
scroll_y = add_scroll_y(5, scroll_y);
Old scroll_y = 0xef, add 0x15. Returns 0x114, new scroll_y.
scroll_y = add_scroll_y(0x15, scroll_y);
— or subtract
Old scroll_y = 0x104, subtract 5. Returns 0xef, new scroll_y
scroll_y = sub_scroll_y(5, scroll_y);
Again, skipping over the 0xf0 – 0xff invalid Y scroll values.
Horizontal scrolling (Vertical mirroring)
Remember from the intro page, I said that the NES only has enough VRAM for 2 nametables. If you set it to Vertical mirroring — the mirroring is set in the ines header in crt0.s, which is actually a linker symbol “NES_MIRRORING” found in the .cfg file. On a real cartridge they would have soldered one of the connections to permanently set it to H or V mirroring.
So with vertical mirroring the nametables are arranged like this.
With nametables 2 and 3 being copies of 0 and 1.
This is good for sideways scrolling. If you never change the Y scroll, you can scroll to the right, and have plenty of blank space just off screen to make changes to the nametable that the user can’t see. Here’s some example code of Vertical mirroring. You can freely scroll around, and see that the lower 2 nametables are just a copy of the top 2.
The numbers on the screen are sprites.
Vertical scrolling (Horizontal mirroring)
is basically the same, except the right 2 nametables are copies of the left 2
This is good for vertical scrolling. You can keep the X scroll static, and scroll up or down, and you have plenty of room to make changes just off screen, above or below where the user can see.
There is also 4 screen mode, which almost zero games used. It required a special mapper with an extra RAM chip in the cartridge. Gauntlet for example, and Rad Racer II.
This would be good for all direction scrolling. Most games just used 2 screen, and had glitchy tiles at the edges. Old TVs tended to cut off the edges, so it usually wasn’t too bad. A modern TV / monitor, might show all pixels… PAL TVs do also. Let’s not worry about that now.