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.