Determining spr0 hit on a vert/horz scrolling screen

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Determining spr0 hit on a vert/horz scrolling screen

Post by FrankenGraphics »

Description:
The goal is to arbitrarily be able to switch nametables (or rather, nametable banks since it's GTROM) using sprite 0 hit at a top scanline.

This is how i imagine it to work: After vblank, we begin a new frame with a constant, never scrolling tile row from nametable/pattern bank 0. Sprite 0 is constantly placed on top of a same-coloured line. This will tell the mapper to switch nametable/pattern banks to 1 and set scroll to positions stored in zp RAM. This bank 1-based field will be scrolling on both x and y axis; following an introductory sweep of the scene, and/or the voluntary movement of camera by player. It's never larger than the four screens' worth of nametable space.

A strip of text will appear describing the scenery or some detail. This is supposed to be done by having counted scanlines and switching back to the 'text'/0 banks. This means i'd probably use pubby's constant-cycle music engine to keep the counting accurate.

The game is simple. It's just pictures and text and 'point/select and click'. No action logic happening between player actions. Just a bit of sprite animation happening during vblank.

Question 1: am i overlooking a less complicated way of doing the switching? IRQ scanline counting is unfortunately out of question since the project relies on making use of GTROMs' nametable and pattern bankswitching capabilities in order to keep both scenery as detailed as possible and item graphics + text patterns/strings in their separate nt/char banks.

An option i've pondered is starting in nt/chartable bank 1 (meaning no border above), make sure sprite overflow will happen at a certain scanline (where the text strip section should begin), do a little counting here where it is less sensitive to cycle wobbling and get the desired text scroll effect. Sacrificing 8 or 9 sprites this way is a bit wasteful, but there's less need for counting lines. Then either terminate the text strip with further scanline count, or spr0 hit.

Question 2: Anything i should be watchful of, or something that will outright put a halt to this plan/layout?

For clarification, here's a rudimentary layout. Imagine a free-moving scenery where the typographic samples and green gradients are.

Another few notes:
-Overscan will hide the upper border, and if not; it's simple enough to not be intrusive.
-The 'text strip' can be put off-grid and hopefully scroll independently to reveal more than two lines of text in a scrolling motion. The 'ankh' symbol is meant to mark "end of description - next button press will remove the text strip from the field of play". To keep borders nonscrolling, y scrolling will be set more than just once here.
Attachments
layout_and_typography_test.bmp
layout_and_typography_test.bmp (30.12 KiB) Viewed 2823 times
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by rainwarrior »

FrankenGraphics wrote:i'd probably use pubby's constant-cycle music engine to keep the counting accurate
Why would you need to use that if you're using sprite 0 hit to synchronize?

I find it a little difficult to follow your description, but it sounds like you want 2 scroll splits. The first at the top of that text region at the bottom, and a second one at the end of the text region to put that green piece of footer there?

A sprite 0 hit will find the top. Just count cycles for 64 scanlines and then do the other split. There should be lots of time to fit the rest of your game's update before the sprite 0 hit, so you can probably literally just waste cycles across it, and not have to do anything more difficult/tedious than that.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by tepples »

A sprite 0 hit at the top of the text region will miss if the background is blank there, unless the game continuously changes the tile behind the hit to one guaranteed to be opaque. It's slightly more annoying to guarantee a hit there for an 8-way scrolling engine than for a 2-way one, though some NES games do this.

Does the music use the DMC? If not, there's another way to make multiple splits without spin-waiting throughout most of the frame.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by FrankenGraphics »

rainwarrior wrote:I find it a little difficult to follow your description, but it sounds like you want 2 scroll splits.
Re-reading my description, i can see how it was hard to follow. Let me try rephrasing it.

The text box will always appear somewhere on the bottom but not quite at the very bottom. It's also going to get a bit slimmer.

It would in its most basic form require 2 scroll splits + 2 GTROM-specific CHR-RAM bank shifts.* If i also want the text inside that box to scroll 'forward' at a button press; while at the same time keep the upper and lower borders of the box non-scrolling, i'd need 2 additional scroll splits. 4 in total so far, and close to each other. That's all fine, i think.

The trouble is that at the same time, everything that is _not_ the text strip will scroll independently in horz, vert or both axes; depending on scene. This means i cannot guarantee sprite 0 will get a hit, since the background it is hitting against will move.

So my first solution is a brute force one: Start a frame with scroll values set to 0 and "sacrifice" one or two scanlines for a visible border; probably using tiles from the 'text box chr-ram bank'. Sprite 0 will always hit against that border, so we can switch to the 'scenery chr-ram bank' and set scroll to their appropriate values. This means counting would start very early on.

The second solution i'm considering is using the sprite overflow flag, always make sure that scenery sprites + cursor never trigs it prematurely, and live with 8 'wasted' sprites (9 in total compared to the one used for sprite 0 checks) by placing 9 of them at the scanline where i want the text box/item box to appear. That is easier, more dynamic, it just means the scenes will be somewhat less detailed/dynamic in return. But it's a fair tradeoff.

*This is because i dedicate all four visible nametables to sceneries in one of the two "CHR-RAM banks", and all four in the other bank for preloading anything text/dialogue/status/inventory related. A 'scene' is never larger than 4 nametables, so i never need to update nametables due to scrolling. all CHR-RAM loading happens inbetween when the player is being taken from scene to scene.

My first question then is:
If i mean to keep this specific feature set; am i overlooking a less complicated solution?

The second question is more or less a safety check if anyone more knowledgable knows there's something with these two strategies that just won't work and i shouldn't pursue it.
tepples wrote:A sprite 0 hit at the top of the text region will miss if the background is blank there, unless the game continuously changes the tile behind the hit to one guaranteed to be opaque. It's slightly more annoying to guarantee a hit there for an 8-way scrolling engine than for a 2-way one, though some NES games do this.
So that's a third strategy: Always change the the reference of the tile that's going to be under sprite 0 to a custom one that will always guarantee a match. The challenge then becomes making that tile look "non-glitchy" by copying the contents of the tile it is supposed to replace and fill in a single pixel just where sprite 0 will be.
Does the music use the DMC?

I haven't even considered this before. The music is mostly currently a collection of whistled, played and hummed tunes on my dictaphone. In a game which premieres 'pretty sceneries' (like an interactive adventure novel or an adventure game) over intricate real-time updates (like an action platformer), it might make sense to make the most out of the 2A03 to complement the scenes/substitute the lack of continous action - be it music or sfx. But nothing is set in stone.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by rainwarrior »

FrankenGraphics wrote:The second solution i'm considering is using the sprite overflow flag, always make sure that scenery sprites + cursor never trigs it prematurely, and live with 8 'wasted' sprites (9 in total compared to the one used for sprite 0 checks) by placing 9 of them at the scanline where i want the text box/item box to appear. That is easier, more dynamic, it just means the scenes will be somewhat less detailed/dynamic in return. But it's a fair tradeoff.
Are you aware that sprite overflow is broken? It generates false positives in some conditions that are hard to avoid if you've got arbitrary sprite placement. It's easy to use at the top of the screen without fear of getting a false positive, but not easy to use reliably anywhere else.
FrankenGraphics wrote:If i mean to keep this specific feature set; am i overlooking a less complicated solution?
I don't think so. The "easy" way to do it is by using a mapper with a scanline IRQ. This is what that feature is designed to do.

If you're trying to target hardware that's easy to build, you might consider that a "complicated" mapper can be a lot less complicated if you only use a subset of its features.
FrankenGraphics wrote:So that's a third strategy: Always change the the reference of the tile that's going to be under sprite 0 to a custom one that will always guarantee a match. The challenge then becomes making that tile look "non-glitchy" by copying the contents of the tile it is supposed to replace and fill in a single pixel just where sprite 0 will be.
Guardian Legend does this in a pretty visible way, if you want an example.

Since you're using CHR-RAM, you could maybe stick one custom tile in the corner with one pixel, or row of pixels added to ensure a sprite 0 hit. Like, reserve tile 255 for this or something, and on each frame, identify the corner tile in the nametable, replace it with tile 255, and then fill tile 255's CHR with a copy of the tile that should be there but with the pixels you need set. Could potentially reduce the visual error to <= 8 pixels on the line before the split.

It's a little bit of a complicated suggestion, but you said you're not planning to update the nametables anyway, so your PPU bandwidth seems free for something like this?

(Edit: I just realized, on re-reading it that this is maybe exactly what you're suggesting? Sorry for being an echo. My first scanning of it thought you were just talking about the coarse/easier technique of just replacing a single nametable tile with a solid one.)
tepples wrote:(DMC IRQ suggestion)

In general, the DMC IRQ is reliable for only very coarse timings, I think? You use it to IRQ in the ballpark of something else you can reliably wait for (e.g. sprite 0 hit). Having an IRQ basis, though, means you're free to spend more time on your game update and not worry about waiting for sprite 0 in time, since the IRQ is now doing that automatically. So... it's useful as an augmentation of sprite 0 rather than a substitute for it.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by rainwarrior »

FrankenGraphics wrote:If i mean to keep this specific feature set; am i overlooking a less complicated solution?
Oh, I completely forgot to say, the easiest thing to do is have your raster splits at the top of the screen rather than the bottom. If you wouldn't mind having the text at the top instead, the whole problem kinda goes away.

There are several simple ways to detect/synchronize with the end of vblank. The raster effects can be confined to the NMI handler so you don't have to worry about lag frames either.


I suppose I also don't understand how either of the layers is supposed to be free-scrolling if you've got those green fringed borders. The raster effects are going to necessitate a hard line either way, aren't they? Why does the border have a fringed edge?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by tepples »

rainwarrior wrote:
tepples wrote:(DMC IRQ suggestion)

In general, the DMC IRQ is reliable for only very coarse timings, I think? You use it to IRQ in the ballpark of something else you can reliably wait for (e.g. sprite 0 hit). Having an IRQ basis, though, means you're free to spend more time on your game update and not worry about waiting for sprite 0 in time, since the IRQ is now doing that automatically. So... it's useful as an augmentation of sprite 0 rather than a substitute for it.
If I trigger an IRQ then count cycles till the next IRQ, I can determine fairly precisely when the next IRQ will happen. Remember DPCM Letterbox? Two rock-solid splits, little spinwaiting, no mapper.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by rainwarrior »

Hm, so you use a quick IRQ test to get the DPCM sample pipeline into a predictable state, followed by the IRQ for your split? That makes sense, I'd never thought about the possibility of an extra throw-away IRQ in there.
User avatar
FrankenGraphics
Formerly WheelInventor
Posts: 2064
Joined: Thu Apr 14, 2016 2:55 am
Location: Gothenburg, Sweden
Contact:

Re: Determining spr0 hit on a vert/horz scrolling screen

Post by FrankenGraphics »

rainwarrior wrote:Are you aware that sprite overflow is broken?
I'm aware the bug exists, but not 100% sure what it entails.

My hypothesis is that if i need to allow for 8 sprites on a scanline (which will trig the 'diagonal' bug), the last of those 8 sprites should be placed last in primary OAM so that we've reached end of list by the time it trigs, so that it can't do any harm. This would yield a safe width of 7 sprites per scanline just like otherwise, but once per full screen it can safely be 8 (for example an eighth sprite overlapping two rows of 7 other sprites each). At least that's how i think it would work. But with horizontal scroll, what would be the 8th sprite is not as certain as otherwise.

Just having 7 sprites per scanline for most of the time is a bit harsh, but could work.

For a screen of non-moving sprites (maybe a title screen), one could pay close attention to what bytes are read as y position and place lots of safe-positioned/attributed sprites last in OAM. But most sprites will move in my case, either in pace with the scrolling, and/or by position animation.
If you're trying to target hardware that's easy to build
Well, this is one reason (i'm terribly slow at coding, quicker at making graphics), but not the only one. On one hand, GTROM lets me:
-Be very flexible with how much of ROM is used for graphics storage; as any chr-ram pcb would. It'll be lightweight on code, heavyweight on graphics and probably also sound.
-Allow me to swap between chr banks a bit like it was chr-rom on the fly, even though it's chr-ram (because of banked 16kB pattern table, 8kb nametable). Perks from both options. This means i can dedicate a whole pattern table to the scenery alone, and keep another for graphical/text interface. This is also used as a simple (free of code) way to have subsets of lowercase letters aligned differently to get around monospacing.
-For the same reason come up with simple code and be done with it; like loading precomposed descriptive texts to nametable ram and set scroll to show a bit at a time.
-save game and settings in a nonvolative storage without the need of batteries.
-Make hardware copies at circa half the price per pcb of, say, TKROM.

On the other hand:
-Since it's chr-ram, loading has to happen, and it's a lot to load ever so often: For every or every other new place/room, up goes up to 2 pattern tables' worth of data (scenery bg and sprites), and up to 8 nametables (scenery and new text strings. I might load the latter progressively, though).
-32kB bankswitching will either have me write extra code or copyclone code to different banks.
and more importantly:
-No scanline IRQ.

I think TKROM is a somewhat good comparison. It was used for Shadowgate (same genre of game), which i hope to "surpass" at least a bit in terms of visual presentation, if nothing else. It has something like 44-45 rooms, i believe, and 128kB chr-rom. Deja Vu has 256kB chr-rom (but doesn't look twice as pretty :wink: ) EDIT: Looking at Shadowgates' pattern tables, there's the reason for detail not scaling 1:1 with chr rom size. A good half (from $6e to $ff) is reserved for the interface in both tables, and since it's chr-rom, it must keep a copy of it in each chr bank.

An oversized UxROM might've been an interesting option, too, from the 'detailed/pretty scenery' perspective - not that it would help with the particular issue of this thread.
Guardian Legend
Hm. it doesn't look too bad, even if it's a bit quirky. That'd be an ok fall-back option if editing tiles in ram would prove a bit too tedious for me.
not planning to update the nametables
Might be that i add a little tile reference animation in the end, but i won't plan around it. Uploading new columns/rows for further scrolling than 4 static nametables would permit won't be on the table.


All in all, it looks like there's some great options to experiment with.
Oh, I completely forgot to say, the easiest thing to do is have your raster splits at the top of the screen rather than the bottom. If you wouldn't mind having the text at the top instead, the whole problem kinda goes away
Yeah, that's true. :) It kind of feels more 'natural' to let the eyes 'rest' on descriptive text if it appears below the scene, though?
I suppose I also don't understand how either of the layers is supposed to be free-scrolling if you've got those green fringed borders. The raster effects are going to necessitate a hard line either way, aren't they? Why does the border have a fringed edge?
Oh, that's unnecessarily confusing. Pardon that. I should've replaced the whole typography test with a rudimentary scene. Basically, anything above the hard black-and-purple lines is to be considered 'scenery', not 'text box'. Same goes below the box. The green/black gradient won't be there or anywhere at all. :oops:
Post Reply