Can somebody explain "Sprite #0" to me?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Can somebody explain "Sprite #0" to me?
by on (#18461)
I've been reading documents that briefly discuss Sprite 0 but I don't understand what it actually does. I read somewhere that this is how the status information in Super Mario Bros. stays in one place while the screen scrolls? Is it that nothing on the screen is altered until the Hit Flag is set? Like, if the screen was scrolling to the right and Sprite 0 was in the third row of the screen and the top left pixel of Sprite 0 was on top of an opaque background pixel, would everything above that stay where it was before? That might very well be stupid but I've been searching for an explination for a while and I can't find one. :oops:

by on (#18463)
Yeah, you've got the basic idea of how it can be used. It's pretty generic and you can use it for anything, though only once per frame.

What it is exactly, is an easy way to time your code so you can do something in the middle of the screen (or wherever you place sprite #0 overlapping something).

So in Super Mario Bros for example, in the NMI routine it'd set the horizontal scroll to zero. After it does any other stuff needed, it'd wait for the sprite zero hit to happen. Then it would write the actual horizontal scroll, so the lower part of the screen will scroll. And just loops doing that.

BTW, sprite #0 in SMB is the coin graphic on the status bar.

Here's the code I use to wait for sprite 0 hit:
Code:
        lda #$40
:
        bit $2002
        beq :-


Let me know if that clarifies things or not.

by on (#18465)
Thanks Memblers, that does help. But now I've confused myself in a different way...

The text in the SMB status bar is made up of background tiles right? If the coin is sprite 0, why doesn't the text to the right of the coin scroll along with the rest of the screen? Then again, isn't the blue color the transparent background color? If the coin is always on top of the transparent background color, how is the hit flag ever set? Or, is there something behind the coin that isn't transparent?

I would have thought that if you wanted the top two 8px rows of the screen to remain stationary, you would have Sprite 0 placed so its top left pixel was at the top left of the third row on top of a non-transparent background tile and then have the scroll set to 0 until the hit flag was set. Wouldn't that make the top two rows remain stationary?

by on (#18466)
Quote:
Or, is there something behind the coin that isn't transparent?

I don't know exaclty about SMB, but yeah, that is the only way I can see, because you have to have both non-transparant pixels on both layer to have the hit flag set.
Also, you cannot rely on hits on just the last pixel of the scanline (pixel 255) nor in the first 8 pixels if any of the BG or sprites are clipped.

by on (#18469)
Bregalad wrote:
Quote:
Or, is there something behind the coin that isn't transparent?

I don't know exaclty about SMB, but yeah, that is the only way I can see, because you have to have both non-transparant pixels on both layer to have the hit flag set.
Also, you cannot rely on hits on just the last pixel of the scanline (pixel 255) nor in the first 8 pixels if any of the BG or sprites are clipped.


So basically you're saying if the sprites in the first and last column are being clipped you would have to put Sprite 0 in the second or next-to-last column for the hit flag to be able to be set, right? That makes sense.

What I don't understand is, if your routine has no scrolling and then when the hit flag is set it starts scrolling, does that mean that if you have Sprite 0 somewhere in the horizontal center of the screen, that the rest of the pixels in that scanline will be drawn with the scroll applied to them, or is the scroll not applied until the following scanline starts to be drawn? (I mean, does the change happen immediately when the overlapping pixels are detected?)

And I still don't understand why everything after the first nontransparent pixel of Sprite 0 (assuming there is something nontransparent behind it) doesn't scroll in SMB? That's like 7 and a half scanlines worth of graphics that don't scroll after the hit flag is presumably set (assuming it's at the leftmost pixel on the top row of the sprite). All of which means I'm just not understanding how it works... :oops:

by on (#18474)
Quote:
What I don't understand is, if your routine has no scrolling and then when the hit flag is set it starts scrolling, does that mean that if you have Sprite 0 somewhere in the horizontal center of the screen, that the rest of the pixels in that scanline will be drawn with the scroll applied to them, or is the scroll not applied until the following scanline starts to be drawn? (I mean, does the change happen immediately when the overlapping pixels are detected?)

This depend of your programm. Sprite zero hit doesn't make anything scrolling, it just helps a lot to TIME your programm.
The NES doesn't have any HDMAs or anything : you cannot just tell to the NES : Scroll background = 0 before the hit and ScrollFieldX after hit. You have to set the scroll to 0, wait the hit, and then rewrite ScrollFieldX after that in your scrolling register.
So you can use it for scrolling or whathever, or just wait a little more constant time until you upload the scrolling if you want to do so (looks like it is what SMB does).

Now, at the time you first write to $2005, as my undestanding, this will affect the horizontal scrolling immediately. To change vertical scrolling, you have to play with both $2005 and $2006 registers ($2006 is basically for adress, but during rendering it serves to adress tiles to render inside the screen). This is incredibly absurd and horrible to understand, and myself I've only understood half of that stuff (just enough to make some working mid-frame vertical scrolling in my game after loads of tries). Fortunatly, as long as you just scroll horizontally, things keeps simple.

Note that sprite zero hit isn't limited to scrolling. Actually, you'll have to use it for almost all effects changing anything midframe. You can change the scrolling each scanline inside a timed loop to have various wavy effects, change the colour emphasis or monochrome bit mid-frame and even mid-scanline, turn either BG or sprites (or even both) on and off, turn the left clipping on and off (while I haven't found any interesting use of this), change pattern table used for either BG or sprites, change name table used (this often comes together with horizontal scrolling). You can even turn the whole screen off during some scanline to write stuff to PPU memory through $2006/7 (such as the palette or re-do sprite DMA to have 2 regions with 256 sprites available) and turn the screen back, but this is hard to do proprely and doesn't make much sense in my opinion.

by on (#18479)
oxymoron wrote:
What I don't understand is, if your routine has no scrolling and then when the hit flag is set it starts scrolling, does that mean that if you have Sprite 0 somewhere in the horizontal center of the screen, that the rest of the pixels in that scanline will be drawn with the scroll applied to them, or is the scroll not applied until the following scanline starts to be drawn? (I mean, does the change happen immediately when the overlapping pixels are detected?)

The change does not happen immediately when the sprite 0 is detected; the program has to make it happen by writing to the scrolling registers. Typically, a program will wait in a tight loop spinning on PPUSTATUS ($2002), wait a few cycles after that (until horizontal blank, which depends on the horizontal position chosen for sprite 0), and then set the scroll position.

Quote:
And I still don't understand why everything after the first nontransparent pixel of Sprite 0 (assuming there is something nontransparent behind it) doesn't scroll in SMB? That's like 7 and a half scanlines worth of graphics that don't scroll after the hit flag is presumably set (assuming it's at the leftmost pixel on the top row of the sprite). All of which means I'm just not understanding how it works... :oops:

For one thing, the sprite 0 detection sprite overlaps only the bottom of the coin. For another, the program waits a few cycles after receiving the sprite 0 hit before rewriting the scroll registers.

by on (#18539)
tepples wrote:
Quote:
And I still don't understand why everything after the first nontransparent pixel of Sprite 0 (assuming there is something nontransparent behind it) doesn't scroll in SMB? That's like 7 and a half scanlines worth of graphics that don't scroll after the hit flag is presumably set (assuming it's at the leftmost pixel on the top row of the sprite). All of which means I'm just not understanding how it works... :oops:

For one thing, the sprite 0 detection sprite overlaps only the bottom of the coin. For another, the program waits a few cycles after receiving the sprite 0 hit before rewriting the scroll registers.


Thank you tepples! :D Half way through your first explanation I realized the overlap must be at the bottom of the coin and the scroll would start the following scanline. I don't know why it didn't occur to me that you could wait for hblank to actually change the scroll. :roll:

by on (#18682)
Bregalad wrote:
You can even turn the whole screen off during some scanline to write stuff to PPU memory through $2006/7 (such as the palette or re-do sprite DMA to have 2 regions with 256 sprites available) and turn the screen back, but this is hard to do proprely and doesn't make much sense in my opinion.

That would be 64 sprites, not 256! =)

Anyway, the procedure you described can surely be useful, if you are doing the type of screen set-up used in the 2-player split-screen mode in Sonic 2, 3 and knuckles. Or the one in Toejam & Earl (also a Genesis/Megadrive title). If you have a few blank scanlines between both views, you can easily have 2 diferent game sessions going on at once.

The only problem here would be processing power. That is, if the NES can handle two sets of collision detections, level-map rendering, etc, etc, without making it all too slow. I believe it can be done, depending on the type of the game, of course.

by on (#18685)
I believe Bigfoot used this principle.