User:Bregalad/Scrolling sandbox: Difference between revisions
(Separate regular scrolling and split scrolling) |
(Separate regular scrolling and split scrolling) |
||
Line 1: | Line 1: | ||
This is my proposal for a new [[scrolling]] page. Information which is currently on the [[mirroring]] page should be moved here. Because scrolling is complicated, it'll need much time before this is ready however !! Please wait until the merging is complete before giving feedback or constructive critisism. | This is my proposal for a new [[scrolling]] page. Information which is currently on the [[mirroring]] page should be moved here. Because scrolling is complicated, it'll need much time before this is ready however !! Please wait until the merging is complete before giving feedback or constructive critisism. | ||
The information previously in [[scrolling]] page is split between regular scrolling (this page) and [[User:Bregalad/Split Scrolling]] | |||
''' !! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!''' | ''' !! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!''' |
Revision as of 17:07, 16 April 2017
This is my proposal for a new scrolling page. Information which is currently on the mirroring page should be moved here. Because scrolling is complicated, it'll need much time before this is ready however !! Please wait until the merging is complete before giving feedback or constructive critisism.
The information previously in scrolling page is split between regular scrolling (this page) and User:Bregalad/Split Scrolling
!! CURRENTLY THIS PAGE IS A WORK IN PROGRESS !!
Info to be added from mirroring page
Horizontal mirroring is most commonly used for games which only scroll vertically or in all directions. Doing any horizontal scrolling using horizontal mirroring is hard to do smoothly because the data on the right of the screen is immediately show on the left due to mirroring. Clever use of hardware left-side screen clipping will hide all name table glitches, but because the attribute tables have a resolution of 2x2 tiles, there will always be attribute glitches on the left and/or the right side of the screen. The best possible way to hide it is to have 4 pixels with potentially wrong attributes on both sides, but most commercial games did worse than that having usually 8 or even more glitchy pixels, so that is why so many NES games have color glitches on the border of the screen. Some televisions overscan up to 8 pixels on both left and right border, but most doesn't. Perfectionist programmers could use solid black sprites on the right border to hide attribute glitches and make the screen look symmetrical and hide absolutely all attribute glitches, as in the game Alfred Chicken, but very few games do this because it reduces the number of sprites per scanline to 7 and wastes a lot of OAM space (roughly 1/4 in 8x16 pixel sprite mode).
Vertical mirroring is most commonly used for games which only scroll horizontally. Games that scroll vertically (by any amount and without status bar) and that never scroll horizontally by more than one screen would use this mirroring (e.g. Lode Runner, Bomberman, Fire Emblem, Crystal Mines), so that they don't have to load anything when scrolling horizontally. Of course it is also used for games which scroll in both directions without a status bar. Because data that is on the top/bottom of the screen will immediately show up on the other side, a clever use of NTSC overscan can make it glitch-less multidirectional scrolling, but glitches will appear on PAL televisions (and NTSC televisions with a overscan range which is a little off). The best possible way to hide glitches is to make 4 pixels with wrong tiles and 4 additional pixels with wrong color on both sides, but most commercial games did much worse than this, that's why they look so bad if overscan is disabled. Perfectionist programmers could use raster split to hide glitches (and possibly also provide more blanking time to update VRAM) as in the games Jurassic Park and M.C. Kids, but it was rarely done because it complicates the code a lot for little benefits.
Single-screen mirroring's main advantage is that it allows using a status bar at the top or bottom of the screen while also allowing the playfield to extend equally in any direction - this can be done by storing the status bar in one nametable, rendering the playfield in the other nametable, and switching mirroring (and scrolling parameters) at the appropriate screen location during rendering. There is also a lot of other things that can be drastically simplified when using 1-screen mirroring: The formulas used to calculate PPU address of data to be updated to the screen are also significantly simpler, and if the status bar have a variable size or is scrolling, all this would be a headache without 1-screen mirroring. When this mirroring is used to scroll horizontally, similar glitches and scrolling problems that those of horizontal mirroring will happen. However, as long as there is a status bar, no glitches will happen vertically since the data that falls off the bottom (or the top) of the screen will come in the area that is "hidden" by the status bar, regardless of overscan factors.
L- or X-shaped mirroring would facilitate changes in scrolling direction without having to flip between Horizontal and Vertical mirroring.
Mirroring chart
This table lists the more simple and easy to understand mirroring and scrolling techniques. There are a huge variety of more complicated techniques. For a more comprehensive survey, see: List of games by mirroring technique
Scrolling Type | Mirroring | Example Games | Comment |
---|---|---|---|
None | Any | Donkey Kong, Tennis | With only a single fixed screen, any mirroring type can be used. |
Horizontal Only | Vertical | Super Mario Bros., Gimmick! | A status bar at the top is easy to accomplish with a sprite-0 hit (see Super Mario Bros.). |
Vertical Only | Horizontal | Ice Climber, Gun.Smoke | Without a status bar, horizontal mirroring is the best choice for vertical-only scrolling. With a status bar, vertical or single-screen mirroring give you a place in the nametable to render the status bar, and the scrolling seam should be hidden under the bar. |
Alternating Horizontal/Vertical | Mapper switches H/V | Metroid, Air Fortress | Motion is limited to a single axis at any given time, and the direction can only change when a new screen is reached. |
Limited Bidirectional | Horizontal/Vertical | Super Mario Bros. 3, Fire Emblem | By limiting one of the scrolling axes to only 2-screens wide, this makes unlimited scrolling in the other axis simple. With unlimited horizontal scrolling there will be unavoidable attribute glitches at one side of the screen (see Super Mario Bros. 3), but with unlimited vertical scrolling this can be hidden by overscan in NTSC regions (see Fire Emblem). |
Unlimited Bidirectional | Various | Castlevania II, Battletoads, Crystalis, Final Fantasy | Unlimited scrolling in both axes at once is an advanced technique requiring a game-specific solution. |
The best way to understand the mirroring techniques used in a game, use a debugging emulator to look at the nametables. Status bars typically require a scrolling split at a timed location on the screen. This can be done most easily with a mapper based IRQ, but can also be accomplished with a sprite-0 hit or other techniques.
From current scrolling page
Scrolling is the movement of the displayed portion of the map. Games scroll to show an area larger than the 256x240 pixel screen. For example, areas in Super Mario Bros. may be up to 24 screens wide. The NES's first major improvement over its immediate predecessors (ColecoVision and Sega Mark 1) was pixel-level scrolling of playfields.
The common case
Ordinarily, a program writes to two PPU registers to set the scroll position in its NMI handler:
- Find the X and Y coordinates of the upper left corner of the visible area (the part seen by the "camera")
- Write the X coordinate to PPUSCROLL ($2005)
- Write the Y coordinate to PPUSCROLL
- Write the starting page (high order bit of X and Y) to bits 0 and 1 of PPUCTRL ($2000)
The scroll position written to PPUSCROLL is applied at the end of vertical blanking, just before rendering begins, therefore these writes need to occur before the end of vblank. Also, because writes to PPUADDR ($2006) can overwrite the scroll position, the two writes to PPUSCROLL must be done after any updates to VRAM using PPUADDR.
By itself, this allows moving the camera within a usually two-screen area (see Mirroring), with horizontal and vertical wraparound if the camera goes out of bounds. To scroll over a larger area than the two screens that are already in VRAM, you choose appropriate offscreen columns or rows of the nametable, and you write that to VRAM before you set the scroll, as seen in the animation below. The area that needs rewritten at any given time is sometimes called the "seam" of the scroll.
Frequent pitfalls
- Don't take too long
- If your NMI handler routine takes too long and PPUSCROLL ($2005) is not set before the end of vblank, the scroll will not be correctly applied this frame. Most games do not write more than 64 bytes to the nametable per NMI, more than this may require advanced techniques to fit this narrow window of time.
- Set the scroll last
- PPUSCROLL must always be set after using PPUADDR ($2006). They have a shared internal register and using PPUADDR will overwrite the scroll position.
PPU registers
If you aren't trying to split the screen, scrolling the background is as easy as writing the X and Y coordinates to $2005 and writing the high bit of both coordinates to $2000. Programming or emulating a game that uses complex raster effects, on the other hand, requires a complete understanding of how the various address registers inside the PPU work.