I’ve been planning to make a game that can freely scroll in all directions, like a modern game. The issue with the NES is that it only has enough VRAM for 2 nametables. So, the background is mirrored left to right (horizontal mirror) or top to bottom (vertical mirror). You could use 4 screen mirroring, but that required an extra RAM chip on the cartridge, which was an expense that almost no games used (and people seem to think this is a bit of a cheat, as it isn’t using the basic hardware).
And, when you only have 2 nametables to work with, moving in the perpendicular direction will always be visible. The oldest TVs tended to cut off as much as 8 pixels from the edges of the screen, so maybe you couldn’t see the changes. But, modern TVs and emulators can show 100% of the pixels (256 x 240). So, we want to minimize the visible changes. Including the attribute table, which only has 16×16 granularity.
A side scroller layout can easily hide the right and left scroll changes, just off screen. But you would see the changes at the top and bottom. Ideally you would have it only update when the Y scroll is aligned to the 8’s (08, 18, 28, 38, etc). So that 8 pixels at the top and 8 pixels at the bottom at most, which would be hidden by most old TVs. Like this.
Another option is to turn the screen off with carefully timed writes to the 2001 register. This would require a mapper with a scanline counter, like MMC3.
…here the bottom 16 pixels are hidden by turning the screen off at the bottom (with a write of zero to 2001). The bottom is the safest / easiest way to hide the visual glitches.
Or, a little more excessive, this game turns both the top 16 pixels off and the bottom 16 pixels off…
I guess for a more balanced visual. But, not really necessary. The screen is turned off at the top of the screen, then back on at line 16 and then back off again at line 224.
UPDATE – upon further investigation, this is done NOT by writing zero to $2001, but instead by having part of the CHR-ROM have all zeros. Many mappers allow swapping graphics banks any time you like, and where there is all black, they swapped the all blank CHR bank in. Where the screen is normal, they swap the normal CHR bank in place. This is the easiest way to handle this, and I recommend that you do that if your mapper has that ability. So, the graphics banks are changed multiple times per frame, usually handled with an IRQ timer. Ideally, you would use a scanline counter, like MMC3 has.
With horizontal mirroring, you can easily hide changes in the top and bottom just off screen, but the right and left side changes would be visible.
I’m sure you’ve played Super Mario Bros 3, and noticed the tiles change on the right side of the screen, and be the wrong color. So why would you intentionally put the changing tiles at exactly where the user is looking? Oh, well. Let’s see what other games did.
The NES does have a way of hiding the left 8 pixels of the screen in the 2001 register.
By resetting these bits to zero xxxx x00x the left 8 pixels will use the universal BG color (3f00) for the entire strip. Thus, you would only (ideally) 8 pixels worth of changes visible, which might be hidden on the overscan of the old TV. Here on the right…
To be the least visible, you would change tiles every 8 X scroll movements (hidden on the left) and change attribute tables on the 8’s (08, 18, 28, 38, etc) to best hide that on the far right.
And, another interesting choice, Kirby changes tiles and attributes on the left 16 pixels, which would be the simplest for programming. And, change attribute tables on the 0’s.
But we could go 1 step further and draw a column of black sprites along the right edge. Combined with the left 8 turned off, this is the maximum level of hiding scrolling glitches with standard hardware. If programmed right, you shouldn’t see any tiles changing nor attribute table glitches.
…but this requires sprites to be in 8×16 mode, and steals 15 sprites from you. And, worst of all, reduces the number of usable sprites per horizontal line from 8 to 7.
I bet you thought that was enough, right, but look at this game (vertical mirroring)…
…that cuts 16 pixels off the top and more than 16 pixels off the bottom, and has the left 8 pixels turned off. Hmm. That might be a bit excessive.
Single Screen Mirroring
A few games (AxROM) use this and attempt to do all direction scrolling. Cobra Triangle minimizes the attribute table glitches by just having only 1 BG palette used for the entire play area, and then switches to another screen for the bottom area (which uses a different BG palette). The left 8 pixels are turned off to hide left to right scrolling changes, and the swapped screen at the bottom hides the top to bottom changes.
After further consideration.. Cobra Triangle might just be a lousy example. Some games use single screen mirroring and do a great job. They use all 4 palettes, and they use the HUD to hide the screen errors. Some good examples are Battletoads, Solar Jetman, and Wizard & Warriors 2 and 3. They all look great, so maybe this is a good idea.
They both turn the left 8 pixels off, and use a sprite zero hit to switch the nametables and scrolling. Solar Jetman even draws a tiny dot on the bottom left on the background so the sprite zero hit will work correctly. That must take some fancy programming, since the dot needs to move slightly each frame.
Some mappers (like MMC1 and MMC3) can change between Horizontal and Vertical mirroring. Usually having sections of the game that are strictly side scrolling…
and some sections that are strictly vertical scrolling…
But, I don’t consider these all-direction scrolling. And it requires a special mapper.
I haven’t written the code to make my own all-direction scroller, yet. I did some test code for 4 screen mirroring and scrolling any direction, but I would prefer to rewrite it with standard 2 screen mirroring.
And I think the easiest would be to do what Kirby did, with the left 8 pixels turned off and attribute tables updated on the left on the 0’s (10, 20, 30, 40) of X scroll change. So I might attempt that first.