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

Parallax scrolling + status bar in "Choplifter"

Parallax scrolling + status bar in "Choplifter"
by on (#154580)
What exact technique does the NES version of "Choplifter" use to create a non-scrolling status bar and background parallax scrolling at the same time?

One of them is surely done with sprite 0 hit.

But the other: Do they abuse the "more than eight sprites per scanline" flag by placing nine invisible sprites at the bottom of the status bar. Or do they use something different?
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154581)
Upper one is sprite 0. ($9250-$9255). The lower one seems to be a delay loop from the sprite 0 hit.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154584)
As far as I know, only Bee 52 uses the 9 sprites flag, and that's just for the title screen.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154601)
I was actually planning to do the thing with the nine sprites because I want to have a status bar and two background layers that scroll individually. Ergo: Nine sprites for the status bar and sprite 0 for the two layers.

Since it is so uncommon, is there anything that speaks against it? (Apart from the obvious fact that it takes away sprites for display.) I saw it as a pretty easy way to implement parallax scrolling. (Although I haven't tried it out yet.)

How complicated would the delay loop be? Does it just consist of the Assembly equivalent of this code:
Code:
for (i = 0; i < delayValue; i++)
{
}
and then you experiment how big the delay value has to be, so that the scrolling split happens at the right location? Or would it be more complicated?
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154607)
DRW wrote:
Since it is so uncommon, is there anything that speaks against it?

There's a sprite evaluation bug in the PPU that can result in false positives and false negatives, unless you use 9 high priority (i.e. lower OAM indices) sprites. This means that no other sprites can be displayed in the same scanlines.

Quote:
How complicated would the delay loop be?

It's as simple as you described. The only complication is that you have to use different values for PAL and NTSC/DENDY, so you need to detect the type of the console during the initialization or build different ROMs for different regions.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154610)
But you can use those 9 sprites as part of the status bar itself, so it isn't a total loss.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154613)
In a status bar it's not so bad that you can't have other sprites sharing the same scanlines. The only drawback is having to time the split from the top of the sprites, which are placed completely inside the status bar to avoid making sprites in the gameplay area.

The logical approach to using sprite overflows would be to use 9 LOW priority sprites, that would be there only to ensure that an overflow would happen, but would allow for actual game objects to be displayed. Unfortunately, the sprite evaluation bug makes that impossible.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154623)
tokumaru wrote:
There's a sprite evaluation bug in the PPU that can result in false positives and false negatives, unless you use 9 high priority (i.e. lower OAM indices) sprites. This means that no other sprites can be displayed in the same scanlines.

Yes, I've read about this bug. My intention was to use the first 10 sprites anyway: Sprite 0 for the parallax scrolling in the middle of the screen. And sprite 1-9 for the overflow. This will work, right?

My game will be designed in a way that no sprite from the actual game scenery will ever be able to touch the status bar.

tokumaru wrote:
It's as simple as you described. The only complication is that you have to use different values for PAL and NTSC/DENDY, so you need to detect the type of the console during the initialization or build different ROMs for different regions.

I was actually hoping that I just have to program the game for NTSC. If someone plays PAL, he either has to live with the slower speed or get himself a real NES.
But if something like that actually breaks the game when played in PAL (and I've seen that it actually does in "Choplifter") then I probably won't use the timing code. (Because either I implement a true PAL conversion or I program for NTSC only and let it run in PAL unaltered. But having just this one single check to prevent glitches in PAL while the rest is still slower, that's just a half ass work.) So, it's the nine sprites for me.

tepples wrote:
But you can use those 9 sprites as part of the status bar itself, so it isn't a total loss.

Sure, but what do I gain? I mean, if I have a status bar like in "Super Mario Bros.", of what use would it be if the score was created with the help of the nine sprites while the rest of the status values are still part of the background?
I mean, it's not that I could use the background tiles otherwise. Either the nine sprites are blank or a portion of the status bar in the background stays blank. What's the advantage to actually use the sprites for something in the status bar instead of leaving them invisible?

There is one disadvantage, though: If I use the nine sprites for the status bar, I have to put the number tiles into the sprite pattern table as well, wasting 10 of my 256 graphics items.

tokumaru wrote:
In a status bar it's not so bad that you can't have other sprites sharing the same scanlines. The only drawback is having to time the split from the top of the sprites, which are placed completely inside the status bar to avoid making sprites in the gameplay area.

I'm not sure if I understood this correctly. Are you talking about the fact that when this is my status bar and the magenta square represents my nine sprites:
Image
that the sprite overflow hits as soon as the first scanline of sprites is drawn and I therefore still have to calculate the time it takes to reach the last pixel of the status bar before I can change the scrolling position?

If yes, then I already thought about that:
I will have one blank row of eight pixels between the status bar and the highest gameplay point.

So, instead of something like this:
Image

I would have this:
Image

Therefore, I could change the scrolling position as soon as the sprite overflow hits. Because there is always one row of tiles that only consists of a blank background, so the graphics don't get garbled when I change the scrolling position in the middle of that one row.


Then, when it comes to the actual parallax scrolling in the middle of the screen, which is done with sprite 0, I'll do this:

Since the sprite 0 flag unfortunately only hits at non-transparent pixels, my sprite 0 would be a single dot and I would put it in the rightmost location of the screen so that the dot is at X position 255. (I would hide it behind an actual background element that is completely opaque from left to right in this scanline, like a wall of fog or something.)
The Y position of the dot would be exactly the lowest vertical point of the upper background.
This way, I can change the scrolling position for the lower background immediately when sprite 0 hits since the last pixel of the old scrolling area was just drawn in this very moment.


Would you say that my plans will work?
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154624)
You'd need to make sure the 9 sprites are above everything else, because otherwise you might have 8 sprites somewhere else, and exactly 8 sprites on a scanline breaks the overflow logic. So for a top status bar, that's probably fine, as long as players and projectiles can't get up there.

The timing of the sprite overflow flag isn't at the pixel when it's drawn, it's when it evaluates the 9th sprite. If it's in the first 10 sprites, that would be somewhere around 10/64 of draw time on that scanline.
If you are using the first 10 sprites, you also get sprite masking on those scanlines for free, no sprites can be drawn on the same lines where 8 have already been drawn.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154626)
DRW wrote:
tepples wrote:
But you can use those 9 sprites as part of the status bar itself, so it isn't a total loss.

Sure, but what do I gain? I mean, if I have a status bar like in "Super Mario Bros.", of what use would it be if the score was created with the help of the nine sprites while the rest of the status values are still part of the background?
I mean, it's not that I could use the background tiles otherwise. Either the nine sprites are blank or a portion of the status bar in the background stays blank. What's the advantage to actually use the sprites for something in the status bar instead of leaving them invisible?

These may not apply in all situations. But first, if you're already uploading a display list to OAM, it takes more vblank time to send 24 bytes of status bar to $2007 in addition to the display list that you're already uploading. And second, in games that scroll in four directions, keeping the background blank at the top also helps to hide attribute wraparound glitches.

Quote:
There is one disadvantage, though: If I use the nine sprites for the status bar, I have to put the number tiles into the sprite pattern table as well, wasting 10 of my 256 graphics items.

Or you can have sprites and background pointing at the same pattern table, and then switch sprites to the sprite pattern table once the beam passes the bottom of the status bar.

Quote:
Since the sprite 0 flag unfortunately only hits at non-transparent pixels, my sprite 0 would be a single dot and I would put it in the rightmost location of the screen so that the dot is at X position 255.

Sprite 0 hit operates only in x=0 to 254, not x=255, due to peculiarities of the PPU's pipeline.

The first 64 dots are spent clearing secondary OAM. After that, the PPU scans the sprite table and uses 8 dots for each sprite in range and 2 dots for each sprite not in range. If the first 8 sprites are in range, the flag will be set soon after x=128. If sprites 1-9 are in range, which is the case if you're using both sprite 0 and 9 sprites flags, the flag will be set soon after x=130: 64 to clear secondary OAM, 2 to skip out of range sprite 0, and 64 to accept eight sprites.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154627)
Dwedit wrote:
You'd need to make sure the 9 sprites are above everything else, because otherwise you might have 8 sprites somewhere else, and exactly 8 sprites on a scanline breaks the overflow logic.

Yes, that was my plan. Nothing from the actual game can touch the status bar or the eight pixels below it. Therefore, the first sprite overflow per frame will always be the nine sprites that I consciously placed there.

Dwedit wrote:
The timing of the sprite overflow flag isn't at the pixel when it's drawn, it's when it evaluates the 9th sprite.

Yeah, o.k., that's true.

But what would you say in general: If I have one row of eight pixels between the status bar and the background and if that one row is guaranteed to be blank at every time (i.e. it doesn't have non-blank background tiles and no sprite from the gameplay ever touches that area) and if I place my nine overflow sprites into that empty area, will it be safe to change the scrolling position as soon as the overflow hits (without including any kind of wait loop), so that no background graphics and status bar values are glitched?


EDIT: I'll answer the other post later.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154628)
DRW wrote:
Are you talking about the fact that when this is my status bar and the magenta square represents my nine sprites:
Image
that the sprite overflow hits as soon as the first scanline of sprites is drawn and I therefore still have to calculate the time it takes to reach the last pixel of the status bar before I can change the scrolling position?

Yes, that's exactly what I meant.

Quote:
I would have this:
Image

If that setup is good for you, fine. Normally people don't want a gap like this, and don't want to hide sprites for several scanlines AFTER the status bar, and in those cases the only solution would be to have the overflow happen earlier and wait for the end of the scanlines with timed code.

Quote:
Since the sprite 0 flag unfortunately only hits at non-transparent pixels, my sprite 0 would be a single dot and I would put it in the rightmost location of the screen so that the dot is at X position 255.

I remember something about sprite 0 his not working properly in the last column of pixels.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154633)
It doesn't work at all on the last column of pixels.
Re: Parallax scrolling + status bar in "Choplifter"
by on (#154637)
Good to know.

Alright, some things I have understood now, some things I haven't yet.

I guess before elaborating further theoretical concepts, I'll try out the whole status bar stuff and the parallax scrolling in my actual program with the actual positions and the actual graphics etc. and play around with the timing values to see if the same code works in both, NTSC and PAL without having to make a distinction between the two. (Until now, I've only tried it in a sample program with pseudo graphics.)

If I run into problems, I'll get back to this thread.

Thanks so far.