Advice for artifact free 4-way scrolling

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
bleubleu
Posts: 108
Joined: Wed Apr 04, 2018 7:29 pm
Location: Montreal, Canada

Advice for artifact free 4-way scrolling

Post by bleubleu »

Hi.

I'm trying to implement clean 4-way scrolling. Jurassic Park is a good example of this working really well. Im planning to also hide the top/bottom 8 pixels, but that's note done yet.

I'm getting really close to a bug-free version of it working, but now my code has become kind of a mess.

When I started I was hoping for something clean and symmetric, but since then many things crept in:
  • Because of mirroring, vertical and horizontal scrolling have to be treated quite differently, so that almost double the code right off the bat.
  • Crossing the nametable boundary (or wraping) adds some complexity.
  • Having 16x16 metatiles, but scrolling by adding 8x8 tiles at a time requires the code to properly handle coming from the right/left, top/bottom and adding the individual tiles. Also dealing with the possibility of single tiles on the corners.
  • Using the upper left corner as a reference point makes going right/left, up/down ever so slightly different adding more tests/branches.
  • Attributes are also super annoying to manage.
Anyone here managed to implement this while keeping the code relatively compact and clean? If so, do you have any advice on what you did you keep this as painless as possible.

-Mat
User avatar
Dwedit
Posts: 4922
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Advice for artifact free 4-way scrolling

Post by Dwedit »

You will need separate counters for Camera Y position and Nametable Y position to keep things simple.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Advice for artifact free 4-way scrolling

Post by tokumaru »

bleubleu wrote:I'm trying to implement clean 4-way scrolling. Jurassic Park is a good example of this working really well. Im planning to also hide the top/bottom 8 pixels, but that's note done yet.
Do note that Jurassic Park blanks scanlines by using blank tiles, rather than forced blanking, so it can still use the MMC3's scanline counter normally. If you have mapper IRQs at your disposal, this is indeed a pretty good solution, but if you don't, timing the blank scanlines right may be harder than it sounds, specially at the bottom of the screen.
Because of mirroring, vertical and horizontal scrolling have to be treated quite differently, so that almost double the code right off the bat.
This gets better if you use 4-screen instead.
Crossing the nametable boundary (or wraping) adds some complexity.
Having your row/column updates always be composed of 2 parts (even if the length of one of those parts is 0) will make this the norm, instead of an exception.
Having 16x16 metatiles, but scrolling by adding 8x8 tiles at a time requires the code to properly handle coming from the right/left, top/bottom and adding the individual tiles. Also dealing with the possibility of single tiles on the corners.
I update whole metatiles at once, so I don't really have a problem with this. If you're updating only half metatiles because of VRAM bandwidth concerns, I suggest you still do things like if you were updating entire metatiles (i.e. decode entire metatiles from the level map and buffer the tiles in RAM), but upload them to VRAM one half at a time on consecutive vblanks. You may need to pick which half goes first depending on the direction the camera is moving, but that should be easy. I don't really get what the problem with the corners is.
Using the upper left corner as a reference point makes going right/left, up/down ever so slightly different adding more tests/branches.
You just need to add the camera's dimensions to the respective axes and handle wrapping, no big deal. Or keep a separate set of coordinates for the bottom right corner that you update in sync with the top left, so you can just mix and match coordinates as needed depending on where the new tiles are supposed to go.
Attributes are also super annoying to manage.
Yup. I usually keep a mirror of the attribute tables in RAM, which I modify in place when necessary, so that later I can just copy entire rows/columns of bytes to VRAM.
Anyone here managed to implement this while keeping the code relatively compact and clean?
I've done it a couple of times for unfinished projects, and the things you mentioned do indeed have to be actively taken care of. The NES wasn't really designed for free scrolling like this, so things like the attribute tables and mirroring will definitely get in the way if you don't design everything around them from the start.
If so, do you have any advice on what you did you keep this as painless as possible.
If you can, ditch the mirroring and go with 4-screen, that'll definitely make things easier. I made the switch to 4-screen in my most recent scrolling engine and I don't regret it. It may seem like the cheap way out, but if you're using CHR-RAM in a discrete logic mapper, 4-screen is basically free since you can't even buy 8KB RAM chips anymore, so you can easily wire the cartridge to use the excess CHR-RAM as NT RAM.

Dwedit's advice is good too. Keeping different sets of Y coordinates (one relative to the level and another relative to the name tables) and updating them in sync will save you from having to convert back and forth between them, which is a pain.

Another thing worth mentioning is that there's another technique that can be used to achieve glitch-free 8-way scrolling on the NES, particularly useful if you don't have mapper IRQs at your disposal: use horizontal mirroring and have the PPU hide the leftmost 8 pixels of the screen, while sprites are used to hide the rightmost 8 pixels. Alfred Chicken and Felix the Cat do this. The main drawbacks are the amount of sprites used and the fact that you only get to place 7 more sprites worth of actual game objects per scanline before flickering begins. These 2 games are pretty cool though... Felix the Cat even manages to display pretty large sprites, like vehicles Felix can get in, despite having lost 1 sprite per scanline.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Advice for artifact free 4-way scrolling

Post by thefox »

It does get pretty messy no matter what you do.

Here's my Lua prototype implementation of what I was planning to put in my engine: https://github.com/fo-fo/ngin/blob/mast ... roller.lua. It might give you some ideas.

It's completely generic, supporting any mirroring mode. It can scroll 8 pixels at a time, but multiple calls to the function can be made to scroll more pixels per frame. The API basically consists of scrollHorizontal() and scrollVertical(). Those then call scroll() which is sort of a generic routine that can scroll in any direction. Then scroll() calls update() and updateAttributes() to fill the PPU update buffer. There are some simplifications for purposes of prototyping, though. For example, map data is read by "random access" (MapData.readTile( mapX, mapY )). In an optimized implementation you would want to avoid recalculating the map data address all the time (but this, too, can get tricky if you implement stuff like metatiles in metatiles...)

If you can, I'd suggest using macros to write the code for just a single scroll direction (e.g., to the right), and then expand that macro for all 4 scroll directions. It might turn into a bit of an if/else mess, but it's still better than duplicating a ton of code. (Just a fair warning: it's very easy to make oversimplifications in the code when considering only one scroll direction...)
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Advice for artifact free 4-way scrolling

Post by FrankenGraphics »

It has sort of already been mentioned but conditionally updating 2 rows and 2 columns at any time the NT:s need to be overwritten helps with the attribute problem
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Advice for artifact free 4-way scrolling

Post by Bregalad »

thefox wrote:It does get pretty messy no matter what you do.
That. I couldn't have said it better.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Advice for artifact free 4-way scrolling

Post by tokumaru »

Just plan well from the beginning and it isn't so bad, specially if you use 4-screen.
User avatar
gauauu
Posts: 779
Joined: Sat Jan 09, 2016 9:21 pm
Location: Central Illinois, USA
Contact:

Re: Advice for artifact free 4-way scrolling

Post by gauauu »

tokumaru wrote: If you can, ditch the mirroring and go with 4-screen, that'll definitely make things easier.
That was going to be my advice also. The other thing that can make things easier (in some ways) is using 32x32 metatiles. That way you can write an entire attribute byte when you draw instead of having to mirror attribute ram or read-then-write it.
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Advice for artifact free 4-way scrolling

Post by Bregalad »

This gets better if you use 4-screen instead.
Just plan well from the beginning and it isn't so bad, specially if you use 4-screen.
If for some reason you give any care at developing a game with the same limitations as actual games were developed in the NES' life, do not use "4-screen" unless you absolutely must, as only 3 games did that, period. RAM was expensive back then and wasting it just for ease of coding was unrealistic.

Now if you don't care, then go ahead and use 4-screen, then it sounds like it'd be much easier but it'd feel like cheating.

For "perfect" scrolling with no actifacts you need to blank at least the top 8 scanlines (if using 8x8 sprites), or even the top 16 scanlines (when using 8x16 sprites) in order to avoid sprite pop-up when scrolling vertically. For that reason you'll need to mess with timing and PPU/mapper registers mid-frame for any clean vertical scrolling. So the only con of using vertical mirroring instead of 4-screen is that you need to blank 16 scanlines, and 8 is not an option anymore. (Technically 15 would be enough when using 8x16 sprites, but that doesn't make a great difference).
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Advice for artifact free 4-way scrolling

Post by tokumaru »

gauauu wrote:The other thing that can make things easier (in some ways) is using 32x32 metatiles. That way you can write an entire attribute byte when you draw instead of having to mirror attribute ram or read-then-write it.
Except that every other screen, vertically, is misaligned with the attribute grid due to name tables being 30 tiles (7.5 attribute bytes) tall. Unless you "cheat" and treat the last row of each screen of the level map as non-existent, simplifying rendering but complicating collision detection.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Advice for artifact free 4-way scrolling

Post by tokumaru »

Bregalad wrote:RAM was expensive back then and wasting it just for ease of coding was unrealistic.
Tons of games packed an extra 8KB of WRAM for "ease of coding" though.

Some NES programmers nowadays like to role-play and pretend they are in the 80's, so they won't do things that weren't commonly done back then (they'll hardly give up modern emulators, debuggers and tools though), even if they're cheap/trivial today.

I prefer to think that as technology advanced, the way things were done changed during the years the NES was active. Hardware got cheaper, tools got better, and so on, and it's only natural that development happening after that time continues to change. Each developer will have a different opinion on what's cheating and what's not.
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Advice for artifact free 4-way scrolling

Post by Bregalad »

tokumaru wrote: Except that every other screen, vertically, is misaligned with the attribute grid due to name tables being 30 tiles (7.5 attribute bytes) tall. Unless you "cheat" and treat the last row of each screen of the level map as non-existent, simplifying rendering but complicating collision detection.
Even then, you can work with attribute nybbles of 4x2 tiles instead of having to work with quantities of 2-bit at a time; this is still complicated but less than working with entirely 16x16 metatiles.
I prefer to think that as technology advanced, the way things were done changed during the years the NES was active. Hardware got cheaper, tools got better, and so on, and it's only natural that development happening after that time continues to change. Each developer will have a different opinion on what's cheating and what's not.
In this case, why limit yourself to 4 screens ? You can just put enough RAM so that the entiere level is decoded to VRAM at once, and nametables are just bankswitched in and out as the player scrolls. This makes a lot of sense.
User avatar
gauauu
Posts: 779
Joined: Sat Jan 09, 2016 9:21 pm
Location: Central Illinois, USA
Contact:

Re: Advice for artifact free 4-way scrolling

Post by gauauu »

tokumaru wrote:
gauauu wrote:The other thing that can make things easier (in some ways) is using 32x32 metatiles. That way you can write an entire attribute byte when you draw instead of having to mirror attribute ram or read-then-write it.
Except that every other screen, vertically, is misaligned with the attribute grid due to name tables being 30 tiles (7.5 attribute bytes) tall. Unless you "cheat" and treat the last row of each screen of the level map as non-existent, simplifying rendering but complicating collision detection.
That's absolutely true. Which is why I qualified the "some ways" -- attributes are easier. Other factors become issues instead.

(I "cheat" in my game, and skip the last 16 pixels of each room. It does complicate things in other spots)
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Advice for artifact free 4-way scrolling

Post by tokumaru »

Bregalad wrote:You can just put enough RAM so that the entiere level is decoded to VRAM at once, and nametables are just bankswitched in and out as the player scrolls.
I wouldn't do this myself, but if someone decided that this was worth the trouble of creating a new mapper (including modifying emulators for testing), I wouldn't think this was a bad idea. It's pretty cool, actually.

Like I said, everyone draws the line somewhere. Creating mappers is a little beyond my skillset, so I'd rather use what's readily available, but I won't restrict myself to the configurations that were common because that's supposedly more "authentic". We're not even talking about something new here, 4-screen WAS used back then, just not by many games.
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Advice for artifact free 4-way scrolling

Post by thefox »

tokumaru wrote:
Bregalad wrote:You can just put enough RAM so that the entiere level is decoded to VRAM at once, and nametables are just bankswitched in and out as the player scrolls.
I wouldn't do this myself, but if someone decided that this was worth the trouble of creating a new mapper (including modifying emulators for testing), I wouldn't think this was a bad idea. It's pretty cool, actually.
It's a fun idea for sure... could even be prototyped on PowerPak with its 512 KB PPU-mappable RAM.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
Post Reply