This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Parallax scrolling

Parallax scrolling
by on (#152682)
I tried to do parallax scrolling in my program. I wanted to use the sprite 0 for this to change the scrolling position mid-frame.

If I have two layers that scroll with a different speed, everything works fine.

But I need at least three layers:
1. The status bar (no scrolling).
2. The background (slow scrolling).
3. The foreground (quick scrolling).

My attempt was this:
First, I do the general status bar stuff: Setting scrolling to 0, waiting for sprite 0 to hit, then setting the actual scrolling position. This works as always.

But now my problem:
For three layers, I did this:
I waited for sprite 0 to hit to change the scrolling position from 0 to the current value.
Then I moved sprite 0 down the screen to the next location.
I waited for it to hit again to change the scrolling position a second time.

But the program just took layer 1 (the status bar) and layer 2 (the background) and set it to scroll position 0.

So, I'm able to scroll with two different layers. But as soon as I try three layers, he treats the first two layers as one.

Is there any general thing that I have overlooked?
Re: Parallax scrolling
by on (#152683)
Only one sprite 0 hit is possible per frame. If you put the status bar on the top, you can use the 9 sprites for the first split (at the top of the status bar) and sprite 0 for the second (at the dividing line between the background and foreground). But if you do more than one split, you'll be spending a lot of time sitting in a loop. At that point, it's wise to use more advanced techniques, such as mapper IRQs or the DPCM Split.
Re: Parallax scrolling
by on (#152687)
tepples wrote:
If you put the status bar on the top, you can use the 9 sprites for the first split (at the top of the status bar) and sprite 0 for the second (at the dividing line between the background and foreground).

I didn't understand this. What nine sprites are you talking about?

tepples wrote:
At that point, it's wise to use more advanced techniques, such as mapper IRQs or the DPCM Split.

Is any of this possible with simple mapper 0 games or do you need a higher mapper to do it?
Re: Parallax scrolling
by on (#152690)
Quote:
I didn't understand this. What nine sprites are you talking about?

In addition to sprite 0 hit, there's another bit that in $2002 that tells you if more than 8 sprites per scanline were drawn. You can force that to trigger during a specific part of the screen by putting 9 sprites there.

Quote:
Is any of this possible with simple mapper 0 games or do you need a higher mapper to do it?

There's possible, and there's maintainable. You could do it all solely with timed code, but that's kind of nuts. I'd recommend a mapper if you want two or more splits.
Re: Parallax scrolling
by on (#152692)
Kasumi wrote:
In addition to sprite 0 hit, there's another bit that in $2002 that tells you if more than 8 sprites per scanline were drawn. You can force that to trigger during a specific part of the screen by putting 9 sprites there.

I assume this works only once per frame, right? Because otherwise I would think that you can use this to do as many scroll splits as you like.

Kasumi wrote:
You could do it all solely with timed code, but that's kind of nuts. I'd recommend a mapper if you want two or more splits.

Well, in this case, I'll go with one split and try out the nine sprites version. Because I'm not planning on doing my first game with a higher mapper or with any big fancy tricks.
Re: Parallax scrolling
by on (#152695)
Use a scanline IRQ, you'll waste less time looping waiting for screen splits.
Re: Parallax scrolling
by on (#152697)
Another option (if you don't want to lose 10 sprites), is to use timed code for the status bar. In the NMI, do your PPU updates normally, and when you're done, you wait for the sprite 0 hit flag (which was set in the previous frame) to be cleared, which happens at the end of VBlank, to sync with the PPU. Then you run a dummy loop that always takes X scanlines to finish, where X is the height of the status bar. Now you can do the first split, and the next one is done after the sprite 0 hit, as you already got working.

The downside is the amount of CPU time you spend just waiting, after VBlank and before the first split. To minimize this loss you could try to put some tasks that use a fixed amount of CPU cycles in there, such as reading controllers, clearing OAM, or whatever other tasks that always take the same time to run. Then pad until the end of the status bar.
Re: Parallax scrolling
by on (#152698)
DRW wrote:
I assume this works only once per frame, right? Because otherwise I would think that you can use this to do as many scroll splits as you like.

To be honest, I don't know if it works only once for frame.

When you use sprite DMA, it COPIES the page you give it (say $0200-$02FF) to the PPU. If you write a new value anywhere in that range, it doesn't matter. The PPU wouldn't see it until you sprite DMA again. Because the PPU doesn't look at $0200-$02FF when it's rendering. It looks at its own internal RAM which you can't really access. (Please no pedantic, guys.) You can't sprite DMA while the screen is rendering safely, so the whatever sprites you gave it are what is drawn. You can't move them mid render to get multiple hits. That would at least be why sprite 0 doesn't work multiple times.

It'd be interesting to know if the 9 sprites can hit multiple times per frame, but you could only get 7 splits that way using ALL of your sprites for only that purpose. 64/9=7 and some decimals.

Edit: One other thing to keep in mind if it IS possible to do multiple times, is the action on screen (your actual enemies/projectiles/player character) might cause a sprite overflow which would screw up your splits. This is why tepples recommended the overflow for the status bar split (It's easy to keep your game objects from going there), and sprite 0 for the extra split.
Re: Parallax scrolling
by on (#152704)
Yes, the sprite 0 hit and sprite overflow flags only work once per frame, because once they're set by the PPU, you can't manually clear them. The PPU will automatically clear them at eh end of VBlank.

But even if you could reuse the sprite overflow flag for multiple splits, that would be dangerous, since you can have accidental overflows as the game objects move around the screen. This is why this solution was suggested for a status bar at the top of the screen, because the status bar is rendered before the game objects, so you can be sure there will be no sprite overflows before the status bar ends. You can't use this flag reliably at the bottom of the screen.
Re: Parallax scrolling
by on (#152707)
Another thought... If your upper background is a repeating pattern, you could swap CHR-ROM banks to shift the pattern at a different rate than the lower background.

I think Bucky O'Hare does this somewhere.
Re: Parallax scrolling
by on (#152709)
And Battletoads, and Blade Buster, etc.
Re: Parallax scrolling
by on (#152711)
dougeff wrote:
And Battletoads, and Blade Buster, etc.

And Sword Master, and Metal Storm, and Mitsume ga Tooru... BTW, Battletoads doesn't use bankswitching, it uses CHR-RAM and manually updates the tiles. That's hardcore.

Anyway, unless you use CHR-RAM and do it like Battletoads (which is pretty hardcore), you have to use a complex mapper, which he doesn't want to.
Re: Parallax scrolling
by on (#152714)
Why did some games try to do everything with CHR-RAM? Were the ROM chips cheaper?
Re: Parallax scrolling
by on (#152718)
Using CHR-RAM instead of CHR-ROM probably did result in a lower production cost. But certain things particularly with more advanced mappers are better suited to CHR-ROM. And the reverse is true, CHR-RAM is better suited for certain things too.
Re: Parallax scrolling
by on (#152722)
Yes, ROM was (and still is) cheaper.
Re: Parallax scrolling
by on (#152725)
lidnariq wrote:
Yes, ROM was (and still is) cheaper.


But if you need two separate ROMs made, would that have cost more than having just one ROM and CHR-RAM? With the volume of units that could use the 8KB SRAM chips maybe the cost wasn't more?
Re: Parallax scrolling
by on (#152728)
To me it sounds logical that a mask ROM, which is a custom part, would cost more than an off the shelf part, but I can't back this up.

There's also the fact that by using CHR-RAM you can save some money on the mapper, because CHR-RAM is versatile by nature, while CHR-ROM needs fine bankswitching (which is only present in more advanced mappers) to be versatile.

Even if using CHR-RAM instead of CHR-ROM didn't make Battletoads carts cheaper, using AOROM instead of an MMC3 probably did, and yet the game still features large colorful well animated characters, split parallax, overlapping parallax, background animations, things that a lot of games with more complex mappers didn't have, because CHR-RAM is that versatile, in the hands of competent programmers.

Most computers and consoles didn't offer the possibility of using CHR-ROM, so it's not like CHR-RAM was something mysterious or difficult to use, it was actually the norm, so it's not so surprising that some programmers would consider it common place.
Re: Parallax scrolling
by on (#152735)
MottZilla wrote:
But if you need two separate ROMs made, would that have cost more than having just one ROM and CHR-RAM? With the volume of units that could use the 8KB SRAM chips maybe the cost wasn't more?
As near as I can tell, not only is a PROM cheaper than a RAM, but the up-front cost for a Mask ROM conversion is small enough that you don't need too much volume to make it cheaper to switch:
this webpage says that it's an up-front cost of $85k for a Mask ROM conversion, and this book claims that the per-unit cost of a EPLD is 3x the cost of a Mask PLD (which, yes, isn't the same as a ROM, but it's not too dissimilar)

Of course, now, with e.g. the SST39SF010A being 58¢/@10k, the calculus is less clear. A substantial portion of this cost is packaging, now. Even the SST39SF040 is 93¢/@10k, and the M29F160 is ≈$2.40/@10k, so for modern prices you're necessarily talking about volumes of hundreds of thousands to make up this investment.

To make matters worse, I can't find any information about costs in the last 1980s/early 1990s, although I have this hunch that the Mask ROM conversion cost hasn't changed appreciably.
Re: Parallax scrolling
by on (#152871)
Alright, I'll try the version with the nine sprites. My game will have only one scrolling split anyway (plus the status bar).

Does the sprite overflow work even with empty sprites (i.e. a tile that has only the transparent color) or is it the same as with the sprite 0 hit where the flag is only set if an actually visible pixel hits the scanline?
Re: Parallax scrolling
by on (#152872)
Sprite overflow will work with transparent sprites. In theory, it's supposed to tell you if there are too many sprites on a scanline. Even if they're transparent, they still take up a slot in the PPU's working RAM for OAM.
Re: Parallax scrolling
by on (#152874)
Why wasn't this done with the sprite 0 as well? Why does the sprite 0 flag only hit when a visible pixel of that sprite touches a visible pixel of the background?
Re: Parallax scrolling
by on (#152876)
DRW wrote:
Why wasn't this done with the sprite 0 as well? Why does the sprite 0 flag only hit when a visible pixel of that sprite touches a visible pixel of the background?

As far as anybody outside Nintendo's sphere of non-disclosure can tell, it's probably a workaround for some patent. (Remember that the Famicom was conceived when the concept of a video game itself was still patented by Ralph Baer.) This way, Nintendo could plausibly pretend that it was for collision detection.
Re: Parallax scrolling
by on (#152878)
You can set the sprite zero attributes to be behind the background, essentially making it invisible.
Re: Parallax scrolling
by on (#152891)
Yeah, but you need to have a background element in the first place. If you want to draw your status bar on the blank background, you need to have some element that is only there to hide the zero sprite.
Re: Parallax scrolling
by on (#152912)
Note that you can also do a top status bar with timed code, but that might be tricky.
Re: Parallax scrolling
by on (#152914)
Yeah, I tend to use the simple stuff for these things. I guess I'll have enough to do implementing the game itself. So, these whole techical details: For my first game, I'll try not to use some complicated hacks.
The nine sprite thing is something that I'll probably use anyway because I really want to do parallax scrolling. But timed code: Meh. Maybe next time when I program the next "Castlevania". 8-)
Re: Parallax scrolling
by on (#152919)
Dwedit wrote:
Note that you can also do a top status bar with timed code, but that might be tricky.

Am I invisible?

It's tricky if you try to time the code from the start of VBblank, but when you detect the end of VBlank by waiting for the sprite 0 hit or sprite overflow flag to be cleared and time it from there, it's quite simple.
Re: Parallax scrolling
by on (#170226)
tokumaru wrote:
To me it sounds logical that a mask ROM, which is a custom part, would cost more than an off the shelf part, but I can't back this up.

There's also the fact that by using CHR-RAM you can save some money on the mapper, because CHR-RAM is versatile by nature, while CHR-ROM needs fine bankswitching (which is only present in more advanced mappers) to be versatile.

Even if using CHR-RAM instead of CHR-ROM didn't make Battletoads carts cheaper, using AOROM instead of an MMC3 probably did, and yet the game still features large colorful well animated characters, split parallax, overlapping parallax, background animations, things that a lot of games with more complex mappers didn't have, because CHR-RAM is that versatile, in the hands of competent programmers.

Most computers and consoles didn't offer the possibility of using CHR-ROM, so it's not like CHR-RAM was something mysterious or difficult to use, it was actually the norm, so it's not so surprising that some programmers would consider it common place.


Yeah battletoads was/is an interresting game wich greatly simulate 16bit graphics on the nes,man if i saw this back in the 90's,whoaah,that would,ve blowed my face being me deheaded hahaha,also 1bit pcm can be done on the nes while still running a game smoothly can be done too,but that takes tons and tons of space, who could,ve ever tout that this was possible on nes,even supermariobros3 looks like nothing,even ninja gaiden 3 on the nes has some paralax scrolling wich even the lynx & snes version do averagely lack.
Sega said,genesis does what nintendon't,well think again an 8bit is all you need.
Re: Parallax scrolling
by on (#170242)
Not to sound like a dick, but did you just dig up a nine months old thread about the technical implementation of parallax scrolling just for some general ramblings about how much you like "Battletoads"?
Re: Parallax scrolling
by on (#170249)
Presumably, he's got so much appreciation for Battletoads that he wanted to share it with the world.
johannesmutlu wrote:
well think again an 8bit is all you need.

I loved this.
Re: Parallax scrolling
by on (#170377)
That's the kind of agony I feel when I read comments like "the NES has 8 bits of memory".

But to actually contribute something to the topic, it's clear that CHR-ROM has a clear advantage when you need lots of tiles swapped quickly, or have multiple tilesets available per frame, but other than that...?
Re: Parallax scrolling
by on (#170378)
It depends if you're contrasting CHR-ROM to bankswitched CHR-RAM, which is considerably more viable now than it was then. If you have bankswapping CHR-RAM, then the only real advantage I'd see for CHR-ROM is the option to use the second ROM slot so that you have more PRG-ROM available. However, there are a several advantages to using ROM over RAM in the traditional sense.

For starters, I'm sure Nintendo cut costs by not having more video RAM in their systems. This was a selfish, long-term play though that pushed the cost to software manufacturers.

Arcades used ROM for graphics, so that they could have more frames of animation quickly. NES can have a lot of frames of animation very quickly where some video RAM based consoles suffer at this.

Mid-screen graphic changes in general, are not possible without bankswapping. To bring it back to the topic of parallax scrolling, you can have multiple horizontal strips which draw from different background banks, and swap them while the screen is rendering. There is no way you could write tiles into CHR-RAM during that time.

Edit: I went back and reread and you listed most of the same advantages I did... but those can be big advantages! Graphics can push boundaries on the NES in ways they can't on many other systems, particularly in framerate.