Zapper hit detection

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

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Zapper hit detection

Post by Dafydd » Sat Mar 02, 2013 9:11 am

In my game, I'm only going to have 1 target at any time, so I just want to know whether I found a hit or not.

If I've understood this correctly, it's not enough to just read from the zapper - it needs to be done while the frame is being drawn, because the light sensor turns off after a very short time compared to my eyes, which perceive the white area on the screen as being constantly white.

So how do I do this? One idea was to poll $2002 for vblank to end and then have a loop that polls $2002 for vblank to start and $4017 for a hit, or that polls just $4017 while waiting for nmi... how would you more experienced people do it?

Also, are there other light sources I could use, for debugging and such? What kind of light, specifically, does the zapper detect?

tepples
Posts: 22014
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Zapper hit detection

Post by tepples » Sat Mar 02, 2013 11:10 am

Dafydd wrote:One idea was to poll $2002 for vblank to end and then have a loop that polls $2002 for vblank to start and $4017 for a hit, or that polls just $4017 while waiting for nmi... how would you more experienced people do it?
What I did in Zap Ruder was set up sprite 0 at the top of the screen, wait for the sprite 0 hit (0 then 1 on $2002 bit 6), and use the "zapkernels" (subroutines that I wrote using timed code to read $4017 once each scanline, whose source code is included with Zap Ruder) to wait up to 192 scanlines for light to be detected. If you just want a Y coordinate (as used in ZapPing), you can leave the whole screen bright and count scanlines.

Otherwise, darken the screen except for the targets and use the Y coordinate to narrow down which target was hit. If this Y coordinate is close to more than one target (not the case in 1 DUCK, but possible for 2 DUCKS or CLAY SHOOTING), turn each on individually. The Zap Ruder menu has two target groups: the boxes on the left and the boxes on the right. When the photodiode turns on, it darkens the groups in sequence over the course of the next two frames and moves the cursor to that group if darkening the group caused the photodiode to turn off.

In my experience, the Zapper's photodiode will turn on reliably when the color in the target area is $10 (light gray), $20-$2C (white and bright colors), or $30-$3C (white and pale colors). It's still unclear whether or not the IC in the Zapper includes a resonator at 15.7 kHz (SDTV horizontal scan rate) to distinguish TV light from other light sources.

lidnariq
Posts: 9494
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Zapper hit detection

Post by lidnariq » Sat Mar 02, 2013 2:01 pm

tepples wrote:It's still unclear whether or not the IC in the Zapper includes a resonator at 15.7 kHz (SDTV horizontal scan rate) to distinguish TV light from other light sources.
The IC used in the zapper is identical in functionality to a standard infrared remote demodulator IC; the selective frequency has been changed and the normally-IR photodiode has been replaced with a visible light one. I suppose I should sit down and build a testing rig to characterize the behavior.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Sun Mar 03, 2013 5:23 pm

So... if I point the thing at the sun, it should register a hit, right? Why does a lightbulb, or anything that shines a white light, not do the trick? It doesn't react to just ANY visible light, does it?

(I should clarify I do know about the blank screens drawn before and after the frames that draw white hitboxes to prevent cheating)

tepples
Posts: 22014
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Zapper hit detection

Post by tepples » Sun Mar 03, 2013 6:05 pm

Light from a CRT SDTV turns on and off about 15,700 times a second. Light from a light bulb or the sun does not. The Zapper's demodulator IC detects the difference.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Mon Mar 04, 2013 12:38 pm

Ah, so it's not the frequency of the light, but the frequency at which it flashes. Got it.

Well, I made a screen where the upper quarter is in all white and the rest in all black, save for a message that is printed differently depending on whether you are aiming at white or not, and depending on whether the trigger is pulled. It does, however, not react to ANYTHING I do to it - pulling the trigger, aiming the zapper at the TV or elsewhere, into a pillow while pressing the trigger... nothing happens. It's just stuck displaying HIT. What am I doing wrong?

Code: Select all

wait_for_hit_and_vblank:
	lda #$08
	cmp $4017 ; set Z if A == $08, i.e. if $4017.3 is 1,
			  ; i.e. light sense: not detected
	bne wait_for_just_vblank ; if Z is not set: light detected!
	lda #$10
	cmp $4017 ; set Z if A == $10, i.e. if $4017.4 is 1,
			  ; i.e. trigger is pulled
	beq wait_for_just_vblank ; if Z is set: trigger pulled!
	
	bit $2002
	bpl wait_for_hit_and_vblank ; still no hit registered, wait some more
	
	; we're now in vblank with no hit or trigger pull registered. Display MISS
	lda $2002
	lda #$22
	sta $2006
	lda #$2E
	sta $2006
	lda #$4D ; M
	sta $2007
	lda #$49 ; I
	sta $2007
	lda #$53 ; S
	sta $2007
	sta $2007
	jmp set_scroll

; we're still not in vblank, so wait for it...	
wait_for_just_vblank:
	bit $2002
	bpl wait_for_just_vblank
	
	; we're now in vblank with either a hit or a pulled trigger. Display HIT 
	lda $2002
	lda #$22
	sta $2006
	lda #$2E
	sta $2006
	lda #$48 ; H
	sta $2007
	lda #$49 ; I
	sta $2007
	lda #$54 ; T
	sta $2007

set_scroll:
	lda #$00
	sta $2000
	sta $2005
	sta $2005

	jmp wait_for_hit_and_vblank

3gengames
Formerly 65024U
Posts: 2276
Joined: Sat Mar 27, 2010 12:57 pm

Re: Zapper hit detection

Post by 3gengames » Mon Mar 04, 2013 12:50 pm

You use bad programming, which is why. Here's the explaination:

Code: Select all

   lda #$08
   cmp $4017 ; set Z if A == $08, i.e. if $4017.3 is 1,
           ; i.e. light sense: not detected
   bne wait_for_just_vblank ; if Z is not set: light detected!
   lda #$10
   cmp $4017 ; set Z if A == $10, i.e. if $4017.4 is 1,
           ; i.e. trigger is pulled
   bne wait_for_just_vblank ; if Z is set: trigger is pulled!
$4017 return what it's supposed to OR'd with $40 because of open bus. AND other bits can be set, too. To get the bits you need the right way, use LDA+BIT or LDA+AND.

Code: Select all

   lda #$08
   bit $4017 ; set Z if A == $08, i.e. if $4017.3 is 1,
           ; i.e. light sense: not detected
   bne wait_for_just_vblank ; if Z is not set: light detected!
   lda #$10
   bit $4017 ; set Z if A == $10, i.e. if $4017.4 is 1,
           ; i.e. trigger is pulled
   bne wait_for_just_vblank ; if Z is set: trigger is pulled!

Code: Select all

   lda $4017
   and #$08 ; set Z if A == $08, i.e. if $4017.3 is 1,
           ; i.e. light sense: not detected
   bne wait_for_just_vblank ; if Z is not set: light detected!
   lda $4017
   and #$10 ; set Z if A == $10, i.e. if $4017.4 is 1,
           ; i.e. trigger is pulled
   bne wait_for_just_vblank ; if Z is set: trigger is pulled!
And on a side note, if you are not using pre-defined labels for the NES hardware, I'd say start doing that as looking at text is easier then looking at a bunch of numbers, especially when you do a ton of hardware interaction as remembering the registers is a waste of time to just having exactly what you're modifying in the name.
Last edited by 3gengames on Mon Mar 04, 2013 1:20 pm, edited 1 time in total.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Mon Mar 04, 2013 1:17 pm

3gengames wrote:You use bad programming, which is why.
Fair enough...

Unfortunately, your code doesn't work either.

tepples
Posts: 22014
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Zapper hit detection

Post by tepples » Mon Mar 04, 2013 2:46 pm

In case you missed it the first time: Zap Ruder includes working code for Zapper polling that you are free to use in your own game.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Mon Mar 04, 2013 3:02 pm

I should have thanked you the first time :) I had a look at it, and I don't really see what I'm doing differently from you (besides the obvious, what with the timed code and all). I have to say, I'm very impressed by the accuracy you've achieved. However, copy+pasting someone else's code wholesale kind of defeats the whole point of why I'm doing this in the first place, and this is way too advanced for me right now (it's also NTSC specific). I only have 1 target on the screen, so the code would be very simple, but I want to understand what I'm doing.

... um. Ok, I changed

Code: Select all

  lda $4017
  and #$08
  beq wait_for_just_vblank
for

Code: Select all

  lda #$08
  and $4017
  beq wait_for_just_vblank
(as per zapkernel's example) and now it works. Also

Code: Select all

  lda #$10
  and $4017
  bne wait_for_just_vblank
works for trigger detection.

So close, 3gengames! :lol: I still don't know why this works and the other way didn't, but I'm going to find out.

Thanks again, tepples! Or, um, both of you, actually :)
Last edited by Dafydd on Mon Mar 04, 2013 5:54 pm, edited 1 time in total.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Mon Mar 04, 2013 3:25 pm

Umm... nope. Changed it back, still works. I think it was a misuse of beq and bne that did it. ...somehow. Here's some code that works, anyway. Maybe something similar should be on the wiki for noobs like me?

Code: Select all

lda #$08; 00001000
and $4017; ????1??? <- miss
; result: A=00001000, Z=0
beq hit_reported; results in no branch because Z=0

lda #$08; 00001000
and $4017; ????0??? <- hit
; result: A=00000000, Z=1
beq hit_reported; results in branch because Z=1

lda #$10; 00010000
and $4017; ???1???? <- trigger
; result: A=00001000, Z=0
bne trigger_pulled; results in branch because Z=0

lda #$10; 00010000
and $4017; ???0???? <- no trigger
; result: A=00000000, Z=1
bne trigger_pulled; results in no branch because Z=1
Last edited by Dafydd on Mon Mar 04, 2013 5:49 pm, edited 2 times in total.

User avatar
Quietust
Posts: 1566
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: Zapper hit detection

Post by Quietust » Mon Mar 04, 2013 3:37 pm

tepples wrote:It's still unclear whether or not the IC in the Zapper includes a resonator at 15.7 kHz (SDTV horizontal scan rate) to distinguish TV light from other light sources.
It's my recollection that it's not the IC itself but a capacitor or resistor elsewhere in the circuit - I recall somebody replacing it in order to make their zapper sensitive to 31.5kHz and work properly with scan-doubled NTSC (in fact, I think it may have been kevtris back when he first made his FPGA console).
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

lidnariq
Posts: 9494
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Zapper hit detection

Post by lidnariq » Mon Mar 04, 2013 6:15 pm

The RC pair off pin 3 (22Ω + 1µF) has a corner frequency of hsync rate÷2. This probably determines the bandwidth of the filter, i.e. the number of scanlines necessary to count.
Assuming that the mechanism of the IR3T07 is similar to the contemporary CX20106 or its equivalent GL3274, the 390KΩ resistor should be what determines the scanrate.

Amusing piece of trivia: The reason that the trigger is "true" for ≈6 vblanks is because that's approximately 10kΩ (the pullup inside the console) × 10µF (the capacitor inside the zapper) = 0.1s

tepples
Posts: 22014
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Zapper hit detection

Post by tepples » Mon Mar 04, 2013 6:54 pm

lidnariq wrote:Amusing piece of trivia: The reason that the trigger is "true" for ≈6 vblanks is because that's approximately 10kΩ (the pullup inside the console) × 10µF (the capacitor inside the zapper) = 0.1s
On an unmodified Zapper, I can hold the trigger halfway in and keep it true indefinitely. One activity in Zap Ruder relies on this to change the instrument's timbre.

User avatar
Dafydd
Posts: 114
Joined: Sun Mar 16, 2008 1:45 am
Location: Uppsala, Sweden

Re: Zapper hit detection

Post by Dafydd » Tue Mar 05, 2013 10:48 am

Hmm,
http://en.wikipedia.org/wiki/NES_Zapper#History_and_usage wrote:A known glitch about the zapper is you can get a perfect hit score every time in some poorly programmed games by simply pointing the gun right next to and into a light bulb.
This didn't work for me, anyway. Did they just make that up, or are there light bulbs that flash with the same frequency as CRT monitors?

But then again,
Image

Post Reply