The zapper gun came with many NES consoles. They are pretty common, but you need a CRT TV for them to work. You can also play on most emulators using the mouse to click on the screen (make sure you set the 2nd player input to “zapper”).
It is possible to play a modified game on an non-CRT TV using a Tommee brand Zapp Gun. You would need to add a 3-4 frame delay in the code, since LCD screens typically have 3-4 frames of lag. You couldn’t play the standard Duck Hunt, but some people have been working on modifying zapper games to have a delay before reading the zapper.
Ok, so we’ve all seen Duck Hunt. Do you know how it works?
The game reads the 2nd player port until it gets a signal that the trigger has been pulled. Once that happens, it blacks out the background and replaces 1 object per frame with a big white blob. If there are 2 objects on screen, it will display the first object on 1 frame and the other object on the next frame… to tell which object you hit (if any).
Duck Hunt uses 32×32 pixel box for standard ducks (4 sprites by 4 sprites). Which is about the size you want for a medium level difficulty. Other games had much bigger things to shoot and much bigger white boxes. To vary the difficulty, they would then change the amount of time that the target was on screen.
Duck Hunt used 24×16 pixel box for clay pidgeons. (3 wide by 2 high). Which is kind of difficult to hit. 24×24 is a little more reasonable, and that’s what I used.
I had to write a different controller reading routine, due to the zapper using completely different pins than the standard controllers. I threw in this zaplib.s and zablib.h files.
zap_shoot(1) takes 1 arg, (0 for port 1, 1 for port 2). And, it returns 0 or 1 if it reads the trigger has been pulled.
I also checked to make sure the last frame didn’t also have trigger pulled.
zapper_ready = pad2_zapper^1;
zapper_ready is just the opposite of the last frame. That’s a bitwise XOR, if you’re not familiar with the caret operator “^”.
So when we get that signal, I turn off the BG… ppu_mask(0x16); and draw a white box where the star was… draw_box();
0x16 is 0001 0110 in binary, see the xxxx 0xxx bit is zero. That’s the “show BG” bit. It’s off, but the sprites are still on.
Then immediately, I turn the BG back on, ppu_mask(0x1e); so the flicker is minimized.
0x1e is standard display. 0001 1110 in binary has the xxxx 1xxx bit active again.
And I call zap_read(1) takes 1 arg, (0 for port 1, 1 for port 2).
which is a loop that waits till it either gets a signal that the gun sees white, or that the end of the frame has been reached. It returns 0 for fail and 1 for success.
I tested this on a real CRT on a real NES, and it seems to work fine at 5 ft. This game uses port 2 for the zapper, which is kind of standard. But, you could make a game that uses port 1, if you wanted to. zaplib.s will have to be included in crt0.s and zaplib.h will have to be included in your main c file.
If you want the game to run on a Famicom, you should put the zapper reads on port 2. The zapper will have to be plugged into the expansion port which is read from port 2.
Also see the wiki for more technical info.
The Power Pad is a little less standard. There weren’t many games that used it. Just like the zapper, the Power Pad uses different pins than the standard controller, so I had to rewrite the code that reads the input. See padlib.s and padlib.h.
read_powerpad(1) takes 1 arg, 0 for port 1, 1 for port 2.
And, it returns a 2 byte value (unsigned int). And I made these contants to represent each foot pad.
#define POWERPAD_4 0x8000
#define POWERPAD_2 0x4000
#define POWERPAD_3 0x2000
#define POWERPAD_1 0x1000
#define POWERPAD_12 0x0800
#define POWERPAD_5 0x0400
#define POWERPAD_8 0x0200
#define POWERPAD_9 0x0100
#define POWERPAD_6 0x0040
#define POWERPAD_10 0x0010
#define POWERPAD_11 0x0004
#define POWERPAD_7 0x0001
padlib.s will have to be included in crt0.s and padlib.h will have to be included in your main c file. This was tested on a real Power Pad on a real NES.
If you want the game to run on a Famicom, you should put the power pad reads on port 2. The power pad will have to be plugged into the expansion port which is read from port 2.
Also see the wiki for more technical info.