Click here if you are stuck in someone else's frames.


If this page looks like garbage then you need one of these browsers...

Microsoft Internet Explorer

Netscape Navigator

Please sign my programmer's page guestbook.

Please sign my guestbook

View my guestbook entries

Communicating with Devices in BASIC


In order to control the action of our video games, we must be able understand the input devices used and how to communicate with them in order for us to make any real use out of them for our video games. On the PC, we essientally have a choice of 3 different input devices for use with games: the keyboard, the joystick, and the mouse.

Of the three devices, the keyboard is perhaps the single most popular device used, simply because it is the most widely available, with the mouse coming next and finally the joystick. First let's start off with the most popular of the three devices in use for video games, the joystick.


Reading the Joystick Ports

The joystick(s) on the PC is an analog device, meaning that instead of of simply registering an on off state when the joystick is moved to any of the eight directions, it instead measures how far the joystick is moved in any direction and that measurement is returned to the software. Analog joysticks have many advantages over their digital counterparts by allowing the software to track the full range of motion of the actual stick itself instead of just simply knowing that it is held in one of the eight directions.

To read these joystick positions, we can use one of three methods, each of which is more reliable than others and more easy to implement. Let's take a look at what we can use:

Using QBasic's STICK function

This has got to be the easiest and the most recommended method that I know if you're programming in QBasic or QuickBASIC. Just call the function with the appropriate axis and it returns the current position of that axis. If your version of BASIC has a similar function, I would highly recommend that you use it. The language hides all the details behind reading the port and provides an easy to use interface.

A brief explanation of QBasic's joystick functions

I will go over breifly how you can use the functions in QBasic to read the joystick ports. To read the horizontal axis of the left joystick, just pass zero as a parameter to the STICK function.

LeftHorizPos = STICK(0)
PRINT "Horizontal position of the left joystick ="; LeftHorizPos
    

QBasic also supplies a set of functions that read the joystick buttons called the STRIG functions. I will not go into too much detail on how to use these functions since you can read all about them in the QBasic online help. Let's move on to other ways to read the joysticks ports.


If you are using QBasic, you will find that you cannot call interrupts like those who use QuickBASIC can. For you, you should download this BASIC file that emulates QuickBasic's CALL INTERRUPT function. You will need this file in order to add mouse support to your programs. Thanks to Hans Lunseng.

Using BIOS to retrieve info from the joysticks.

The BIOS allows for us to read both the joystick button states and the current position of the joystick pots (potentiometers used in the joystick hardware). The BIOS contains two seperate functions that can be called at interrupt 15h. To use them, we must set register AH to the value of 84h which tells the BIOS that we are interested in communicating with the joystick. The we load register DX with either 00h (to read the button states) or 01h (to read the joystick pot values). After that just make a call to INT 15h and we're done.

A quick look at the code involved in using the BIOS.

' This code will read the joystick ports
' and button status using an interrupt
' call to the BIOS at INT 15h.

' This program was written using QuickBASIC 4.5

'$INCLUDE: 'QB.BI'

DIM regs AS RegType

' Clear keyboard
WHILE INKEY$ <> "": WEND

' Escape key ends the program
DO UNTIL INKEY$ = CHR$(27)
    regs.AX = &H8400    ' Joystick support
    regs.DX = 0         ' read joystick buttons
    CALL INTERRUPT(&H15, regs, regs)

    LOCATE 1, 1

    IF (regs.AX AND &H10) THEN
        PRINT SPACE$(35)
    ELSE
        PRINT "Joystick 1, first button pressed."
    END IF

    IF (regs.AX AND &H20) THEN
        PRINT SPACE$(35)
    ELSE
        PRINT "Joystick 1, second button pressed."
    END IF

    IF (regs.AX AND &H40) THEN
        PRINT SPACE$(35)
    ELSE
        PRINT "Joystick 2, first button pressed."
    END IF

    IF (regs.AX AND &H80) THEN
        PRINT SPACE$(35)
    ELSE
        PRINT "Joystick 2, second button pressed."
    END IF


    regs.AX = &H8400    ' Joystick support
    regs.DX = 1         ' read joystick pots
    CALL INTERRUPT(&H15, regs, regs)

    LOCATE 11, 1

    PRINT "Joystick 1 x-axis:"; regs.AX
    PRINT "Joystick 1 y-axis:"; regs.BX
    PRINT "Joystick 2 x-axis:"; regs.CX
    PRINT "Joystick 2 y-axis:"; regs.DX
LOOP
END
    

Communicate directly with the joystick

The last method of of reading the joystick pots is to communicate to the joystick directly. This is not recommended in BASIC since it requires that we disable hardware interrupts (to get an accurate reading) which is beyond BASIC's capability. For QBasic (QuickBASIC) user's, I would recommend that you stick with STICK and STRIG functions. If your version of basic does not have any functions at all to communicate with the joystick, then you may be able to do so with the BIOS. Outside of that, it takes an assembly call to accurately measure the values of the joystick pots. Visit the C programming page for more info on how to communicate directly with the joystick hardware.


Translating the coordinates

Whatever way you use to retrieve the joystick coordinates, you must then translate the coordinates into actions for your games. Generally whatever direction you deflect the joystick yoke, you want your game character to move in that direction. This is fairly easy to do and requires just a couple of lines of code to translate.

Assuming that we've calibrated our joystick already...what? You haven't done this yet??? Well, guess we better get to that part first. There are various methods for calibrating a joystick for use in a game. Many games ask the user to move the joystick to the upper left and lower right corners and press the button. Others assume that the joystick is centered and calibrate the lower right to be twice the center coordinates. The method I prefer is the one that asks the user to move the joystick and press it's buttons. It may not be the most elegant, but it does ensure the most accurate calibration, assuming of course the user can follow instructions ;) .

' This code snippet prompts the user to move
' the joystick in the upper left and lower right
' positions to calibrate the joystick.
'

PRINT : PRINT "Press [ESC] to exit"
PRINT "Move joystick to upper left, and press fire: ";
DO
    IF INKEY$ = CHR$(27) THEN EXIT DO
    ' Get current minimum joystick coordinates
    Joy1MinX = STICK(0)
    Joy1MinY = STICK(1)
LOOP UNTIL STRIG(0) OR STRIG(2)
PRINT "OK"

' Wait till user releases joystick buttons
WHILE STRIG(0) OR STRIG(2): WEND

PRINT "Move joystick to lower right, and press fire: ";
DO
    IF INKEY$ = CHR$(27) THEN EXIT DO
    ' Get current maximum joystick coordinates
    Joy1MaxX = STICK(0)
    Joy1MaxY = STICK(1)
LOOP UNTIL STRIG(0) OR STRIG(2)
PRINT "OK"
    

Of course I don't think I need to tell you this, but just in case, this code works for joystick one. If you want to calibrate a second joytsick just change the STICK arguments from 0 and 1 to 2 and 3 respectively and the STRIG arguments from 0 and 2 to 4 and 6 respectively.

Please note: If you change the STICK arguments to read joystick's 2 coordinates you must add an extra line in both of the DO...LOOPs that read STICK(0)s coordinate or else this code will not work properly.

Now for a little code that translates the deflection of the joystick yoke into a direction for your game character.

' Translating the deflection into a direction
' It's as easy as it looks...

SELECT CASE STICK(0)
CASE IS < Joy1MinX + 15
    XDirection = -1
CASE IS > Joy1MaxX - 15
    XDirection = 1
CASE ELSE
    XDirection = 0
END SELECT

SELECT CASE STICK(1)
CASE IS < Joy1MinY + 15
    YDirection = -1
CASE IS > Joy1MaxY - 15
    YDirection = 1
CASE ELSE
    YDirection = 0
END SELECT

' Code to erase game character here

XPosition = XPosition + XDirection
YPosition = YPosition + YDirection

' Code to redisplay game character here
    

This to me is the most simplest and fastest method to read and translate joystick coordinates for most games that we plan to write, feel free to experiment and try whatever you like.


Send your questions, comments, or ideas to: wilkeg@gamewood.net

This page hosted by GeoCities Get your own Free Home Page
Next Back |