Sprite 0 hit, do I understand correctly?

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
klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Sprite 0 hit, do I understand correctly?

Post by klonoa » Sat Aug 08, 2020 8:04 am

Good day all,

I was reading up on the sprite 0 flag and immediately a few questions started popping up in my head.

When an nmi hits:
0. update color palates and background tiles if necessary. (still in vblank)
1. Do the sprite DMA. (still in vblank)
2. Read controllers.
2. update game.
3. update music and sound.

Now say I want a status bar at the bottom of the screen that takes about a 5th of the screen.
I'd place sprite 0 around x0 and y52 so it will set the flag when the beam is around the last 5th of the screen.
The problem that I see is that this doesn't trigger an interrupt.
So where would one usually check the sprite-0 flag?

When an nmi hits:
0. update color palates and background tiles if necessary. (still in vblank)
1. Do the sprite DMA. (still in vblank)
<<<<<<<<<<<<<<<<<<<<Somewhere here?
2. Read controllers.
2. update game.
<<<<<<<<<<<<<<<<<< Or here?
3. update music and sound.

Somewhere the program has to continuously check if sprite-0 has been hit and time it sits waiting for sprite-0 to be hit is time it can't spend on other stuff.

Do I understand this correctly?

User avatar
za909
Posts: 211
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Sprite 0 hit, do I understand correctly?

Post by za909 » Sat Aug 08, 2020 9:00 am

Sprite 0 has no associated interrupt. The only thing you can do to run code at the exact time you want with it is if you "lock" the CPU in a loop that checks the flag continuously (called polling) and then exits when it sees that the bit has gone to 1. This means you can not do anything else until the sprite 0 hit occurs. Due to this it is not recommended to use it for a status bar at the bottom of the screen, unless you can make sure that you can place code that can always finish before you start checking for the flag. This way you can still make use of most of the time, and then start polling the flag when screen rendering is somewhere close to the sprite. This requires your code to run in a predictably amount of time, and lag spikes could cause you to start checking too late. In this case the status bar would be displayed somewhere lower and to the right of where you'd want it to be for that frame.

More sophisticated tricks can be done if you can make use of the DMC channel trick and use its IRQ, but then you can't meaningfully use it for audio (not unless you are content with random garbage sound effects like I was).

If you don't want to spend too much time getting it right, it can still be beneficial to run a sample with no sound, then let it trigger an IRQ somewhere close to where the status bar would start, and then you could start polling the sprite 0 flag inside the interrupt. This method would allow you to run any kind of code anywhere because the interrupt would take over when necessary.

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: Sprite 0 hit, do I understand correctly?

Post by klonoa » Mon Aug 10, 2020 1:21 am

Thanks! That pretty much explains everything. :D

User avatar
Gilbert
Posts: 395
Joined: Sun Dec 12, 2010 10:27 pm
Location: Hong Kong
Contact:

Re: Sprite 0 hit, do I understand correctly?

Post by Gilbert » Mon Aug 10, 2020 1:32 am

klonoa wrote:
Sat Aug 08, 2020 8:04 am
I'd place sprite 0 around x0 and y52 so it will set the flag when the beam is around the last 5th of the screen.
Also note that as there are 200+ horizontal lines in a screen, putting sprite 0 at y=52 place it nearer to the top of the screen, rather than around the last 5th of it (note that during render the screen is drawn from the top to the bottom, so higher y-coordinate means closer to the bottom). You should place the sprite at around 160 or lower.

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: Sprite 0 hit, do I understand correctly?

Post by klonoa » Mon Aug 10, 2020 2:29 am

Gilbert wrote:
Mon Aug 10, 2020 1:32 am
klonoa wrote:
Sat Aug 08, 2020 8:04 am
I'd place sprite 0 around x0 and y52 so it will set the flag when the beam is around the last 5th of the screen.
Also note that as there are 200+ horizontal lines in a screen, putting sprite 0 at y=52 place it nearer to the top of the screen, rather than around the last 5th of it (note that during render the screen is drawn from the top to the bottom, so higher y-coordinate means closer to the bottom). You should place the sprite at around 160 or lower.
Woops, I remember I was doubting myself when I was writing that. Should've checked. :roll:

User avatar
za909
Posts: 211
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

Re: Sprite 0 hit, do I understand correctly?

Post by za909 » Tue Aug 11, 2020 5:13 am

You can also use the sprite 0 flag to sync with the end of vblank. If the flag gets set during the frame it is only cleared when vblank is about to end. So once you are ready with everything that must be done during vblank you can start polling the flag again, this time waiting for it to be cleared, and then launch the dpcm sample that will trigger the IRQ close to the sprite 0 hit. There will be up to 4 scanlines of jitter depending on the DMC timing relative to the cpu, but if you make sure to have the IRQ fire early enough you'll catch the sprite 0 flag every time.

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: Sprite 0 hit, do I understand correctly?

Post by klonoa » Mon Aug 17, 2020 10:46 am

za909 wrote:
Sat Aug 08, 2020 9:00 am
Sprite 0 has no associated interrupt. The only thing you can do to run code at the exact time you want with it is if you "lock" the CPU in a loop that checks the flag continuously (called polling) and then exits when it sees that the bit has gone to 1. This means you can not do anything else until the sprite 0 hit occurs. Due to this it is not recommended to use it for a status bar at the bottom of the screen, unless you can make sure that you can place code that can always finish before you start checking for the flag. This way you can still make use of most of the time, and then start polling the flag when screen rendering is somewhere close to the sprite. This requires your code to run in a predictably amount of time, and lag spikes could cause you to start checking too late. In this case the status bar would be displayed somewhere lower and to the right of where you'd want it to be for that frame.

More sophisticated tricks can be done if you can make use of the DMC channel trick and use its IRQ, but then you can't meaningfully use it for audio (not unless you are content with random garbage sound effects like I was).

If you don't want to spend too much time getting it right, it can still be beneficial to run a sample with no sound, then let it trigger an IRQ somewhere close to where the status bar would start, and then you could start polling the sprite 0 flag inside the interrupt. This method would allow you to run any kind of code anywhere because the interrupt would take over when necessary.

Just read up on the dmc trick.
It's pretty incredible how people come up with these tricks!
Definitely helpful because I wasn't planning on using the dmc channel anytime soon anyway. :)

Post Reply