I've always wanted a light gun, the closest thing I had to it was a Nintendo Wii controller, but it wasn't quite the same. There's been quite a few light guns produced for different computers over the years, and I thought I would make my own for the ZX Spectrum NEXT. I've recently seen a few games were you have to aim and shoot at baddies, but wouldn't it be great to have something like this for an inexpensive light gun. This project is proof of concept for that, something that will work on different screen types. Games producers typically shy away from things like this, which really is a terrible shame, but their markets are too limited.
I'd like to create a simple game using our home made light gun, I like the idea of defending our planet aginst evil AI alien robots who want to land on our planet and take over our minds.
When I studied computer science all those years ago, I remember covering light pens (same principal more or less), and the electronics are quite straightforward. A simple hack into a joystick port would allow the software to read when the fire trigger is pulled and if the gun is on target from the light sensor.
Software would need to have a way of detecting where on the screen the gun is pointing, and I have some ideas for that, remembering videos I've seen of Duck Hunt, you do see a brief flash on the screen when you shoot, thjs is the detection routine. I also understand that some systems take advantage of timing of the rasterscan to know where in the screen it's being drawn on each frame, corresponding to when the trigger is pulled, avoiding the flash. I don't want to go down that route, and welcome anyone to develop this further allowing for a BASIC call for us more simplistic programmers out there.
The Hardware!
So, let's look inside a Cheetah Light Gun that plugs into a joystick port.
We need a trigger (fire button) and a light sensor at the end of a tube that can detect a relatively small patch of light on the screen. The tube creates focus for the light and reduces stray light. As I happen to have a 3D printer, I'm going to mock something up that can hold the components, but some arts and crafts materials and hot glue could easily help with a prototype.
The Software
I mentioned at the beginning about raster scans: the image on your screen (on an old CRT TV screen) is drawn from little dots plotted left to right, row at a time from top to bottom, and looped back up to the top again. I've heard that modern screens don't work properly with the old tech, I'd imagine that the display doesn't die over each screen update. My approach bypasses this, but may not necessarily be the best method - I just want to see it working.
In our BASIC routine, we'll run a check for the trigger to see if the gun is being shot. If the trigger is pulled, then we'll check if it's pointing at a target. We'll create a procedure to do this, called from our main control loop, passing row and column into the procedure (where our target is on screen), and returning true or false for the result.
So, passing this into the program, we display a target on screen. When we detect a shot fired by the light gun, we'll blank out the screen, and flash a block of white at the co-ordinates where our on-screen target would be. We'll record the result of the light gun's sensor to true or false, and clear the white square ready for next use. We do this blanking, as we don't want to capture a graphic on the screen and mis-identify it as a target.
A good way to flash a block of white on a black screen would be to use layer 1 for this. The screen memory is made up of monochrome pixels that are too small for our purposes, followed by the attribute value blocks (8 x 8 pixel blocks that record paper and ink values). We can POKE the atrribute layer values directly resulting in fast display of the block on and off. If I was to do this on the SAM coupe, I could use a second SCREEN and then swap the screen DISPLAYs over and back again after detection.
On the NEXT, top layers will be turned off for the scan, and switched back on when the scan is complete. I can POKE values into the screen area of memory to change the 8x8 attribute values very quickly. We're going to have a potential grid of 32 columns by 24 rows - That's 728 targets on screen, and more than detailed enough for a responsive game.
Scratchpad
; Check to see if there's a hit at target #1 - Pass the co-ordinates to the checker
proc Target (r,c)
DEFPROC Target (r, c, h); r=row, c=column, h=hit (true of false)