Traditionally, games in BASIC use the keyboard for player input and act accordingly. For eg, the keys Q, A, O and P may be used to move the player character around and M may be used to fire or other action. However, as anyone who has played ‘professional’ games (i.e written using machine code) on the speccy would know, using a joystick is a far better alternative especially in fast action games.
This article will tell you how to use the popular Kempston Joystick in your games for that ‘professional’ touch. 😉
To begin with, inputs from the Kempston Joystick are read via port 31. The Spectrum manual has more information on what a ‘port’ is and so I won’t be covering it here. Suffice to say, any external device connected to the speccy reads through a specific port, numbered 1 to 255. The Kempston Joystick uses port 31.
To read the ‘value’ in port 31 you simply do: LET kj = IN 31. Depending on what state the joystick is in, kj will hold a very specific value that can be interpreted as desired. Now then, the Kempston joystick has only 5 states to deal with, namely ‘Fire’ (any of the fire buttons pressed), ‘Up’ (joystick pulled back), ‘Down’ (joystick pushed forward), ‘Left’ (joystick to the left) and ‘Right’ (joystick to the right).
This information is packed into a single byte in the following format: 000FUDLR. As you can see only the lower 5 bits are of interest to us, which means we can ignore any value of kj above 31. Depending on which bit is set (value of 1) we can assume the joystick is in that state. Multiple states are also possible – firing and moving for example, or moving diagonally for example. Obviously you can’t have states of ‘Up’ & ‘Down’ or ‘Left’ & ‘Right’ occurring simultaneously!
The table of basic values that we need to test is given below:
|kj (IN 31)||Bit pattern (lower 5 bits only)||State|
For the purpose of this tutorial I’m going to ignore multiple directional states because BASIC doesn’t support the kind of bit level manipulation we would like to achieve detection of that. However, it will be useful to detect if we’re firing and moving so that will be on the agenda.
Let’s get the simple detection out of the way first!
10 LET x=10: LET y=10 20 LET kj=IN 31: REM get the state of joystick 30 PRINT AT y,x;"*" 40 IF (kj>31) OR (kj=0) THEN GO TO 20: REM ignore spurious inputs 45 BORDER 1: PRINT AT y,x;" ": REM overwrite at old position 50 IF kj=1 THEN LET x=x+1: REM left 60 IF kj=2 THEN LET x=x-1: REM right 70 IF kj=4 THEN LET y=y+1: REM Down 80 IF kj=8 THEN LET y=y-1: REM Up 90 IF kj=16 THEN BORDER 2: REM Fire 100 GO TO 20
The code is pretty simple. To see it in action we will print an asterisk on the screen that can be moved about by manipulating the joystick. Screen boundaries aren’t checked though to keep the code simple. We’ll also set the border to Red if the fire button is pressed. That’s it really.
To check for the event of fire and moving we’ll have to perform a simple trick. When firing and moving, kj will have bit 5 (for fire) and the bits for movement (any of them from 1 to 4) to be set, leading to a number that is greater than 16 (since fire by alone is itself 16). So all we do then is check for this fact (kj > 16) and if so, note that the fire is being pressed and then subtract 16 from kj so that we can continue to check for the movement keys as normal.
The above code can be modified so (changed lines in blue):
10 LET x=10: LET y=10 20 LET fire=0: LET kj=IN 31: REM note: reset fire event every time! 30 PRINT AT y,x;"*" 40 IF (kj>31) OR (kj=0) THEN GO TO 20 45 BORDER 1: PRINT AT y,x;" " 46 IF kj>16 THEN LET kj=kj-16: LET fire=1: REM Check if firing AND moving 50 IF kj=1 THEN LET x=x+1 60 IF kj=2 THEN LET x=x-1 70 IF kj=4 THEN LET y=y+1 80 IF kj=8 THEN LET y=y-1 90 IF kj=16 OR fire THEN BORDER 2: REM fire by itself or firing and moving? If so red border 100 GO TO 20
That’s about it really. Doing the above in machine code is, in fact, easier because it has all the necessary operators to perform low level bit manipulation which you really need if you want to check for multiple states of the joystick. However, I believe the above will do very nicely for those BASIC games that do not need diagonal movement!
Experiment and enjoy!