Controller Library - TerryRitchie - 04-12-2023
------------------------------------------------------
05/17/23 - UPDATE
Version 1.10 is now available (code below updated as well as attached ZIP file)
NOTE: This library will now require QB64PE version 3.7.0 and above.
This version now adds the following capabilities:
- Save and load user defined buttons ( __LOAD_BUTTONS, __SAVE_BUTTONS )
- The ability to detect new controllers plugged and existing controllers unplugged/plugged back in ( __NEW_CONTROLLER, __CONNECTED )
- Remove all controller associated user defined buttons ( __REMOVE_CONTROLLER )
- Prior versions automatically created buttons based on integer variables. A change was needed to facilitate the loading of saved button configurations.
__MAKE_BUTTON is now required to initialize user defined buttons (see documentation in CONTROLLER.BI for more info).
------------------------------------------------------
I wrote a controller library for use with the keyboard, mouse, and joysticks / game pads.
The first code is CONTROLLER.BI to be placed at the top of your code. It also contains the library documentation.
The second code is CONTROLLER.BM to be placed at the bottom of your code.
The next three pieces of code are examples showing the use of the library. A ZIP file is also attached that contains all the code as well. A fourth demo named "Configure_Buttons.BAS" is also included that is a mini-game that highlights all the features of the library.
Give it a whirl and let me know if you find any bugs or changes that I should make to the library. I have not incorporated WHEEL routines yet. Having a bit of an issue getting WHEEL functions to work properly.
Code: (Select All) '----------------------------
' Controller Library V1.10
' Terry Ritchie
' May 17th, 2023
' Written using QB64PE v3.7.0
'----------------------------
' CONTROLLER.BI
'----------------------------
'
' TODO: Add WHEEL routines
' Create PDF instructions
'
'----------------------------
' 04/10/23 V1.0 - Initial Release
' 04/26/23 V1.01 - Corrected slot reassigning issues
' 05/17/23 V1.10 - Added __MAKE_BUTTON, __CONNECTED, __SAVE_BUTTONS, __LOAD_BUTTONS, __NEW_CONTROLLER, __REMOVE_CONTROLLER
' - The library now has the ability to save and load controller user defined button configurations
' - You can now detect when a controller has been plugged in or unplugged
' - A controller's user defined button assignments can be removed when the controller has been unplugged
'----------------------------
' +---------------------------------------+
' | |
' | HOW QB64 HANDLES CONTROLLERS |
' | |
' +---------------------------------------+
'
' QB64's controller commands work by identifying the connected controllers at program start up using _DEVICES. This list of identified controllers can
' only be added to during program execution. If a controller is unplugged the controller's id number is not removed from the list. Instead, the
' controller will be listed as [DISCONNECTED] through _DEVICE$. When the controller is plugged back in the [DISCONNECTED] will be removed from the
' controller's identifying string returned by _DEVICE$.
'
' This library will support up to six controllers (see the list below in "INITIALIZING THE LIBRARY") connected at one time. The behavior above will only
' become an issue if your user, for whatever reason, has plugged in, and then unplugged, so many controllers that the device list contains all
' [DISCONNECTED] controllers and a new controller plugged in occupies id #7. That controller will not be detected, only the previous controllers the
' user plugged in. This scenario is highly unlikely but, users being users, it may happen. You can test for this condition by checking if _DEVICES is
' ever greater than 6.
' +---------------------------------------+
' | |
' | INITIALIZING THE LIBRARY |
' | |
' +---------------------------------------+
'
' The first subroutine that MUST be called is __INITIALIZE_CONTROLLERS. This subroutine initializes all the associated controller variables and
' identifies all connected controllers. Up to 6 total controllers can be detected and used:
'
' - 1 keyboard, 1 mouse, and 4 joysticks/game pads
' - 1 leyboard, no mouse, and 5 joysticks/game pads
' - no keyboard, 1 mouse, and 5 joysticks/game pads
' - no keyboard, no mouse, and 6 joysticks/game pads
'
' Once the connected controllers have been identified the following shared integers will be set with controller ID numbers:
'
' __KEYBOARDCID Always a value of 1 when a keyboard is detected
' __MOUSECID Always a value of 2 if a keyboard is also present, 1 if no keyboard detected
' __JOYPAD1CID The first joystick/game pad detected. Always a value of 3 if a keyboard and mouse present, 1 or 2 otherwise
' __JOYPAD2CID The second joystick/game pad detected. Always a value of 4 if a keyboard and mouse present, 2 or 3 otherwise
' __JOYPAD3CID The third joystick/game pad detected. Always a value of 5 if a keyboard and mouse present, 3 or 4 otherwise
' __JOYPAD4CID The fourth joystick/game pad detected. Always a value of 6 if a keyboard and mouse present, 4 or 5 otherwise
' __JOYPAD5CID The fifth joystick/game pad detected. ALWAYS A VALUE OF 5. Will only be detected if a keyboard or mouse is NOT present
' __JOYPAD6CID The sixth joystick/game pad detected. ALWAYS A VALUE OF 6. Will only be detected if a keyboard and mouse are NOT present
'
' NOTE: If a certain controller is not found, for instance a mouse, then the corresponding variable will contain 0 (__MOUSECID = 0)
'
' These variables are now to be used to indentify the controller you wish to interact with. If a variable contains a value other than 0 the controller
' exists and will continue to exist until program termination.
' +---------------------------------------+
' | |
' | REDETECING CONTROLLERS |
' | |
' +---------------------------------------+
'
' If at any time you wish to rescan for currently connected controllers you can use this subroutine:
'
' __IDENTIFY_CONTROLLERS
'
' However, you'll more than likely never need to use this subroutine. The library is designed to automatically use __IDENTIFY_CONTROLLERS when a
' change in controller status occurs, such as a new controller plugged in, an existing controller unplugged, or an existing controller plugged back in.
' __INITIALIZE_CONTROLLERS automatically calls this subroutine as well.
' +---------------------------------------+
' | |
' | GET EXISTING CONTROLLERS |
' | |
' +---------------------------------------+
'
' The following functions can be used to determine the number and type of controllers found:
'
' __KEYBOARD_EXISTS - determine if a keyboard controller was found, -1 (TRUE) or 0 (FALSE)
' __MOUSE_EXISTS - determine if a mouse controller was found, -1 (TRUE) or 0 (FALSE)
' __JOYPAD_EXISTS(Number) - determine if a joystick/game pad was found
' Number = the desired joystick/game pad to query (1 to 6)
' If the numbered game pad was found __JOYPAD_EXISTS returns the TOTAL NUMBER of joysticks/game pads found.
'
' Example:
'
' IF __KEYBOARD_EXISTS THEN PRINT "Found!" ' was keyboard controller found?
' IF __MOUSE_EXISTS THEN PRINT "Found!" ' was mouse controller found?
' NumberOfJoypads = __JOYPAD_EXISTS(__JOYPAD1CID) ' query to determine if at least one joystick/game pad found
' IF NumberOfJoypads THEN ' at least 1 joystick found?
' PRINT "Joystick 1 found!" ' yes, display result
' PRINT "Total number of joysticks/game pads:"; NumberOfJoypads
' END IF
' +---------------------------------------+
' | |
' | GET CONTROLLER PROPERTIES |
' | |
' +---------------------------------------+
'
' The following functions can be used to query each controller for information:
'
' __CONTROLLER_NAME$(cid) - the descriptive name of the controller
' __BUTTON_TOTAL(cid) - the number of buttons a controller has
' __AXIS_TOTAL(cid) - the number of axes a controller has
'
' Example:
'
' IF __JOYPAD1CID THEN ' or "IF __JOYPAD_EXISTS(1) THEN" would work as well
' PRINT "Joystick 1 name : "; __CONTROLLER_NAME$(__JOYPAD1CID)
' PRINT "Buttons available:"; __BUTTON_TOTAL(__JOYPAD1CID)
' PRINT "Axes available :"; __AXIS_TOTAL(__JOYPAD1CID)
' END IF
' +---------------------------------------+
' | |
' | QUERY CONTROLLER DIRECTLY |
' | |
' +---------------------------------------+
'
' The following function can be used to determine if a controller is plugged in or unplugged:
'
' __CONNECTED(cid)
'
' The function will return a value of -1 (TRUE) if the controller is plugged in and 0 (FALSE) if the controller in unplugged.
'
' Example:
'
' IF __JOYPAD2CID THEN ' was joystick 2 detected at program startup?
' IF __CONNECTED(__JOYPAD2CID) THEN ' yes, is joystick 2 currently connected?
' PRINT "Joystick 2 found and currently connected." ' yes, inform user
' ELSE ' no, joystick 2 has been unplugged
' PRINT "Joystick 2 is currently unplugged." ' inform user
' END IF
' END IF
'
' The following functions can be used to query buttons and axes directly from a controller:
'
' __CONTROLLER_BUTTON(cid, Button)
' __CONTROLLER_AXIS(cid, Axis)
'
' Example:
'
' IF __CONTROLLER_BUTTON(__JOYPAD1CID, 1) THEN ' is joystick button one down?
' PRINT "Joystick button #1 pressed!" ' yes, report findings
' END IF
' IF __CONROLLER_BUTTON(__KEYBOARDCID, CLKEY_UP) THEN ' is keyboard UP ARROW key down?
' PRINT "Keyboard UP ARROW key pressed!" ' yes, report findings
' END IF
' VerticalAxis = __CONTROLLER_AXIS(__JOYPAD1CID, 1) ' get current vertical axis of joystick/game pad 1
' +---------------------------------------+
' | |
' | RETRIEVING CONTROLLER EVENTS |
' | |
' +---------------------------------------+
'
' The __NEW_CONTROLLER function is used to identify when a new controller has been plugged in, and existing controller has been unplugged, or an
' existing controller has been plugged back in:
'
' Controller = __NEW_CONTROLLER(Event)
'
' Event will contain the controller event that was detected (if any):
'
' 0 - no events occurred
' 1 - an existing controller was unplugged (the constant __UNPLUGGED can be used to check for this event)
' 2 - an existing controller was plugged back in (the constant __PLUGGEDIN can be used to check for this event)
' 3 - a new controller has been plugged in (the constant __NEWCONTROLLER can be used to check for this event)
'
' The function will return the following values:
'
' - a value of 0 (FALSE) if nothing has changed
' - the value will contain the new controller id when a new controller is plugged in (Event = 3 )
' - the value will contain the controller id of a controller that was unplugged or plugged back in (Event = 1 or 2)
'
' Example:
'
' Controller = __NEW_CONTROLLER(Event) ' check for a controller event
' IF Controller THEN ' has a controller event ocurred?
' SELECT CASE Event ' yes, what happened?
' CASE __NEW_CONTROLLER ' a new controller was plugged in
' PRINT "A new controller with the id of"; Controller; "has been plugged in."
' CASE __PLUGGEDIN ' an existing controller was plugged back in
' PRINT "Controller id"; Controller; "has been plugged back in."
' CASE __UNPLUGGED ' an existing controller was unplugged
' PRINT "Controller id"; Controller; "has been unplugged."
' END SELECT
' END IF
'
' During game play there is no need to constantly check for controller events. Inside the main game loop during game play a check once per second
' will be more than enough. See the example program named "Configure_buttons.BAS" for a demonstration of this in action.
' +---------------------------------------+
' | |
' | CREATING USER DEFINED BUTTONS |
' | |
' +---------------------------------------+
'
' A user defined button can have up to 4 buttons or axes from various controllers associated with it. First, create an integer handle for each user
' defined button:
'
' DIM UP_Button AS INTEGER ' user defined button handles with up to four associated controller buttons and/or axes
' DIM DOWN_Button AS INTEGER
' DIM LEFT_Button AS INTEGER
' DIM RIGHT_Button AS INTEGER
'
' Next, the variables must be identified as user defined buttons using the __MAKE_BUTTON subroutine:
'
' __MAKE_BUTTON UP_Button ' __MAKE_BUTTON statement added with version 1.10
' __MAKE_BUTTON DOWN_Button ' __MAKE_BUTTON must be used with versions 1.10 and above
' __MAKE_BUTTOn LEFT_Button
' __MAKE_BUTTON RIGHT_Button
'
' The following subroutines allow for assigning a controller button and/or axes directly to a user defined button:
'
' __ASSIGN_BUTTON(Handle, cid, Button)
' __ASSIGN_AXIS(Handle, cid, Axis)
'
' Example:
'
' __ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_UP ' keyboard UP ARROW key assigned to UP_Button [SLOT1]
' __ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_W ' Keyboard W key also assigned to UP_Button [SLOT2]
' __ASSIGN_AXIS UP_Button, __JOYPAD1CID, -2 ' joystick vertical axis UP (-) also assigned to UP_Button [SLOT3]
' __ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_DOWN ' keyboard DOWN ARROW key assigned to DOWN_Button [SLOT1]
' __ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_S ' keyboard S key also assigned to DOWN_Button [SLOT2]
' __ASSIGN_AXIS DOWN_Button, __JOYPAD1CID, 2 ' joystick vertical axis DOWN (+) also assigned to DOWN_Button [SLOT3]
' __ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_LEFT ' keyboard LEFT ARROW key assigned to LEFT_Button [SLOT1]
' __ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_A ' keyboard A key also assigned to LEFT_Button [SLOT2]
' __ASSIGN_AXIS LEFT_Button, __JOYPAD1CID, -1 ' joystick horizontal axis LEFT (-) also assigned to LEFT_Button [SLOT3]
' __ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_RIGHT ' keyboard RIGHT ARROW key assigned to RIGHT_Button [SLOT1]
' __ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_D ' keyboard D key also assigned to RIGHT_Button [SLOT2]
' __ASSIGN_AXIS RIGHT_Button, __JOYPAD1CID, 1 ' joystick horizontal axis RIGHT (+) also asigned to RIGHT_Button [SLOT3]
'
' The above example now gives the player the option of using the keyboard ARROW keys, WASD keys, or the joystick to move in all four directions.
' Each of the above user defined buttons still have one slot remaining [SLOT4] and it could be populated with another joystick axis or perhaps
' the keyboard NUMBER PAD arrow keys if you wish.
'
' Joystick and game pad axis directions are defined with positive and negative values. A negative axis value either means UP or LEFT and a positive
' axis value either means DOWN or RIGHT depending on the axis being assigned. Axis deflections are detected when the axis is 50% or greater in
' deflection in a given direction. Top hats and D-Pads typically return a vale of -1 (-100%) or 1 (100%) while analog joystick inputs will change
' from -1 to 1 with a range of values in between. Analog joystick axes will register as a button press when they are deflected -.5 (-50%) to
' .5 (+50%) in either direction. (This .5 value can be changed using __SET_AXIS_THRESHOLD to suit your needs)
' +---------------------------------------+
' | |
' | SETTING AXIS THRESHOLD SENSITIVITY |
' | |
' +---------------------------------------+
'
' When using an axis as a button a certain axis deflection must be reached before the axis is considered "pressed". By default a joystick or game pad
' axis must be deflected at least 50% to reach this threshold. The following function can be used to change the threshold sensitivity amount:
'
' __SET_AXIS_THRESHOLD(Value)
'
' Example:
'
' __SET_AXIS_THRESHOLD .25 ' set axis button sensitivity to 25% deflection.
'
' Value can be any number from .01 (1%) to .99 (99%).
' +---------------------------------------+
' | |
' | DETECTING A USER DEFINED BUTTON PRESS |
' | |
' +---------------------------------------+
'
' The following function can be used to test if a user defined button is being pressed:
'
' __BUTTON_DOWN(Handle)
'
' Example:
'
' IF __BUTTON_DOWN(UP_Button) THEN
' PRINT "Either the keyboard UP ARROW or W key was pressed or joystick 1 was pushed or pressed UP."
' END IF
' +---------------------------------------+
' | |
' | AUTO-ASSIGNING USER DEFINED BUTTONS |
' | |
' +---------------------------------------+
'
' Because of the wide variety of joytick and game pad controllers a user may connect it may be best to have the user define the keys, buttons, and
' axes they wish to use. The following subroutine can be used to have the user auto-assign user defined button assignments:
'
' __AUTOASSIGN_BUTTON(Handle)
'
' Example:
'
' __AUTOASSIGN_BUTTON UP_Button ' [SLOT1] wait for a button press or axis deflection
' __AUTOASSIGN_BUTTON UP_Button ' [SLOT2] wait for a button press or axis deflection
'
' __AUTOASSIGN_BUTTON will wait for a controller button press or axis deflection and then store that information into an available slot. Again,
' this can be done up to four times to fill the four available slots.
'
' NOTE: The mouse controller axes are ignored while __AUTOASSIGN_BUTTON waits for a controller button or axis. If you wish to assign mouse movements as
' axes to a user defined button you'll need to do it manually with __ASSIGN_AXIS.
' +---------------------------------------+
' | |
' | REMOVING BUTTON ASSIGNMENTS |
' | |
' +---------------------------------------+
'
' The following subroutine can be used to clear button/axis assignments (slots) from a user defined button:
'
' __REMOVE_BUTTON(Handle, Slot)
'
' Example:
'
' __REMOVE_BUTTON UP_Button, 3 ' remove the assigned button/axis from slot 3
' __REMOVE_BUTTON DOWN_Button, 0 ' remove the assigned buttons/axes from all slots
'
' Slot can range from 1 to 4, or 0 if you wish to remove all user assigned buttons/axes.
' +---------------------------------------+
' | |
' | REMOVING A CONTROLLER'S BUTTONS |
' | |
' +---------------------------------------+
'
' The subroutine __REMOVE_CONTROLLER will remove all user assigned buttons associated with a controller. This is most useful when a controller has
' been detected as unplugged by __NEW_CONTROLLER and the associated assigned buttons need to be removed as well.
'
' __REMOVE_CONTROLLER cid
'
' Example:
'
' Controller = __NEW_CONTROLLER(Event) ' check for a controller event
' IF Controller THEN ' has a controller event ocurred?
' SELECT CASE Event ' yes, what happened?
' CASE __NEW_CONTROLLER ' a new controller was plugged in
' PRINT "A new controller with the id of"; Controller; "has been plugged in."
' CASE __PLUGGEDIN ' an existing controller was plugged back in
' PRINT "Controller id"; Controller; "has been plugged back in."
' __LOAD_BUTTONS ' load user defined buttons associated with controller (if they exist)
' CASE __UNPLUGGED ' an existing controller was unplugged
' PRINT "Controller id"; Controller; "has been unplugged."
' __REMOVE_CONTROLLER Controller ' remove controller's associated user defined buttons
' END SELECT
' END IF
' +---------------------------------------+
' | |
' | ENABLING/DISABLING BUTTON REASSIGNMENT|
' | |
' +---------------------------------------+
'
' If an attempt is made to assign an axis or button that was previously assigned to a user defined button, the original assignment will be erased and
' replaced by the new assignment by default. This behavior can be changed using the following subroutines:
'
' __BUTTON_REASSIGN_ALLOWED
' __BUTTON_REASSIGN_NOT_ALLOWED
'
' Example:
'
' __BUTTON_REASSIGN_ALLOWED ' allow previously assigned buttons/axes to be moved into a different user assigned button *DEFAULT*
' __BUTTON_REASSIGN_NOT_ALLOWED ' ignore requests to reassign buttons
' +---------------------------------------+
' | |
' | GETTING A BUTTON'S NAME |
' | |
' +---------------------------------------+
'
' When a user defined button is created a descriptive name is also generated and stored. You can use the following function to get a user defined button's
' name:
'
' __BUTTON_NAME$(Handle, Slot)
'
' Example:
'
' ButtonName$ = __BUTTON_NAME$(UP_Button, 1)
'
' Slot values range from 1 to 4.
' +---------------------------------------+
' | |
' | LOADING/SAVING USER DEFINED BUTTONS |
' | |
' +---------------------------------------+
'
' It's now possible to save and load user defined buttons associated to controller inputs. Use the __SAVE_BUTTONS subroutine to save the current
' set of user defined buttons and __LOAD_BUTTONS to load any user defined buttons that may be associated with a controller.
'
' __SAVE_BUTTONS ' save all currently configured user define buttons to configuration files
' __LOAD_BUTTONS ' load buttons that are associated with the currently connected controllers
'
' When __SAVED_BUTTONS is used a configration file for each attached controller is created. The name of the controller and the controller's id number
' ised used to create the file. For instance, if a system currently has a keyboard, mouse, Joystick, and game pad. The name of the joystick is
' "Saitek ST290 Pro" and the name of the game pad is "USB Game Pad". The joystick is using id#3 and the game pad is using id#4. The four configration
' files that will be created are:
'
' - "Keyboard.ID1"
' - "Mouse.ID2"
' - "Saitek ST290 Pro.ID3"
' - "USB Game Pad.ID4"
'
' All user assigned buttons will be saved in their assigned controller configuration file. It's possible to have multiple configration files for any
' given controller based on the id number it is using. For example, let's say the next time the program is started only the USB Game Pad is connected.
' It will be identified as using id number 3. Later on the user plugs in the Saitek ST290 Pro which will now be have an id of 4. When __SAVE_BUTTONS
' is used the four configration files will be as follows:
'
' - "Keyboard.ID1"
' - "Mouse.ID2"
' - "USB Game Pad.ID3"
' - "Saitek ST290 Pro.ID4"
'
' Therefore, depending on which id number a controller currently has will depend on which configuration file is used to load saved user defined
' buttons. This allows controllers to be set up with player 1-6 configurations with each player having a different preferred configuration.
'
' Also, controllers that have no user assigned buttons will still create a configuration file of zero bytes in size. This is normal.
'
' __LOAD_BUTTONS will look for configuration files associated with all currently connected controllers based on their id numbers. If a configration
' exists the user defined buttons wil be loaded.
' +---------------------------------------+
' | |
' | REMAPPING JOYSTICK/GAME PAD AXES |
' | |
' +---------------------------------------+
'
' As stated before, joystick and game pad axis are always returned as values between -1 and 1. The following function can be used to remap this range
' to a different value range:
'
' __MAP_AXIS(AxisValue, Lower, Upper)
'
' Example:
'
' J1Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), -128, 128) ' remap joystick 1 horizontal axis values from -128 to 128 (0 being center)
' J1Yaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 2), -128, 128) ' remap joystick 1 vertical axis values from -128 to 128 (0 being center)
' J2Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD2CID, 1), 0, 255) ' remap joystick 2 horizontal axis values from 0 to 255 (127 being center)
' J2Yaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD2CID, 2), 0, 255) ' remap joystick 2 vertical axis values from 0 to 255 (127 being center)
'
' The Lower and Upper range values can be any values you wish as long as the Lower value is less than the Upper value.
'
' +---------------------------------------+
' | |
' | LIBRARY CODE BEGINS HERE |
' | |
' +---------------------------------------+
'OPTION _EXPLICIT
' __________________________________________________________________________________________________________________________________________________
'/ KEYBOARD KEY _BUTTON CONSTANTS \
CONST CLKEY_ESC = 2 ' |
CONST CLKEY_F1 = 60 ' FUNCTION KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_F2 = 61 ' _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ |
CONST CLKEY_F3 = 62 ' ||ESC|| ||F1 |||F2 |||F3 |||F4 || ||F5 |||F6 |||F7 |||F8 || ||F9 |||N/A|||F11|||F12|| |
CONST CLKEY_F4 = 63 ' ||___|| ||___|||___|||___|||___|| ||___|||___|||___|||___|| ||___|||___|||___|||___|| |
CONST CLKEY_F5 = 64 ' |/___\| |/___\|/___\|/___\|/___\| |/___\|/___\|/___\|/___\| |/___\|/___\|/___\|/___\| |
CONST CLKEY_F6 = 65 ' |
CONST CLKEY_F7 = 66 ' NOTE: F10 does not register as a _BUTTON. I know, strange but true. |
CONST CLKEY_F8 = 67 ' These _BUTTON contants were provided by gx.bi in dbox's Game Engine: https://github.com/boxgaming/gx |
CONST CLKEY_F9 = 68 ' |
CONST CLKEY_F11 = 88 ' |
CONST CLKEY_F12 = 89 ' |
CONST CLKEY_BACKQUOTE = 42 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_1 = 3 ' FIRST KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_2 = 4 ' |
CONST CLKEY_3 = 5 ' _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _________ |
CONST CLKEY_4 = 6 ' ||`~ |||1! |||2@ |||3# |||4$ |||5% |||6^ |||7& |||8* |||9( |||0) |||-_ |||=+ |||BACKSP || |
CONST CLKEY_5 = 7 ' ||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||_______|| |
CONST CLKEY_6 = 8 ' |/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/_______\| |
CONST CLKEY_7 = 9 ' |
CONST CLKEY_8 = 10 ' |
CONST CLKEY_9 = 11 ' |
CONST CLKEY_0 = 12 ' |
CONST CLKEY_MINUS = 13 ' |
CONST CLKEY_EQUALS = 14 ' |
CONST CLKEY_BACKSPACE = 15 ' |
CONST CLKEY_TAB = 16 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_Q = 17 ' SECOND KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_W = 18 ' |
CONST CLKEY_E = 19 ' _______ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _______ |
CONST CLKEY_R = 20 ' ||TAB |||Q |||W |||E |||R |||T |||Y |||U |||I |||O |||P |||[{ |||]} |||\| || |
CONST CLKEY_T = 21 ' ||_____|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||_____|| |
CONST CLKEY_Y = 22 ' |/_____\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/_____\| |
CONST CLKEY_U = 23 ' |
CONST CLKEY_I = 24 ' |
CONST CLKEY_O = 25 ' |
CONST CLKEY_P = 26 ' |
CONST CLKEY_LBRACKET = 27 ' |
CONST CLKEY_RBRACKET = 28 ' |
CONST CLKEY_BACKSLASH = 44 ' |
CONST CLKEY_CAPSLOCK = 59 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_A = 31 ' THIRD KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_S = 32 ' |
CONST CLKEY_D = 33 ' ________ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ ____________ |
CONST CLKEY_F = 34 ' ||CAPS |||A |||S |||D |||F |||G |||H |||J |||K |||L |||;: |||'" |||ENTER || |
CONST CLKEY_G = 35 ' ||______|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||__________|| |
CONST CLKEY_H = 36 ' |/______\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/__________\| |
CONST CLKEY_J = 37 ' |
CONST CLKEY_K = 38 ' |
CONST CLKEY_L = 39 ' |
CONST CLKEY_SEMICOLON = 40 ' |
CONST CLKEY_QUOTE = 41 ' |
CONST CLKEY_ENTER = 29 ' |
CONST CLKEY_LSHIFT = 43 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_Z = 45 ' FOURTH KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_X = 46 ' |
CONST CLKEY_C = 47 ' _____________ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____ _____________ |
CONST CLKEY_V = 48 ' ||LEFT SHIFT |||Z |||X |||C |||V |||B |||N |||M |||,< |||.> |||/? |||RIGHT SHIFT|| |
CONST CLKEY_B = 49 ' ||___________|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___|||___________|| |
CONST CLKEY_N = 50 ' |/___________\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___\|/___________\| |
CONST CLKEY_M = 51 ' |
CONST CLKEY_COMMA = 52 ' |
CONST CLKEY_PERIOD = 53 ' |
CONST CLKEY_SLASH = 54 ' |
CONST CLKEY_RSHIFT = 55 ' |
CONST CLKEY_LCTRL = 30 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_LWIN = 348 ' FIFTH KEY ROW _BUTTON CONSTANTS |
CONST CLKEY_SPACEBAR = 58 ' |
CONST CLKEY_RWIN = 349 ' ______ ______ ______ _____________________________________________ ______ ______ ______ |
CONST CLKEY_RCTRL = 286 ' ||LCTL|||LWIN|||MENU|||SPACEBAR |||N/A |||RWIN|||RCTL|| |
CONST CLKEY_MENU = 350 ' ||____|||____|||____|||___________________________________________|||____|||____|||____|| |
' |/____\|/____\|/____\|/___________________________________________\|/____\|/____\|/____\| |
' |
CONST CLKEY_NUMLOCK = 326 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_NUMPAD_DIVIDE = 310 ' NUMBER PAD _BUTTON CONSTANTS |
CONST CLKEY_NUMPAD_MULTIPLY = 56 ' |
CONST CLKEY_NUMPAD_MINUS = 75 ' _____ _____ _____ _____ |
CONST CLKEY_NUMPAD_7 = 72 ' ||NUM|||/ |||* |||- || |
CONST CLKEY_NUMPAD_8 = 73 ' ||___|||___|||___|||___|| |
CONST CLKEY_NUMPAD_9 = 74 ' |/___\|/___\|/___\|/___\| |
CONST CLKEY_NUMPAD_PLUS = 79 ' _____ _____ _____ _____ |
CONST CLKEY_NUMPAD_4 = 76 ' ||7 |||8 |||9 |||+ || |
CONST CLKEY_NUMPAD_5 = 77 ' ||___|||___|||___||| || |
CONST CLKEY_NUMPAD_6 = 78 ' |/___\|/___\|/___\|| || |
CONST CLKEY_NUMPAD_1 = 80 ' _____ _____ _____|| || |
CONST CLKEY_NUMPAD_2 = 81 ' ||4 |||5 |||6 ||| || |
CONST CLKEY_NUMPAD_3 = 82 ' ||___|||___|||___|||___|| |
CONST CLKEY_NUMPAD_ENTER = 285 ' |/___\|/___\|/___\|/___\| |
CONST CLKEY_NUMPAD_0 = 83 ' _____ _____ _____ _____ |
CONST CLKEY_NUMPAD_PERIOD = 84 ' ||1 |||2 |||3 |||E || |
' ||___|||___|||___|||N || |
' |/___\|/___\|/___\||T || |
' ___________ _____||E || |
' ||0 |||. |||R || |
' ||_________|||___|||___|| |
' |/_________\|/___\|/___\| |
' |
CONST CLKEY_UP = 329 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_LEFT = 332 ' ARROW KEY _BUTTON CONSTANTS |
CONST CLKEY_DOWN = 337 ' |
CONST CLKEY_RIGHT = 334 ' _____ |
' || || |
' ||___|| |
' |/___\| |
' _____ _____ _____ |
' || ||| ||| || |
' ||___|||___|||___|| |
' |/___\|/___\|/___\| |
' |
CONST CLKEY_SCRLK = 71 ' ----------------------------------------------------------------------------------------- |
CONST CLKEY_PAUSE = 70 ' POSITION KEY _BUTTON CONSTANTS |
CONST CLKEY_INSERT = 339 ' |
CONST CLKEY_HOME = 328 ' _____ _____ _____ |
CONST CLKEY_PAGEUP = 330 ' ||N/A|||SCR|||PAU|| |
CONST CLKEY_DELETE = 340 ' ||___|||___|||___|| NOTE: Pause not working on my system? |
CONST CLKEY_END = 336 ' |/___\|/___\|/___\| |
CONST CLKEY_PAGEDOWN = 338 ' _____ _____ _____| |
' ||INS|||HOM|||PUP|| |
' ||___|||___|||___|| |
' |/___\|/___\|/___\| |
' _____ _____ _____ |
' ||DEL|||END|||PDN|| |
' ||___|||___|||___|| |
' |/___\|/___\|/___\| |
' |
'\__________________________________________________________________________________________________________________________________________________/
'/ __NEW_CONTROLLER CONSTANTS \
CONST __UNPLUGGED = 1 ' existing controller unplugged - use with __NEW_CONTROLLER |
CONST __PLUGGEDIN = 2 ' existing controller plugged back in - use with __NEW_CONTROLLER |
CONST __NEWCONTROLLER = 3 ' a new controller has been plugged in - use with __NEW_CONTROLLER |
'\__________________________________________________________________________________________________________________________________________________/
'/ TYPE__SLOT \
TYPE TYPE__SLOT ' USER DEFINED BUTTON SLOT PROPERTIES |
Cname AS STRING * 25 ' controller name |
cid AS INTEGER ' controller id number (_DEVICES) |
Button AS INTEGER ' button number (0 if using axis) |
Axis AS INTEGER ' axis number (0 if using button) (- value for UP/LEFT or + value for DOWN/RIGHT) |
Name AS STRING * 15 ' button/axis name |
END TYPE ' |
'\__________________________________________________________________________________________________________________________________________________/
'/ TYPE__BUTTON \
TYPE TYPE__BUTTON ' USER DEFINED BUTTON PROPERTIES |
Slot0 AS TYPE__SLOT ' blank slot to clear others |
Slot1 AS TYPE__SLOT ' user defined button slot 1 |
Slot2 AS TYPE__SLOT ' user defined button slot 2 |
Slot3 AS TYPE__SLOT ' user defined button slot 3 |
Slot4 AS TYPE__SLOT ' user defined button slot 4 |
END TYPE ' |
'\__________________________________________________________________________________________________________________________________________________/
'/ TYPE__CONTROLLER \
TYPE TYPE__CONTROLLER ' DETECTED CONTROLLER PROPERTIES |
Found AS INTEGER ' controller found (t/f) |
Connected AS INTEGER ' controller connected (t/f) |
Name AS STRING * 25 ' description of controller |
Buttons AS INTEGER ' number of buttons controller has ( _LASTBUTTON(Controller) ) |
Axis AS INTEGER ' number of axis controller has ( _LASTAXIS(Controller) ) |
Wheels AS INTEGER ' number of wheels controller has ( _LASTWHEEL(Controller) ) ** NOT IMPLEMENTED YET * |
END TYPE ' |
'\__________________________________________________________________________________________________________________________________________________/
'/ TYPE__SETTINGS \
TYPE TYPE__SETTINGS ' LIBRARY SETTINGS |
Reassign AS INTEGER ' reassign (-1) or ignore (0) already used user defined buttons |
Threshold AS SINGLE ' axis sensitivity when used as a user defined button (.01 to .99) |
FoundDevices AS INTEGER ' number of controllers found when program first started |
END TYPE ' |
'\__________________________________________________________________________________________________________________________________________________/
'/ VARIABLE ASSIGNMENTS \
REDIM CL_BUTTON(1) AS TYPE__BUTTON ' user assigned button array |
DIM CL_CONTROLLER(6) AS TYPE__CONTROLLER ' controller array (index number equals _DEVICES id number) |
DIM CL_KEYNAME(350) AS STRING ' keyboard _BUTTON key names |
DIM CL_SETTINGS AS TYPE__SETTINGS ' library settings |
DIM SHARED __CURRENT_ROUTINE AS STRING ' __ERROR use |
DIM SHARED __PREVIOUS_ROUTINE AS STRING ' __ERROR use |
DIM SHARED __KEYBOARDCID AS INTEGER ' these will contain the device ids (_DEVICES) |
DIM SHARED __MOUSECID AS INTEGER ' |
DIM SHARED __JOYPAD1CID AS INTEGER ' |
DIM SHARED __JOYPAD2CID AS INTEGER ' |
DIM SHARED __JOYPAD3CID AS INTEGER ' |
DIM SHARED __JOYPAD4CID AS INTEGER ' |
DIM SHARED __JOYPAD5CID AS INTEGER ' |
DIM SHARED __JOYPAD6CID AS INTEGER ' |
'\__________________________________________________________________________________________________________________________________________________/
Code: (Select All) '----------------------------
' Controller Library V1.10
' Terry Ritchie
' May 17th, 2023
' Written using QB64PE v3.7.0
'----------------------------
' CONTROLLER.BM
'----------------------------
'
' TODO: Add WHEEL routines
' Create PDF instructions
'
'----------------------------
' 04/10/23 V1.0 - Initial Release
' 04/26/23 V1.01 - Corrected slot reassigning issues
' 05/17/23 V1.10 - Added __MAKE_BUTTON, __CONNECTED, __SAVE_BUTTONS, __LOAD_BUTTONS, __NEW_CONTROLLER, __REMOVE_CONTROLLER
' - The library now has the ability to save and load controller user defined button configurations
' - You can now detect when a controller has been plugged in or unplugged
' - A controller's user defined button assignments can be removed when the controller has been unplugged
'----------------------------
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __REMOVE_CONTROLLER (cid AS INTEGER) ' __REMOVE_CONTROLLER |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Removes all user defined buttons associated with a controller. |
'| |
'| __REMOVE_CONTROLLER __JOYPAD3CID |
'| |
'| cid - the controller id |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
DIM b AS INTEGER ' button counter
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__REMOVE_CONTROLLER"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-----------------------------------------------------------------------------+
'| Cycle through each assigned button slot. If a button assignment matches the |
'| controller name and controller id then remove the button from the array. |
'+-----------------------------------------------------------------------------+
b = 0 ' reset button counter
DO ' begin button search
b = b + 1 ' increment button counter
IF CL_BUTTON(b).Slot1.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot1.cid = cid THEN ' does controller name and id match in slot 1?
__REMOVE_BUTTON b, 1 ' yes, remove the button assignment in slot 1
END IF
IF CL_BUTTON(b).Slot2.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot2.cid = cid THEN ' does controller name and id match in slot 2?
__REMOVE_BUTTON b, 2
END IF
IF CL_BUTTON(b).Slot3.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot3.cid = cid THEN ' does controller name and id match in slot 3?
__REMOVE_BUTTON b, 3
END IF
IF CL_BUTTON(b).Slot4.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot4.cid = cid THEN ' does controller name and id match in slot 4?
__REMOVE_BUTTON b, 4
END IF
LOOP UNTIL b = UBOUND(CL_BUTTON) ' leave when all buttons checked
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __NEW_CONTROLLER (Action AS INTEGER) ' __NEW_CONTROLLER |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Checks for the addition of a new controller, a controller that has been unplugged, or a controller plugged back in. |
'| |
'| Controller = __NEW_CONTROLLER(Action) |
'| |
'| Action - the returned action that occurred |
'| 0 - nothing changed |
'| 1 - a controller was unplugged (the constant __UNPLUGGED has been created to check for this) |
'| 2 - a controller was plugged back in (the constant __PLUGGEDIN has been created to check for this) |
'| 3 - a new controller has been plugged in (the constant __NEWCONTROLLER has been created to check for this) |
'| |
'| The function will return the following values: |
'| |
'| - the value will contain the new controller id when a new controller is plugged in (Action = 3 ) |
'| - the value will contain the controller id of a controller that was unplugged or plugged back in (Action = 1 or 2) |
'| - a value of 0 (FALSE) if nothing has changed |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
DIM Rescan AS INTEGER ' -1 (TRUE) if controllers need to be rescanned
DIM Devices AS INTEGER ' number of devices currently found
DIM d AS INTEGER ' device counter
__NEW_CONTROLLER = 0 ' assume no new or previous controller plugged in
Action = 0 ' assume no changes
d = 0 ' reset device counter
Rescan = 0 ' reset rescan flag
Devices = _DEVICES ' get number of devices found
IF Devices <> CL_SETTINGS.FoundDevices THEN ' has a new controller been plugged in?
Rescan = -1 ' yes, controllers will need to be rescanned
Action = __NEWCONTROLLER ' remember that a new controller was plugged in
ELSE ' no, check for previous plugged/unplugged controllers
DO ' begin controller search
d = d + 1 ' increment device counter
IF __CONNECTED(d) <> CL_CONTROLLER(d).Connected THEN ' has controller connection status changed?
Rescan = d ' yes, remember which controller has changed and needs rescanned
IF CL_CONTROLLER(d).Connected THEN ' was the controller connected?
Action = __UNPLUGGED ' yes, remember that it was just unplugged
ELSE ' no, the controller was disconnected
Action = __PLUGGEDIN ' remember that it was just plugged back in
END IF
EXIT DO ' no need to check any more controllers
END IF
LOOP UNTIL d = Devices ' leave when all controllers checked
END IF
IF Rescan THEN ' need to scan for new/unplugged/plugged in controllers?
__IDENTIFY_CONTROLLERS ' yes, identify connected controllers
IF Rescan = -1 THEN ' was a new controller found?
__NEW_CONTROLLER = CL_SETTINGS.FoundDevices ' yes, return the new controller id number
ELSE ' no, a controller was unplugged/plugged back in
__NEW_CONTROLLER = Rescan ' return the controller that was unplugged/plugged back in
END IF
END IF
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __MAKE_BUTTON (Handle AS INTEGER) ' __MAKE_BUTTON |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Assigns a value to a user generated integer button variable. |
'| |
'| DIM UPButton AS INTEGER |
'| __MAKE_BUTTON UPButton ' define the integer variable UPButton as a user defined button |
'| |
'| Handle - the name of the variable the user wishes to use as a button reference. |
'| The variable's value will change to indicate the new handle value pointing to the button array index. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__MAKE_BUTTON"
IF Handle THEN __ERROR "This button has already been created"
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+----------------------------------------------+
'| Create a new entry for the button assignment |
'+----------------------------------------------+
Handle = UBOUND(CL_BUTTON) + 1 ' set handle to new size of button array
REDIM _PRESERVE CL_BUTTON(Handle) AS TYPE__BUTTON ' increase size of button array to match new handle
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __SAVE_BUTTONS () ' __SAVE_BUTTONS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Saves all assigned buttons for all currently discovered and connected controllers. |
'| |
'| __SAVE_BUTTONS |
'| |
'| The config files created for the controllers will be in the form: [Controller Name].ID[Device ID#] |
'| For example, a joystick with the name Saitek ST290 Pro found as device number 4 will have the following config file: "Saitek ST290 Pro.ID4" |
'| |
'| It's possible for a controller to have multiple config files based on the device id number. |
'| - "Saitek ST290 Pro.ID3" |
'| - "Saitek ST290 Pro.ID4" |
'| - "Saitek ST290 Pro.ID5" |
'| - etc.. |
'| |
'| This allows for multiple configurations based on which player is using which joystick/game pad in any order. |
'| |
'| Controllers with no assigned buttons will create config files that are zero bytes in length. This is normal. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
DIM Fname AS STRING ' controller config file name
DIM b AS INTEGER ' button counter
DIM cid AS INTEGER ' controller id counter
DIM FF AS LONG ' next available free file handle
cid = 0 ' reset controller id counter
DO ' begin controller search loop
cid = cid + 1 ' increment controller id counter
IF CL_CONTROLLER(cid).Found THEN ' was this controller found initially?
IF __CONNECTED(cid) THEN ' yes, is this controller still connected?
'+---------------------------------------------------+
'| This controller is in use and currently connected |
'| Create and open a config file for this controller |
'+---------------------------------------------------+
Fname = _TRIM$(CL_CONTROLLER(cid).Name) + ".ID" + _TRIM$(STR$(cid)) ' yes, build the name of controller's config file
FF = FREEFILE ' get a free file handle
OPEN Fname FOR OUTPUT AS #FF ' open the config file for writing
b = 0 ' reset button counter
'+-----------------------------------------------------------------------------+
'| Cycle through each assigned button slot. If a button assignment matches the |
'| controller name and controller id save the variable assignment value, the |
'| button value (0 if axis is used), and the axis value (0 if button is used). |
'+-----------------------------------------------------------------------------+
DO ' begin assignment search and write loop
b = b + 1 ' increment button counter
IF CL_BUTTON(b).Slot1.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot1.cid = cid THEN ' does controller name and id match in slot 1?
WRITE #FF, b, CL_BUTTON(b).Slot1.Button, CL_BUTTON(b).Slot1.Axis ' yes, write assignment to file
END IF
IF CL_BUTTON(b).Slot2.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot2.cid = cid THEN ' does controller name and id match in slot 2?
WRITE #FF, b, CL_BUTTON(b).Slot2.Button, CL_BUTTON(b).Slot2.Axis ' yes, write assignment to file
END IF
IF CL_BUTTON(b).Slot3.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot3.cid = cid THEN ' does controller name and id match in slot 3?
WRITE #FF, b, CL_BUTTON(b).Slot3.Button, CL_BUTTON(b).Slot3.Axis ' yes, write assignment to file
END IF
IF CL_BUTTON(b).Slot4.Cname = CL_CONTROLLER(cid).Name AND CL_BUTTON(b).Slot4.cid = cid THEN ' does controller name and id match in slot 4?
WRITE #FF, b, CL_BUTTON(b).Slot4.Button, CL_BUTTON(b).Slot4.Axis ' yes, write assignment to file
END IF
LOOP UNTIL b = UBOUND(CL_BUTTON) ' leave when all button assignments checked
CLOSE #FF ' close the file
END IF
END IF
LOOP UNTIL cid = 6 ' leave when all controllers checked
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __LOAD_BUTTONS () ' __LOAD_BUTTONS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Loads assigned buttons for controllers from configuration files if they exist. |
'| |
'| __LOAD_BUTTONS |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
DIM Fname AS STRING ' controller config file name
DIM cid AS INTEGER ' controller id counter
DIM Handle AS INTEGER ' user defined button handle
DIM Button AS INTEGER ' button to assign (0 if axis)
DIM Axis AS INTEGER ' axis to assign (0 if button)
DIM FF AS LONG ' next available free file handle
cid = 0 ' reset controller id counter
DO ' begin controller search loop
cid = cid + 1 ' increment controller id counter
IF CL_CONTROLLER(cid).Found THEN ' was this controller found initially?
IF __CONNECTED(cid) THEN ' yes, is this controller still connected?
'+-----------------------------------------------------------------+
'| This controller was initially found and is currently connected. |
'| Create a config file name to check for. |
'+-----------------------------------------------------------------+
Fname = _TRIM$(CL_CONTROLLER(cid).Name) + ".ID" + _TRIM$(STR$(cid)) ' yes, build the name of the controller's config file
IF _FILEEXISTS(Fname) THEN ' does a config file for this controller exist?
'+-------------------------------------------+
'| A config file exists for this controller |
'| Open the file and assign the buttons/axes |
'+-------------------------------------------+
FF = FREEFILE ' yes, get a free file handle
OPEN Fname FOR INPUT AS #FF ' open the config file for reading
WHILE NOT EOF(1) ' has the end of the file been reached?
'+---------------------------------------------------------------+
'| Config files that are zero bytes in length are simply ignored |
'+---------------------------------------------------------------+
INPUT #FF, Handle, Button, Axis ' no, get the button handle, button, and axis settings
IF Button THEN ' has a button been assigned?
__ASSIGN_BUTTON Handle, cid, Button ' yes, assign the button
ELSE ' no, an axis is assigned
__ASSIGN_AXIS Handle, cid, Axis ' assign the axis as a button
END IF
WEND ' loop back and load next button assignment (if any)
CLOSE #FF ' close the config file
END IF
END IF
END IF
LOOP UNTIL cid = 6 ' leave when all controllers searched
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __CONNECTED (cid AS INTEGER) ' __CONNECTED |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns 0 (FALSE) if a controller is disconnected, -1 (TRUE) otherwise |
'| |
'| Status = __CONNECTED(__JOYPAD1CID) |
'| |
'| cid - the id of the controller |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__CONNECTED"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-------------------------+
'| Return connection state |
'+-------------------------+
WHILE _DEVICEINPUT(cid): WEND ' get latest controller values
IF INSTR(_DEVICE$(cid), "[DISCONNECTED]") THEN ' is controller disconnected?
__CONNECTED = 0 ' yes, return that controller is disconnected
ELSE ' no
__CONNECTED = -1 ' return that controller is connected
END IF
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __BUTTON_NAME$ (Handle AS INTEGER, Slot AS INTEGER) ' __BUTTON_NAME$ |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Retrieves the name of a user defined button. |
'| |
'| Description = __BUTTON_NAME$(Up_Button, 1) ' get name of button in slot 1 |
'| |
'| Handle - the handle of the user defined button |
'| Slot - the slot number (1 to 4) |
'| passing the value of 0 will clear all slot assignments and remove the user defined button completely. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__BUTTON_NAME$"
IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
IF Slot < 0 OR Slot > 4 THEN __ERROR "The requested slot assignment does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-----------------+
'| Get button name |
'+-----------------+
SELECT CASE Slot
CASE 1: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot1.Name
CASE 2: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot2.Name
CASE 3: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot3.Name
CASE 4: __BUTTON_NAME$ = CL_BUTTON(Handle).Slot4.Name
END SELECT
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __SET_AXIS_THRESHOLD (Value AS SINGLE) ' __SET_AXIS_THRESHOLD |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Sets the value at which an axis set up as a user defined button is seen as being pressed. |
'| |
'| __SET_AXIS_THRESHOLD .25 ' button activated when axis is deflected 25% either UP/DOWN or LEFT/RIGHT |
'| |
'| Value - .01 (1%) to .99 (99%) of axis deflection |
'| |
'| NOTE: The default value set up by __INITIALIZE_CONTROLLERS is .5 (50%) |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__SET_AXIS_THRESHOLD"
IF Value <= 0 OR Value >= 1 THEN __ERROR "Threshold value must be between 0 and 1."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+---------------------+
'| Set threshold value |
'+---------------------+
CL_SETTINGS.Threshold = Value ' set value of user defined button axis sensitivity
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __BUTTON_REASSIGN_ALLOWED () ' __BUTTON_REASSIGN_ALLOWED |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Enables user defined button reassigning. |
'| |
'| __BUTTON_REASSIGN_ALLOWED |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
'+---------------------------+
'| Enable button reassigning |
'+---------------------------+
CL_SETTINGS.Reassign = -1 ' enable button reassigning (TRUE)
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __BUTTON_REASSIGN_NOT_ALLOWED () ' __BUTTON_REASSIGN_NOT_ALLOWED |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Disables user defined button reassigning. |
'| |
'| __BUTTON_REASSIGN_NOT_ALLOWED |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
'+----------------------------+
'| Disable button reassigning |
'+----------------------------+
CL_SETTINGS.Reassign = 0 ' disable button reassigning (FALSE)
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __REMOVE_BUTTON (Handle AS INTEGER, Slot AS INTEGER) ' __REMOVE_BUTTON |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Removes an assigned button or axis from a user defined button. Optionally the entire user defined button can be removed by supplying the |
'| value of 0 for slot. |
'| |
'| __REMOVE_BUTTON UP_Button, 3 ' remove the button/axis assigned in the third slot |
'| |
'| Handle - the handle of the user defined button |
'| Slot - the assigned slot to clear (0 to 4) |
'| passing the value of 0 will clear all slot assignments and remove the user defined button completely. |
'| |
'| When a defined button is removed from a slot the assignments in slots above are shifted down. For example, if the assignment in slot 1 is |
'| removed then the assignment in 2 is shifted to 1, 3 is shifted to 2, 4 is shifted to 3, and 4 is cleared. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__REMOVE_BUTTON"
IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
IF Slot < 0 OR Slot > 4 THEN __ERROR "The requested slot assignment does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+----------------------+
'| Remove assignment(s) |
'+----------------------+
SELECT CASE Slot ' which slot?
CASE 0 ' [ALL SLOTS]
CL_BUTTON(Handle).Slot1 = CL_BUTTON(Handle).Slot0 ' clear slot 1
CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot0 ' clear slot 2
CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot0 ' clear slot 3
CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
CASE 1 ' [SLOT1]
CL_BUTTON(Handle).Slot1 = CL_BUTTON(Handle).Slot2 ' move slot 2 up to slot 1
CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot3 ' move slot 3 up to slot 2
CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
CASE 2 ' [SLOT2]
CL_BUTTON(Handle).Slot2 = CL_BUTTON(Handle).Slot3 ' move slot 3 up to slot 2
CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
CASE 3 ' [SLOT3]
CL_BUTTON(Handle).Slot3 = CL_BUTTON(Handle).Slot4 ' move slot 4 up to slot 3
CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
CASE 4 ' [SLOT4]
CL_BUTTON(Handle).Slot4 = CL_BUTTON(Handle).Slot0 ' clear slot 4
END SELECT
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __JOYPAD_EXISTS (Number AS INTEGER) ' __JOYPAD_EXISTS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the total number of joysticks/game pads that exist (TREU) if the selected joystick/game pad exists, 0 (FALSE) otherwise. |
'| |
'| JoyPads = __JOYPAD_EXISTS(1) ' get total number of joysticks/game pads (if any) |
'| IF JoyPads THEN ' was the selected joypad found? |
'| PRINT "Joystick 1 of"; STR$(JoyPads); " found!" ' yes, report findings |
'| Print "Joystick name : ";__CONTROLLER_NAME$(__JOYPAD1CID) |
'| PRINT "Number of buttons:"; __BUTTON_TOTAL(__JOYPAD1CID) |
'| PRINT "Number of axes :"; __AXIS_TOTAL(__JOYPAD1CID) |
'| END IF |
'| |
'| number - the joystick/game pad to query |
'\_______________________________________________________________________________________________________________________________________________/
DIM Found AS INTEGER ' joypad found (t/f)
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__JOYPAD_EXISTS"
IF Number < 1 OR Number > 6 THEN __ERROR "The requested joystick/game pad does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+---------------------------------------+
'| Report existance of joystick/game pad |
'+---------------------------------------+
Found = 0 ' assume no joystick/game pad found
__JOYPAD_EXISTS = 0 ' assume there are no joypads
SELECT CASE Number ' which joypad are we looking for?
CASE 1 ' joypad 1
IF __JOYPAD1CID THEN Found = -1 ' record found if present
CASE 2 ' etc..
IF __JOYPAD2CID THEN Found = -1
CASE 3
IF __JOYPAD3CID THEN Found = -1
CASE 4
IF __JOYPAD4CID THEN Found = -1
CASE 5
IF __JOYPAD5CID THEN Found = -1
CASE 6
IF __JOYPAD6CID THEN Found = -1
END SELECT
IF Found THEN ' was a joypad found?
IF __JOYPAD6CID THEN ' yes, are there 6 joypads?
__JOYPAD_EXISTS = 6 ' yes, return that 6 exist
ELSEIF __JOYPAD5CID THEN ' no, are there 5 joypads?
__JOYPAD_EXISTS = 5 ' yes, return that 5 exist
ELSEIF __JOYPAD4CID THEN ' etc..
__JOYPAD_EXISTS = 4
ELSEIF __JOYPAD3CID THEN
__JOYPAD_EXISTS = 3
ELSEIF __JOYPAD2CID THEN
__JOYPAD_EXISTS = 2
ELSEIF __JOYPAD1CID THEN
__JOYPAD_EXISTS = 1
END IF
END IF
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __MOUSE_EXISTS () ' __MOUSE_EXISTS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns -1 (TRUE) if the mouse controller exists, 0 (FALSE) otherwise. |
'| |
'| IF __MOUSE_EXISTS THEN PRINT "Mouse found!" |
'| |
'| NOTE: It's highly unlikely that a mouse will not exist but for those instances where someone may have created a stand alone computer for |
'| playing QB64 games without a mouse (and/or a keyboard) but just joysticks attached this function is available. |
'\_______________________________________________________________________________________________________________________________________________/
__MOUSE_EXISTS = 0 ' assume no mouse
IF __MOUSECID THEN __MOUSE_EXISTS = -1 ' report that mouse found
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __KEYBOARD_EXISTS () ' __KEYBOARD_EXISTS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns -1 (TRUE) if the keyboard controller exists, 0 (FALSE) otherwise. |
'| |
'| IF __KEYBOARD_EXISTS THEN PRINT "Keyboard found!" |
'| |
'| NOTE: It's highly unlikely that a keyboard will not exist but for those instances where someone may have created a stand alone computer for |
'| playing QB64 games without a keyboard (and/or a mouse) but just joysticks attached this function is available. |
'\_______________________________________________________________________________________________________________________________________________/
__KEYBOARD_EXISTS = 0 ' assume no keyboard
IF __KEYBOARDCID THEN __KEYBOARD_EXISTS = -1 ' report that keyboard was found
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __MAP_AXIS (AxisValue AS SINGLE, Lower AS INTEGER, Upper AS INTEGER) ' __MAP_AXIS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Maps a joypad or mouse axis value from -1 to 1 to another defined range. |
'| |
'| Xaxis = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), 0, 255) ' map -1 to 1 as 0 to 255 |
'| |
'| AxisValue - current axis value (must be -1 to 1) |
'| Lower - the new lower value range |
'| Upper - the new upper value range |
'| |
'| NOTE: This function will only work correctly when AxisValue is between -1 and 1. |
'\_______________________________________________________________________________________________________________________________________________/
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__MAP_AXIS"
IF AxisValue < -1 OR AxisValue > 1 THEN __ERROR "Axis value must be between -1 and 1."
IF Lower >= Upper THEN __ERROR "The lower value must be less than the upper value."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-----------------------------------+
'| Convert input to new output range |
'+-----------------------------------+
__MAP_AXIS = INT(Lower + (AxisValue + 1) * (Lower - Upper) / -2) ' convert input to adjusted output
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __AXIS_TOTAL (cid AS INTEGER) ' __AXIS_TOTAL |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the number of axes a controller has. |
'| |
'| Total = __AXIS_TOTAL(__JOYPAD1CID) |
'| |
'| cid - the controller id |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__AXIS_TOTAL"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF CL_CONTROLLER(cid).Axis = 0 THEN __ERROR "The specified controller has no axes."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+----------------------------------+
'| Return number of controller axis |
'+----------------------------------+
__AXIS_TOTAL = CL_CONTROLLER(cid).Axis ' return number of axes
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __BUTTON_TOTAL (cid AS INTEGER) ' __BUTTON_TOTAL |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the number of buttons a controller has. |
'| |
'| Total = __BUTTON_TOTAL(__JOYPAD1CID) |
'| |
'| cid - the controller id |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__BUTTON_TOTAL"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF CL_CONTROLLER(cid).Buttons = 0 THEN __ERROR "The specified controller has no buttons."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-------------------------------------+
'| Return number of controller buttons |
'+-------------------------------------+
__BUTTON_TOTAL = CL_CONTROLLER(cid).Buttons ' return number of buttons
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __CONTROLLER_BUTTON (cid AS INTEGER, Button AS INTEGER) ' __CONTROLLER_BUTTON |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the state of a controller's button. |
'| |
'| Button = __CONTROLLER_BUTTON(__KEYBOARDCID, 329) ' keyboard UP arrow key |
'| |
'| cid - the controller id |
'| Button - the controller's button (or keyboard key) |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__CONTROLLER_BUTTON"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF CL_CONTROLLER(cid).Buttons = 0 THEN __ERROR "The specified controller has no buttons."
IF Button < 1 OR Button > CL_CONTROLLER(cid).Buttons THEN __ERROR "The specified controller does not have this button."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-----------------------------+
'| Return current button state |
'+-----------------------------+
IF __CONNECTED(cid) THEN ' is controller connected?
WHILE _DEVICEINPUT(cid): WEND ' yes, get latest controller values
__CONTROLLER_BUTTON = _BUTTON(Button) ' return controller button state
END IF
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __CONTROLLER_AXIS (cid AS INTEGER, Axis AS INTEGER) ' __CONTROLLER_AXIS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the value of a controller's axis. (-1 to 1) |
'| |
'| Xaxis = __CONTROLLER_AXIS(__JOYPAD1CID, 1) ' x axis of joypad 1 |
'| |
'| cid - the controller id |
'| Axis - the controller's axis number |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__CONTROLLER_AXIS"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF CL_CONTROLLER(cid).Axis = 0 THEN __ERROR "The specified controller has no axes."
IF Axis < 1 OR Axis > CL_CONTROLLER(cid).Axis THEN __ERROR "The specified controller does not have this axis."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+---------------------------+
'| Return current axis value |
'+---------------------------+
IF __CONNECTED(cid) THEN ' is controller connected?
WHILE _DEVICEINPUT(cid): WEND ' yes, get latest controller values
__CONTROLLER_AXIS = _AXIS(Axis) ' return controller axis value
END IF
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __CONTROLLER_NAME$ (cid AS INTEGER) ' __CONTROLLER_NAME$ |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns the descriptive name of the controller. |
'| |
'| PRINT __CONTROLLER_NAME$(__JOYPAD1CID) |
'| |
'| cid - the id of the controller |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__CONTROLLER_NAME$"
IF cid < 1 OR cid > 6 THEN __ERROR "Invalid controller id."
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist"
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+---------------------------+
'| Return name of controller |
'+---------------------------+
__CONTROLLER_NAME$ = CL_CONTROLLER(cid).Name ' return the name of the controller
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION __BUTTON_DOWN (Handle AS INTEGER) ' __BUTTON_DOWN |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns -1 (TRUE) if a button is pressed, 0 (FALSE) otherwise. |
'| |
'| State = __BUTTON_DOWN(UPButton) |
'| |
'| Handle - the handle of the button to check |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
DIM Slot AS INTEGER ' button/axis slot counter
DIM cid AS INTEGER ' controller id
DIM Button AS INTEGER ' controller button
DIM Axis AS INTEGER ' controller axis
DIM AxisValue AS SINGLE ' controller current axis value
DIM Down AS INTEGER ' button is down (t/f)
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__BUTTON_DOWN"
IF Handle < 1 OR Handle > UBOUND(CL_BUTTON) THEN __ERROR "The specified button does not exist."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-------------------------+
'| Report status of button |
'+-------------------------+
Down = 0 ' assume no button/axis pressed
Slot = 0 ' reset slot counter
DO ' begin button/axis down search
Slot = Slot + 1 ' increment slot counter
'+----------------------------------------------------------+
'| Get the controller's id, button, and axis from each slot |
'+----------------------------------------------------------+
SELECT CASE Slot ' which button/axis slot?
CASE 1 ' slot 1
cid = CL_BUTTON(Handle).Slot1.cid ' get controller's id from slot 1
Button = CL_BUTTON(Handle).Slot1.Button ' get controller's button from slot 1
Axis = CL_BUTTON(Handle).Slot1.Axis ' get controller's axis from slot 1
CASE 2 ' slot 2
cid = CL_BUTTON(Handle).Slot2.cid
Button = CL_BUTTON(Handle).Slot2.Button
Axis = CL_BUTTON(Handle).Slot2.Axis
CASE 3 ' slot 3
cid = CL_BUTTON(Handle).Slot3.cid
Button = CL_BUTTON(Handle).Slot3.Button
Axis = CL_BUTTON(Handle).Slot3.Axis
CASE 4 ' slot 4
cid = CL_BUTTON(Handle).Slot4.cid
Button = CL_BUTTON(Handle).Slot4.Button
Axis = CL_BUTTON(Handle).Slot4.Axis
END SELECT
IF cid THEN ' is there a controller id?
'+---------------------------------------+
'| A controller id was found in the slot |
'+---------------------------------------+
WHILE _DEVICEINPUT(cid): WEND ' yes, get controller's latest values
IF Button THEN ' does a controller button need checked?
'+--------------------------------------------+
'| This slot contained a button to be checked |
'+--------------------------------------------+
IF _BUTTON(Button) THEN Down = -1 ' yes, get state of controller button
ELSEIF Axis THEN ' no, does a controller axis need checked?
'+-------------------------------------------+
'| This slot contained an axis to be checked |
'+-------------------------------------------+
AxisValue = _AXIS(ABS(Axis)) ' yes, get the current controller axis value
IF ABS(AxisValue) >= CL_SETTINGS.Threshold THEN ' is axis deflected at least to sensitivity setting?
IF SGN(AxisValue) = SGN(Axis) THEN Down = -1 ' yes, get state of axis
END IF
END IF
END IF
LOOP UNTIL (Slot = 4) OR Down ' leave when all four slots checked or a button is down
__BUTTON_DOWN = Down ' return state of button
END FUNCTION
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __AUTOASSIGN_BUTTON (Handle AS INTEGER) ' __AUTOASSIGN_BUTTON |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Automatically assigns a button handle with up to a combination of four controller buttons or axis deflections. Simply call this subroutine up |
'| to four times to associate each axis or button with the handle. This allows axis deflections to be treated as button presses. Good for top |
'| hats and Nintendo style "plus" directionals. |
'| |
'| __AUTOASSIGN_BUTTON UPButton ' player chooses the UP ARROW key for instance and that gets saved in SLOT 1 |
'| __AUTOASSIGN_BUTTON UPButton ' player chooses the W key for instance and that gets saved in SLOT 2 |
'| __AUTOASSIGN_BUTTON UPButton ' player chooses the UP direction on a "plus" pad for instance and that gets saved in SLOT 3 |
'| ' the player now has three different methods of inputting a directional UP movement |
'| |
'| Handle - button handle |
'| |
'| The result of the scan is sent to either __ASSIGN_AXIS or __ASSIGN_BUTTON. See the documentation for these two subrotuines for more |
'| information on how the resulting values are stored and used. |
'| |
'| NOTE: Once all four button slots are filled any attempt to associate a handle with more axis or buttons is ignored. |
'| Mouse axes are ignored during auto assign. Use __ASSIGN_AXIS if you wish to assign a mouse axis as a button (not recommended). |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
DIM cid AS INTEGER ' controller id
DIM Number AS INTEGER ' axis/button number (or keyboard scan code) counter
DIM Button AS INTEGER ' button number (or keyboard scan code) that was pressed
DIM Axis AS INTEGER ' axis that was deflected
DIM AxisValue AS SINGLE ' value of axis that was deflected
DO ' begin controller interaction search
'+---------------------------------------------+
'| Wait for a controller to be interacted with |
'+---------------------------------------------+
_LIMIT 60 ' don't hog the CPU while waiting
cid = _DEVICEINPUT ' check for a controller interaction
IF cid THEN ' was a controller interacted with?
'+----------------------------------+
'| A controller was interacted with |
'+----------------------------------+
WHILE _DEVICEINPUT(cid): WEND
IF CL_CONTROLLER(cid).Buttons <> 0 THEN ' yes, does this controler have buttons?
'+---------------------------------------+
'| This controller has buttons available |
'+---------------------------------------+
Number = 0 ' yes, reset button number counter
Button = 0 ' reset button press number
DO ' begin button search
'+--------------------------------------+
'| Get button (if any) that was pressed |
'+--------------------------------------+
Number = Number + 1 ' increment button number counter
IF _BUTTON(Number) THEN Button = Number ' record this button number if it was pressed
LOOP UNTIL Number = _LASTBUTTON(cid) OR Button ' leave when all buttons checked or a button weas pressed
END IF
'+--------------------------------------------------+
'| A check for axis deflection will now be done. |
'| The mouse is purposely excluded from this check. |
'+--------------------------------------------------+
IF cid <> __MOUSECID THEN ' is this the mouse controller?
IF CL_CONTROLLER(cid).Axis <> 0 THEN ' no, does this controller have axis?
'+------------------------------------+
'| This controller has axis available |
'+------------------------------------+
Number = 0 ' yes, reset axis number counter
Axis = 0 ' reset axis deflection number
DO ' begin axis search
'+--------------------------------------------------------------------------+
'| Get axis (if any) that was deflected at least 50% (or threshold setting) |
'+--------------------------------------------------------------------------+
Number = Number + 1 ' increment axis number counter
AxisValue = _AXIS(Number) ' get current value of axis
IF ABS(AxisValue) >= CL_SETTINGS.Threshold THEN ' was axis delfected at least to sensitivity setting?
'+----------------------------------------------------------------------------------------------------------+
'| The axis number is recorded as a negative value if the deflection was in a negative direction. |
'| Likewise, the axis number is recorded as a positive value if the deflection was in a positive direction. |
'| This allows one axis to be recorded as two separate button actions (UP/DOWN or LEFT/RIGHT). |
'+----------------------------------------------------------------------------------------------------------+
Axis = Number * SGN(AxisValue) ' yes, record axis with sign (+/-) of deflection
END IF
LOOP UNTIL Number = _LASTAXIS(cid) OR Axis ' leave when all axis checked or an axis was deflected
END IF
END IF
END IF
LOOP UNTIL cid <> 0 AND (Button <> 0 OR Axis <> 0) ' leave when a controller interacted with and interaction was with a button or axis
IF cid = __KEYBOARDCID THEN _KEYCLEAR ' clear all keyboard buffers if the keyboard was interacted with
IF Button THEN __ASSIGN_BUTTON Handle, cid, Button ' assign the button to the handle
IF Axis THEN __ASSIGN_AXIS Handle, cid, Axis ' assign the axis to the handle
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __ASSIGN_AXIS (Handle AS INTEGER, cid AS INTEGER, Axis AS INTEGER) ' __ASSIGN_AXIS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Associates a handle with up to four axis from the mouse or joypads. Simply call this subroutine up to four times to associate a new axis to |
'| the handle. This allows axis deflections to be treated as button presses. Good for top hats and Nintendo style "plus" directionals. |
'| |
'| __ASSIGN_AXIS UPButton, __JOYPAD1INPUT, -1 ' joystick/gamepad axis 1 UP |
'| __ASSIGN_AXIS DOWNButton, __JOYPAD1INPUT, 1 ' joystick/gamepad axis 1 DOWN |
'| __ASSIGN_AXIS LEFTButton, __JOYPAD1INPUT, -2 ' joystick/gamepad axis 2 LEFT |
'| __ASSIGN_AXIS RIGHTButton, __JOYPAD1INPUT, 2 ' joystick/gamepad axis 2 RIGHT |
'| |
'| Handle - button handle |
'| cid - controller id (1-keyboard, 2-mouse, 3-joypad, etc..) |
'| Axis - controller axis number ( 1 to _LASTAXIS(id) ) |
'| the sign (+/-) of Axis determines which deflection direction will be used as a button press. |
'| Negative typically means UP or LEFT and positive typically means DOWN or RIGHT. |
'| |
'| NOTE: Once all four button slots are filled any attempt to associate a handle with more axis is ignored. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
SHARED CL_KEYNAME() AS STRING ' need access to _BUTTON keyboard key names
DIM Assigning AS TYPE__SLOT ' check slot UDT
DIM AssignedHandle AS INTEGER ' previously assigned button handle
DIM AssignedSlot AS INTEGER ' previously assigned button handle slot
DIM Aname AS STRING ' descriptive axis name
DIM Jname AS STRING ' joystick/game pad name
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__BUTTON_AXIS_ASSIGN"
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF ABS(Axis) < 1 OR ABS(Axis) > _LASTAXIS(cid) THEN __ERROR "The axis specified does not exist on controller."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-----------------------------------+
'| Check if axis is already assigned |
'+-----------------------------------+
Assigning.cid = cid ' set up check slot UDT
Assigning.Button = 0
Assigning.Axis = Axis
IF IUO__ALREADY_ASSIGNED(Assigning, AssignedHandle, AssignedSlot) THEN ' is this axis button already assigned?
'+-------------------------------------+
'| This axis has already been assigned |
'+-------------------------------------+
IF Handle = AssignedHandle THEN ' is this axis already assigned to this handle?
'+---------------------------------------------+
'| This axis is aleady assigned to this handle |
'+---------------------------------------------+
EXIT SUB ' yes, leave subroutine so duplicate is not made
ELSE ' no, this is a new valid assignment
IF CL_SETTINGS.Reassign THEN ' yes, is reassigning allowed?
'+-----------------------------------+
'| Reassigning of buttons is allowed |
'+-----------------------------------+
IF Handle = 0 OR CL_BUTTON(Handle).Slot1.cid = 0_
OR CL_BUTTON(Handle).Slot2.cid = 0_
OR CL_BUTTON(Handle).Slot3.cid = 0_
OR CL_BUTTON(Handle).Slot4.cid = 0 THEN ' yes, is there a slot available?
'+---------------------------------------------------------------+
'| This is either a new user assigned button or an existing user |
'| assigned button with a slot availabe so remove old assignment |
'+---------------------------------------------------------------+
__REMOVE_BUTTON AssignedHandle, AssignedSlot ' yes, remove previous button assignment
END IF
ELSE ' no, reassigning not allowed
'+---------------------------------------+
'| Reassigning of buttons is not allowed |
'+---------------------------------------+
EXIT SUB ' leave subroutine
END IF
END IF
END IF
'+----------------------------------------+
'| Create a descriptive name for the axis |
'+----------------------------------------+
Jname = "" ' clear joystick name
SELECT CASE cid ' which controller?
CASE __MOUSECID ' mouse
IF ABS(Axis) = 1 THEN ' is this axis 1?
IF SGN(Axis) = -1 THEN ' yes, up (negative)?
Aname = "Mouse Up" ' yes, create name
ELSE ' no, down (positive)
Aname = "Mouse Down" ' create name
END IF
ELSE ' no, this must be axis 2
IF SGN(Axis) = -1 THEN ' left (negative)?
Aname = "Mouse Left" ' yes, create name
ELSE ' no, right (positive)
Aname = "Mouse Right" ' create name
END IF
END IF
CASE __JOYPAD1CID: Jname = "J1" ' joystick/game pad 1
CASE __JOYPAD2CID: Jname = "J2" ' joystick/game pad 2
CASE __JOYPAD3CID: Jname = "J3" ' joystick/game pad 3
CASE __JOYPAD4CID: Jname = "J4" ' joystick/game pad 4
CASE __JOYPAD5CID: Jname = "J5" ' joystick/game pad 5
CASE __JOYPAD6CID: Jname = "J6" ' joystick/game pad 6
END SELECT
IF Jname <> "" THEN ' was a joystick name given?
'+-----------------------------------------+
'| The axis belongs to a joystick/game pad |
'+-----------------------------------------+
SELECT CASE ABS(Axis) ' yes, which axis?
CASE 1: IF SGN(Axis) = -1 THEN Aname = "A1 Left" ELSE Aname = "A1 Right" ' axis 1, left or right
CASE 2: IF SGN(Axis) = -1 THEN Aname = "A2 Up" ELSE Aname = "A2 Down" ' axis 2, up or down
CASE 3: IF SGN(Axis) = -1 THEN Aname = "A3 Left" ELSE Aname = "A3 Right" ' axis 3, left or right
CASE 4: IF SGN(Axis) = -1 THEN Aname = "A4 Up" ELSE Aname = "A4 Down" ' axis 4, up or down
END SELECT
Aname = Jname + Aname ' complete joystick name
END IF
'+-------------------------+
'| Save button information |
'+-------------------------+
Assigning.cid = cid ' set up button to save
Assigning.Button = 0
Assigning.Axis = Axis
Assigning.Name = Aname
Assigning.Cname = __CONTROLLER_NAME$(cid)
IF CL_BUTTON(Handle).Slot4.cid THEN ' 4 buttons/axis already assigned?
'+--------------------------------------------------------------------------+
'| There are no more available slots to assign another axis to this handle. |
'+--------------------------------------------------------------------------+
EXIT SUB ' yes, leave subroutine, no more room
ELSEIF CL_BUTTON(Handle).Slot3.cid THEN ' no, 3 buttons/axis already assigned?
CL_BUTTON(Handle).Slot4 = Assigning
ELSEIF CL_BUTTON(Handle).Slot2.cid THEN ' no, 2 buttons/axis already assigned?
CL_BUTTON(Handle).Slot3 = Assigning
ELSEIF CL_BUTTON(Handle).Slot1.cid THEN ' no, 1 button/axis already assigned?
CL_BUTTON(Handle).Slot2 = Assigning
ELSE ' no buttons/axis have been assigned yet
CL_BUTTON(Handle).Slot1 = Assigning
END IF
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __ASSIGN_BUTTON (Handle AS INTEGER, cid AS INTEGER, Button AS INTEGER) ' __ASSIGN_BUTTON |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Associates a handle with up to four buttons from the keyboard, mouse, or joypads. Simply call this subroutine up to four times to associate a |
'| new button to the handle. |
'| |
'| __ASSIGN_BUTTON FireButton, __KEYBOARDINPUT, CLKEY_SPACEBAR ' keyboard space bar (in first slot) |
'| __ASSIGN_BUTTON FireButton, __JOYPAD1INPUT, 1 ' joystick trigger (button 1) (in second slot) |
'| |
'| Handle - button handle |
'| cid - controller id (1-keyboard, 2-mouse, 3-joypad, etc..) |
'| Button - controller button number ( 1 to _LASTBUTTON(id) ) |
'| |
'| NOTE: Once all four button slots are filled any attempt to associate a handle with more buttons is ignored. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
SHARED CL_KEYNAME() AS STRING ' need access to _BUTTON keyboard key names
DIM Assigning AS TYPE__SLOT ' check slot UDT
DIM AssignedHandle AS INTEGER ' previously assigned button handle
DIM AssignedSlot AS INTEGER ' previously assigned button handle slot
DIM Bname AS STRING ' descriptive button name
'+------------------+
'| Check for errors |
'+------------------+
__CURRENT_ROUTINE = "__BUTTON_ASSIGN"
IF CL_CONTROLLER(cid).Found = 0 THEN __ERROR "The specified controller does not exist."
IF Button < 1 OR Button > _LASTBUTTON(cid) THEN __ERROR "The button specified does not exist on controller."
__PREVIOUS_ROUTINE = __CURRENT_ROUTINE
'+-------------------------------------+
'| Check if button is already assigned |
'+-------------------------------------+
Assigning.cid = cid ' set up check slot UDT
Assigning.Button = Button
Assigning.Axis = 0
IF IUO__ALREADY_ASSIGNED(Assigning, AssignedHandle, AssignedSlot) THEN ' is this button already assigned?
'+---------------------------------------+
'| This button has already been assigned |
'+---------------------------------------+
IF Handle = AssignedHandle THEN ' is this button already assigned to this handle?
'+-----------------------------------------------+
'| This button is aleady assigned to this handle |
'+-----------------------------------------------+
EXIT SUB ' yes, leave subroutine so duplicate is not made
ELSE ' no, this is a new valid assignment
IF CL_SETTINGS.Reassign THEN ' is reassigning allowed?
'+-----------------------------------+
'| Reassigning of buttons is allowed |
'+-----------------------------------+
IF Handle = 0 OR CL_BUTTON(Handle).Slot1.cid = 0_
OR CL_BUTTON(Handle).Slot2.cid = 0_
OR CL_BUTTON(Handle).Slot3.cid = 0_
OR CL_BUTTON(Handle).Slot4.cid = 0 THEN ' yes, is there a slot available?
'+---------------------------------------------------------------+
'| This is either a new user assigned button or an existing user |
'| assigned button with a slot availabe so remove old assignment |
'+---------------------------------------------------------------+
__REMOVE_BUTTON AssignedHandle, AssignedSlot ' yes, remove previous button assignment
END IF
ELSE ' no, reassigning not allowed
'+---------------------------------------+
'| Reassigning of buttons is not allowed |
'+---------------------------------------+
EXIT SUB ' leave subroutine
END IF
END IF
END IF
'+------------------------------------------+
'| Create a descriptive name for the button |
'+------------------------------------------+
SELECT CASE cid ' which controller?
CASE __KEYBOARDCID ' keyboard
Bname = CL_KEYNAME(Button) + " Key" ' create descriptive keyboard key name
CASE __MOUSECID ' mouse
IF Button = 1 THEN ' left button?
Bname = "Left Mouse" ' yes, create name
ELSEIF Button = 2 THEN ' no, middle button?
Bname = "Center Mouse" ' yes, create name
ELSE ' no, must be right button
Bname = "Right Mouse" ' create name
END IF
CASE __JOYPAD1CID: Bname = "J1B" + _TRIM$(STR$(Button)) ' joystick/game pad 1, create name
CASE __JOYPAD2CID: Bname = "J2B" + _TRIM$(STR$(Button)) ' joystick/game pad 2, create name
CASE __JOYPAD3CID: Bname = "J3B" + _TRIM$(STR$(Button)) ' joystick/game pad 3, create name
CASE __JOYPAD4CID: Bname = "J4B" + _TRIM$(STR$(Button)) ' joystick/game pad 4, create name
CASE __JOYPAD5CID: Bname = "J5B" + _TRIM$(STR$(Button)) ' joystick/game pad 5, create name
CASE __JOYPAD6CID: Bname = "J6B" + _TRIM$(STR$(Button)) ' joystick/game pad 6, create name
END SELECT
'+-------------------------+
'| Save button information |
'+-------------------------+
Assigning.cid = cid ' set up button to save
Assigning.Button = Button
Assigning.Axis = 0
Assigning.Name = Bname
Assigning.Cname = __CONTROLLER_NAME$(cid)
IF CL_BUTTON(Handle).Slot4.cid THEN ' 4 buttons/axis already assigned?
'+----------------------------------------------------------------------------+
'| There are no more available slots to assign another button to this handle. |
'+----------------------------------------------------------------------------+
EXIT SUB ' yes, leave subroutine, no more room
ELSEIF CL_BUTTON(Handle).Slot3.cid THEN ' no, 3 buttons/axis already assigned?
CL_BUTTON(Handle).Slot4 = Assigning
ELSEIF CL_BUTTON(Handle).Slot2.cid THEN ' no, 2 buttons/axis already assigned?
CL_BUTTON(Handle).Slot3 = Assigning
ELSEIF CL_BUTTON(Handle).Slot1.cid THEN ' no, 1 button/axis already assigned?
CL_BUTTON(Handle).Slot2 = Assigning
ELSE ' no buttons/axis have been assigned yet
CL_BUTTON(Handle).Slot1 = Assigning
END IF
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __IDENTIFY_CONTROLLERS () ' __IDENTIFY_CONTROLLERS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Finds all controllers (keyboard, mouse, gamepad, joystick) connected to the computer and polls them for information. |
'| |
'| __IDENTIFY_CONTROLLERS |
'| |
'| The following SHARED variables will be set with the controller's device id: |
'| __KEYBOARDCID - usually 1 if found, 0 otherwise |
'| __MOUSECID - usually 2 if found, 0 otherwise |
'| __JOYPAD1CID - usually 3 if found (typical: 1st game pad, 1st joystick, 1st flight yoke, 1st steering wheel) |
'| __JOYPAD2CID - usually 4 if found (typical: 2nd game pad, 2nd joystick, 2nd flight yoke, 1st rudder pedals, 1st gas/brake pedals) |
'| __JOYPAD3CID - usually 5 if found (typical: 3rd game pad, 3rd joystick, 3rd flight yoke, 2nd rudder pedals, 2nd steering wheel) |
'| __JOYPAD4CID - usually 6 if found (typical: 4th game pad, 4th joystick, 4th flight yoke, 2nd/3rd rudder pedals, 2nd/3rd gas/brake pedals) |
'| |
'| NOTE: The library will store the information for up to 6 controllers. This is typically 1 keyboard, 1 mouse, and up to four game pads and/or |
'| joysticks. The "typical:" devices listed above are what I experienced when plugging these devices into my system. Your configuration |
'| may vary wildly. If no keyboard or mouse is present it's possible to have up to six joysticks/game pads detected and stored. |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
SHARED CL_SETTINGS AS TYPE__SETTINGS ' need access to library settings
DIM Devices AS INTEGER ' number of controller devices connected to computer
DIM Device AS STRING ' description and properties of controller device
DIM cid AS INTEGER ' controller id loop counter
DIM Start AS INTEGER ' beginning position of device name
DIM Finish AS INTEGER ' ending position of device name
__KEYBOARDCID = 0 ' reset input controller identifiers
__MOUSECID = 0
__JOYPAD1CID = 0
__JOYPAD2CID = 0
__JOYPAD3CID = 0
__JOYPAD4CID = 0
__JOYPAD5CID = 0
__JOYPAD6CID = 0
Devices = _DEVICES ' get number of controllers connected to system
CL_SETTINGS.FoundDevices = Devices ' record number of devices initially found
cid = 0 ' reset controller counter
DO ' begin controller identification loop
cid = cid + 1 ' increment controller counter
IF cid <= Devices THEN ' was a controller found?
Device = _DEVICE$(cid) ' yes, get controller properties
CL_CONTROLLER(cid).Found = -1 ' mark this controller as found
IF INSTR(Device, "[KEYBOARD]") THEN ' is this a keyboard?
CL_CONTROLLER(cid).Name = "KEYBOARD" ' set a default descriptive name
__KEYBOARDCID = cid ' set keyboard's input controller id
END IF
IF INSTR(Device, "[MOUSE]") THEN ' is this a mouse?
CL_CONTROLLER(cid).Name = "MOUSE" ' set a default descriptive name
__MOUSECID = cid ' set mouse' input controller id
END IF
IF INSTR(Device, "[DISCONNECTED]") THEN ' is this controller disconnected?
CL_CONTROLLER(cid).Connected = 0 ' yes, mark controller as disconnected
ELSE ' no, controller is connected
CL_CONTROLLER(cid).Connected = -1 ' mark controller as connected
END IF
IF INSTR(Device, "[CONTROLLER]") THEN ' is this a game pad or joystick?
'+---------------------------------------------------------+
'| A generic name will be given to the joystick/game pad |
'| in the event the controller may not have a [NAME] field |
'| Note: controllers 5 and/or 6 will only exist if the |
'| keyboard and/or mouse are not connected |
'+---------------------------------------------------------+
IF __JOYPAD5CID THEN ' has joypad5's id already been set?
__JOYPAD6CID = cid ' yes, set joypad6's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD6" ' set a default descriptive name
ELSEIF __JOYPAD4CID THEN ' has joypad4's id already been set?
__JOYPAD5CID = cid ' yes, set joypad5's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD5" ' set a default descriptive name
ELSEIF __JOYPAD3CID THEN ' has joypad3's id already been set?
__JOYPAD4CID = cid ' yes, set joypad4's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD4" ' set a default descriptive name
ELSEIF __JOYPAD2CID THEN ' no, has joypad2's id already been set?
__JOYPAD3CID = cid ' yes, set joypad3's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD3" ' set a default descriptive name
ELSEIF __JOYPAD1CID THEN ' no, has joypad1's id already been set?
__JOYPAD2CID = cid ' yes, set joypad2's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD2" ' set a default descriptive name
ELSE ' no joypad ids set yet
__JOYPAD1CID = cid ' set joypad1's input controller id
CL_CONTROLLER(cid).Name = "JOYPAD1" ' set a default descriptive name
END IF
END IF
IF INSTR(Device, "[BUTTON]") THEN ' does this controller have buttons?
CL_CONTROLLER(cid).Buttons = _LASTBUTTON(cid) ' yes, record number of buttons controller has
ELSE ' no
CL_CONTROLLER(cid).Buttons = 0 ' record no buttons
END IF
IF INSTR(Device, "[AXIS]") THEN ' does this controller have axis inputs?
CL_CONTROLLER(cid).Axis = _LASTAXIS(cid) ' yes, record number of axis controller has
ELSE ' no
CL_CONTROLLER(cid).Axis = 0 ' record no axis
END IF
IF INSTR(Device, "[WHEEL]") THEN ' does this controller have wheels?
CL_CONTROLLER(cid).Wheels = _LASTWHEEL(cid) ' yes, record number of wheels controller has
ELSE ' no
CL_CONTROLLER(cid).Wheels = 0 ' record no wheels
END IF
IF INSTR(Device, "[NAME]") THEN ' is there a more descriptive name for this controller?
'+-------------------------------------------------------------+
'| Replace the generic name given with the controller's [NAME] |
'+-------------------------------------------------------------+
Start = INSTR(Device, "[NAME]") + 7 ' yes, get the start position of the name
Finish = INSTR(Start, Device, "]") ' get the end position of the name
CL_CONTROLLER(cid).Name = MID$(Device, Start, Finish - Start) ' extract and only use the descriptive name of the controller
END IF
ELSE ' no controller here
CL_CONTROLLER(cid) = CL_CONTROLLER(0) ' reset all controller settings
END IF
LOOP UNTIL cid = Devices OR cid = 6 ' leave when all controllers polled
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __INITIALIZE_CONTROLLERS () ' __INITIALIZE_CONTROLLERS |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Identify number and type of controllers and set initial variable values |
'| |
'| __INITIALIZE_CONTROLLERS |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_KEYNAME() AS STRING ' need access to _BUTTON keyboard key names
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to user assigned buttons
SHARED CL_CONTROLLER() AS TYPE__CONTROLLER ' need access to controller array
REDIM CL_BUTTON(1) AS TYPE__BUTTON ' clear user assigned buttons
DIM k AS INTEGER ' key counter
__KEYBOARDCID = 0 ' these will contain the device ids (_DEVICES)
__MOUSECID = 0
__JOYPAD1CID = 0
__JOYPAD2CID = 0
__JOYPAD3CID = 0
__JOYPAD4CID = 0
__JOYPAD5CID = 0
__JOYPAD6CID = 0
FOR k = 0 TO 6 ' clear controller array
CL_CONTROLLER(k).Found = 0
CL_CONTROLLER(k).Name = ""
CL_CONTROLLER(k).Buttons = 0
CL_CONTROLLER(k).Axis = 0
CL_CONTROLLER(k).Wheels = 0
NEXT k
__IDENTIFY_CONTROLLERS ' identify controllers attached to system
__SET_AXIS_THRESHOLD .5 ' set sensitivity of axis user defined button detection
__BUTTON_REASSIGN_ALLOWED ' allow user defined button reassignments
FOR k = 1 TO 350 ' read in names of keyboard controller keys
CL_KEYNAME(k) = "" ' clear key name
IF k < 90 THEN READ CL_KEYNAME(k) ' first 89 names are in data statements
IF k = 285 THEN READ CL_KEYNAME(k) ' 285, 90 through 284 are skipped
IF k = 286 THEN READ CL_KEYNAME(k) ' 286
IF k = 310 THEN READ CL_KEYNAME(k) ' 310, 287 through 309 are skipped
IF k > 325 THEN READ CL_KEYNAME(k) ' 326 through 350 are in data statements
NEXT k
'Keyboard _BUTTON 1 - 20
DATA "","Escape","1","2","3","4","5","6","7","8","9","0","Minus","Equals","Backspace","Tab","Q","W","E","R"
'Keyboard _BUTTON 21 - 40
DATA "T","Y","U","I","O","P","Left Bracket","Right Bracket","Enter","Left CTRL","A","S","D","F","G","H","J","K","L","Semicolon"
'Keyboard _BUTTON 41 - 50
DATA "Quote","","Left Shift","Back Slash","Z","X","C","V","B","N"
'Keyboard _BUTTON 51 - 60
DATA "M","Comma","Period","Fore Slash","Right Shift","Numpad Multiply","","Space Bar","Caps Lock","F1"
'Keyboard _BUTTON 61 - 70
DATA "F2","F3","F4","F5","F6","F7","F8","F9","","Pause"
'Keyboard _BUTTON 71 - 80
DATA "Scroll Lock","Numpad 7","Numpad 8","Numpad 9","Numpad Minus","Numpad 4","Numpad 5","Numpad 6","Numpad Plus","Numpad 1"
'Keyboard _BUTTON 81 - 89
DATA "Numpad 2","Numpad 3","Numpad 0","Numpad Period","","","","F11","F12"
'Keyboard _BUTTON 285 - 286
DATA "Numpad Enter","Right CTRL"
'Keyboard _BUTTON 310
DATA "Numpad Divide"
'Keyboard _BUTTON 326 - 340
DATA "Number Lock","","Home","UP Arrow","Page UP","","LEFT Arrow","","RIGHT Arrow","","End","DOWN Arrow","Page Down","Insert","Delete"
'Keyboard _BUTTON 341 - 350
DATA "","","","","","","","Left Win","Right Win","Menu"
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
SUB __ERROR (Message AS STRING) ' __ERROR |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Set screen to text mode and display error information passed in. |
'| |
'| __ERROR "Message" |
'| |
'| NOTE: Fatal error trap - halts program execution. |
'\_______________________________________________________________________________________________________________________________________________/
_FULLSCREEN _OFF ' turn off full screen if active
SCREEN 0, 0, 0, 0 ' set screen to pure text mode
CLS ' clear screen
PLAY "l64o3ao2ao1ao3ao2ao1ao3ao2ao1a" ' get developer's attention
COLOR 12, 0
PRINT ' print error message
PRINT " Controller Library has encountered the following error condition:"
COLOR 15, 0
PRINT
PRINT " Error in routine: ";
COLOR 14, 0
PRINT __CURRENT_ROUTINE
COLOR 15, 0
PRINT " Previous routine: ";
COLOR 14, 0
PRINT __PREVIOUS_ROUTINE
COLOR 11, 0
PRINT
PRINT " "; Message
COLOR 7, 0
_KEYCLEAR ' clear all key buffers
END ' terminate with "Press any key to continue..."
END SUB
' ______________________________________________________________________________________________________________________________________________
'/ \
FUNCTION IUO__ALREADY_ASSIGNED (Button AS TYPE__SLOT, Handle AS INTEGER, Slot AS INTEGER) ' IUO__ALREADY_ASSIGNED |
' __________________________________________________________________________________________________________________________________________|____
'/ \
'| Returns -1 (TRUE) if a button is already assigned, 0 (FALSE) otherwise. |
'| |
'| IF IUO__ALREADY_ASSIGNED(Assigning, HandleFound, SlotFound) |
'| |
'| Button - the new button being assigned |
'| Handle - the button handle that already contains this assignment |
'| Slot - the slot number that already contains this assignment |
'| |
'| NOTE: IUO - Internal Use Only |
'\_______________________________________________________________________________________________________________________________________________/
SHARED CL_BUTTON() AS TYPE__BUTTON ' need access to button array
IUO__ALREADY_ASSIGNED = 0 ' assume button is not preassigned
Handle = 0 ' reset button handle
Slot = 0 ' reset slot number
DO ' begin assignment search
Handle = Handle + 1 ' increment handle counter
IF CL_BUTTON(Handle).Slot1.cid = Button.cid THEN ' do the controller ids match in slot 1?
IF CL_BUTTON(Handle).Slot1.Button = Button.Button THEN ' yes, do the buttons match?
IF CL_BUTTON(Handle).Slot1.Axis = Button.Axis THEN ' yes, do the axes match?
Slot = 1 ' yes, slot 1 already has this button assigned
END IF
END IF
END IF
IF CL_BUTTON(Handle).Slot2.cid = Button.cid THEN
IF CL_BUTTON(Handle).Slot2.Button = Button.Button THEN
IF CL_BUTTON(Handle).Slot2.Axis = Button.Axis THEN
Slot = 2 ' slot 2 already has this button assigned
END IF
END IF
END IF
IF CL_BUTTON(Handle).Slot3.cid = Button.cid THEN
IF CL_BUTTON(Handle).Slot3.Button = Button.Button THEN
IF CL_BUTTON(Handle).Slot3.Axis = Button.Axis THEN
Slot = 3 ' slot 3 already has this button assigned
END IF
END IF
END IF
IF CL_BUTTON(Handle).Slot4.cid = Button.cid THEN
IF CL_BUTTON(Handle).Slot4.Button = Button.Button THEN
IF CL_BUTTON(Handle).Slot4.Axis = Button.Axis THEN
Slot = 4 ' slot 4 already has this button assigned
END IF
END IF
END IF
LOOP UNTIL (Handle = UBOUND(CL_BUTTON)) OR Slot ' leave when all checked or a slot contains assignment
IF Slot THEN IUO__ALREADY_ASSIGNED = -1 ' report button already assigned
END FUNCTION
Code: (Select All) '$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 1
' Creating user defined buttons that include keyboard keys and joystick axes
'
' Use the keyboard ARROW keys, keyboard WASD keys, or Joystick 1 to move the circle around the screen
'
' Terry Ritchie
' April 11th, 2023 - initial release
' May 17th, 2023 - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------
DIM UP_Button AS INTEGER ' user defined button handles with up to four associated controller buttons and/or axes
DIM DOWN_Button AS INTEGER
DIM LEFT_Button AS INTEGER
DIM RIGHT_Button AS INTEGER
DIM x AS INTEGER ' circle x location
DIM y AS INTEGER ' circle y location
__INITIALIZE_CONTROLLERS ' initialize controller library
__MAKE_BUTTON UP_Button
__MAKE_BUTTON DOWN_Button
__MAKE_BUTTON LEFT_Button
__MAKE_BUTTON RIGHT_Button
'+----------------------------------------------------------------------------------+
'| Assign keyboard ARROW keys, WASD keys, and joystick 1 to the four button handles |
'+----------------------------------------------------------------------------------+
__ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_UP ' keyboard UP ARROW key assigned to UP_Button [SLOT1]
__ASSIGN_BUTTON UP_Button, __KEYBOARDCID, CLKEY_W ' Keyboard W key also assigned to UP_Button [SLOT2]
__ASSIGN_AXIS UP_Button, __JOYPAD1CID, -2 ' joystick vertical axis UP (-) also assigned to UP_Button [SLOT3]
__ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_DOWN ' keyboard DOWN ARROW key assigned to DOWN_Button [SLOT1]
__ASSIGN_BUTTON DOWN_Button, __KEYBOARDCID, CLKEY_S ' keyboard S key also assigned to DOWN_Button [SLOT2]
__ASSIGN_AXIS DOWN_Button, __JOYPAD1CID, 2 ' joystick vertical axis DOWN (+) also assigned to DOWN_Button [SLOT3]
__ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_LEFT ' keyboard LEFT ARROW key assigned to LEFT_Button [SLOT1]
__ASSIGN_BUTTON LEFT_Button, __KEYBOARDCID, CLKEY_A ' keyboard A key also assigned to LEFT_Button [SLOT2]
__ASSIGN_AXIS LEFT_Button, __JOYPAD1CID, -1 ' joystick horizontal axis LEFT (-) also assigned to LEFT_Button [SLOT3]
__ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_RIGHT ' keyboard RIGHT ARROW key assigned to RIGHT_Button [SLOT1]
__ASSIGN_BUTTON RIGHT_Button, __KEYBOARDCID, CLKEY_D ' keyboard D key also assigned to RIGHT_Button [SLOT2]
__ASSIGN_AXIS RIGHT_Button, __JOYPAD1CID, 1 ' joystick horizontal axis RIGHT (+) also asigned to RIGHT_Button [SLOT3]
SCREEN _NEWIMAGE(640, 480, 32)
x = 319
y = 239
DO
_LIMIT 30
CLS
LOCATE 2, 1
PRINT " Controller Library Demo 1"
PRINT " Use ARROW keys, WASD keys, or Joystick 1"
PRINT " ESC to exit"
IF __BUTTON_DOWN(UP_Button) THEN y = y - 5 ' press UP ARROW key, W key, or move joystick UP
IF __BUTTON_DOWN(DOWN_Button) THEN y = y + 5 ' press DOWN ARROW key, S key, or move joystick DOWN
IF __BUTTON_DOWN(LEFT_Button) THEN x = x - 5 ' press LEFT ARROW key, A key, or move joystick LEFT
IF __BUTTON_DOWN(RIGHT_Button) THEN x = x + 5 ' press RIGHT ARROW key, D key, or move joystick RIGHT
CIRCLE (x, y), 30
_DISPLAY
LOOP UNTIL _KEYDOWN(27) ' exit when ESC pressed
SYSTEM
'$INCLUDE:'CONTROLLER.BM'
Code: (Select All) '$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 2
' Remapping joystick axes
'
' Use Joystick 1 to move the circle around the screen
'
' Terry Ritchie
' April 11th, 2023 - original release
' May 17th, 2023 - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------
__INITIALIZE_CONTROLLERS ' initialize controller library
SCREEN _NEWIMAGE(640, 480, 32)
DO
_LIMIT 30
CLS
LOCATE 2, 1
PRINT " Controller Library Demo 2"
PRINT " Use Joystick 1"
PRINT " ESC to exit"
x = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 1), 0, 639) ' joystick 1 axis now 0 to 639
y = __MAP_AXIS(__CONTROLLER_AXIS(__JOYPAD1CID, 2), 0, 479) ' joystick 2 axis now 0 to 479
CIRCLE (x, y), 30
_DISPLAY
LOOP UNTIL _KEYDOWN(27) ' exit when ESC pressed
SYSTEM
'$INCLUDE:'CONTROLLER.BM'
Code: (Select All) '$INCLUDE:'CONTROLLER.BI'
'----------------------------------------------------------------------------------------------------
' Controller Library Example 3
' Polling controllers for information
'
' Reports information on all controllers found.
'
' Terry Ritchie
' April 11th, 2023 - original release
' May 17th, 2023 - updated to use Controller Library v1.10
'----------------------------------------------------------------------------------------------------
__INITIALIZE_CONTROLLERS ' initialize controller library
DIM Joysticks AS INTEGER
DIM Format AS STRING
DIM j AS INTEGER
DIM jid AS INTEGER
Joysticks = __JOYPAD_EXISTS(1)
Format = " | # | \ \ | ### | ## |"
CLS
PRINT
PRINT " ___________________________________________________________________"
PRINT " / CONTROLLERS FOUND CONNECTED TO YOUR COMPUTER \"
PRINT " |----------------+---------------------------------+---------+------|"
PRINT " | CONTROLLER ID | CONTROLLER NAME | BUTTONS | AXES |"
PRINT " |----------------+---------------------------------+---------+------|"
IF __KEYBOARD_EXISTS THEN PRINT USING Format; __KEYBOARDCID; __CONTROLLER_NAME$(__KEYBOARDCID); __BUTTON_TOTAL(__KEYBOARDCID); 0
PRINT " |----------------+---------------------------------+---------+------|"
IF __MOUSE_EXISTS THEN PRINT USING Format; __MOUSECID; __CONTROLLER_NAME$(__MOUSECID); __BUTTON_TOTAL(__MOUSECID); __AXIS_TOTAL(__MOUSECID)
FOR j = 1 TO Joysticks
SELECT CASE j
CASE 1: jid = __JOYPAD1CID
CASE 2: jid = __JOYPAD2CID
CASE 3: jid = __JOYPAD3CID
CASE 4: jid = __JOYPAD4CID
CASE 5: jid = __JOYPAD5CID
CASE 6: jid = __JOYPAD6CID
END SELECT
PRINT " |----------------+---------------------------------+---------+------|"
PRINT USING Format; jid; __CONTROLLER_NAME$(jid); __BUTTON_TOTAL(jid); __AXIS_TOTAL(jid)
NEXT j
PRINT " \________________|_________________________________|_________|______/"
PRINT
PRINT " Press ESC to exit"
SLEEP
SYSTEM
'$INCLUDE:'CONTROLLER.BM'
RE: Controller Library - TempodiBasic - 04-13-2023
Hi Terry
fine to see another your masterpiece tool
this is demo1 screenshot
this comes out running Demo2
and this is the result of demo3
What to say: wonderful library!
Thanks to share it.
I hope to see many games using Controller Library for managing easily the input dispositives.
RE: Controller Library - TerryRitchie - 04-13-2023
Thank you for trying it out. Let me know if you find anything that needs addressed. I'll get to adding wheel support in a bit as soon as I figure out why my code isn't working.
RE: Controller Library - OldMoses - 04-16-2023
I love the look of the code, with those ASCII picture comments of the keyboard. Cool stuff there, I've always been impressed by how you comment your code.
RE: Controller Library - TerryRitchie - 04-17-2023
(04-16-2023, 04:35 PM)OldMoses Wrote: I love the look of the code, with those ASCII picture comments of the keyboard. Cool stuff there, I've always been impressed by how you comment your code.
Thank you. My comments are just as much for me as they are for others reading my code (probably more for me as I get older!). As every coder knows going back to code you've written a few years back, heck sometimes even a few months back, can make you ponder, "What the heck was I thinking there?"
It only takes a few more minutes to document code well and you'll thank yourself in the long term. I can go back to any of my old code and find routines and methods I want to reuse without having to spend hours studying the code to re-learn what I already did.
It's hard to get into the habit of commenting but now I find I like writing the comments just as much as writing the code. I'm so used to it that it feels strange to me not to comment now.
When I was in the Marine Corps I had a 4 month gap between deployments. A three month 300 level advanced course in x86 Assembler at the base college just so happened to be starting. The professor (wish I could remember his name) commented his code so well you could read it like a book and know exactly what was going on. That's when I decided commenting was just as important as coding. Commenting is an absolute must in Assembler.
RE: Controller Library - OldMoses - 04-17-2023
My commenting style is constantly in flux as I refine my coding skills and procedures, but yours has been a strong influence in what I've tried to incorporate in my code. My magnum opus project, being an almost 6K line behemoth, I decided to make commenting a central part of it. I couldn't possibly begin to work on it after a hiatus without those reminders. Sometimes I spend entire coding sessions tearing out and revising just the comments. Sounds a bit pedantic and wasteful perhaps, but I've heard of worse in some projects, and just occasionally I'll see optimization opportunities in the code while doing it.
RE: Controller Library - TerryRitchie - 04-26-2023
I created a small simulated game that allows the player to reconfigure buttons as a demo to show others how this can be done. The program source code below along with the assets (sounds, graphics, and library files) are now included with the library. I updated the first post with a new ZIP file that you can download.
Also, the library is now at version 1.01. I found some bone head logic mistakes I made and corrected them.
Code: (Select All) '------------------------------
' Controller Library Demo
' "Reconfiguring Buttons"
'
' Terry Ritchie
' April 26th, 2023
'------------------------------
' Default Keys:
'
' W - UP (Mario JUMP)
' S - DOWN (Mario CROUCH)
' A - Mario LEFT
' D - Mario RIGHT
' C - Mario CROUCH
' SPACE - Mario JUMP
' RCTRL - Mario FIRE
' RSHIFT - Mario RUN
'
' Hitting mystery box on bottom
' releases coins.
'
'------------------------------
'$INCLUDE:'CONTROLLER.BI'
OPTION _EXPLICIT ' all variables must be explicitly defined
CONST STAND = 1 ' action sprites - Standing
CONST CROUCH = 2 ' crouching
CONST RUNSTART = 3 ' get ready to run
CONST WALK = 4 ' walking/running (6 animation images)
CONST JUMP = 5 ' jumping
CONST FIRE = 6 ' bullet sprites (4 animation images)
CONST COIN = 7 ' coin sprite
TYPE TYPE_RECTANGLE ' RECTANGLE PROPERTIES
x1 AS INTEGER ' upper left x
y1 AS INTEGER ' upper left y
x2 AS INTEGER ' lower right x
y2 AS INTEGER ' lower right y
END TYPE
TYPE TYPE_BUTTON ' DEFINED BUTTON PROPERTIES
UP AS INTEGER ' UP button(s)
DOWN AS INTEGER ' DOWN button(s)
RIGHT AS INTEGER ' RIGHT button(s)
LEFT AS INTEGER ' LEFT buttons(s)
FIRE AS INTEGER ' FIRE button(s)
RUN AS INTEGER ' RUN button(s)
JUMP AS INTEGER ' JUMP button(s)
CROUCH AS INTEGER ' CROUCH button(s)
F1 AS INTEGER ' F1 button (key - enter config mode)
F2 AS INTEGER ' F2 button (key - reset button defaults)
F3 AS INTEGER ' F3 button (key - leave config mode)
END TYPE
TYPE TYPE_MARIO ' MARIO PROPERTIES
x AS SINGLE ' x location (center bottom)
y AS SINGLE ' y location (center bottom)
Frame AS INTEGER ' animation frame
Action AS INTEGER ' STAND, CROUCH, RUNSTART, WALK, JUMP
Rect AS TYPE_RECTANGLE ' sprite image location
FPS AS INTEGER ' mario animation update speed
Direction AS INTEGER ' direction mario is traveling
Speed AS INTEGER ' speed of mario (walking or running)
Facing AS INTEGER ' direction mario is facing
Jumping AS INTEGER ' mario currently jumping (t/f)
Running AS INTEGER ' mario currently running (t/f)
Walking AS INTEGER ' mario currently walking (t/f)
RunTimer AS INTEGER ' period to show ready to run image
Yvel AS SINGLE ' y velocity of mario jump
Vector AS SINGLE ' y vector of mario jump
Floor AS INTEGER ' lowest point on screen mario can go
END TYPE
TYPE TYPE_BULLET ' BULLET PROPERTIES
InUse AS INTEGER ' this bullet currently active (t/f)
x AS SINGLE ' x coordinate of bullet
y AS SINGLE ' y coordinate of bullet
Direction AS INTEGER ' direction bullet is traveling
Cell AS INTEGER ' current bullet animation cell
END TYPE
TYPE TYPE_COIN ' COIN PROPERTIES
InUse AS INTEGER ' this coin currently active (t/f)
y AS SINGLE ' y coordinate of coin
vector AS SINGLE ' y vector of coin
END TYPE
'+------------------------------+
'| Program variable definitions |
'+------------------------------+
REDIM Bullets(1) AS TYPE_BULLET ' bullet array
REDIM Coins(1) AS TYPE_COIN ' coin array
DIM Button AS TYPE_BUTTON ' player buttons
DIM WorkScreen AS LONG ' graphics drawn here
DIM BackGround AS LONG ' static background image
DIM Sprite(7, 6) AS LONG ' mario sprite image pool
DIM Mario AS TYPE_MARIO ' mario properties
DIM Box AS TYPE_RECTANGLE ' mystery box coordinates
DIM MysteryBox AS LONG ' mystery box image
DIM FPSFrame AS INTEGER ' current frame (1 to 30)
DIM BulletTimer AS INTEGER ' time to wait between bullets
DIM SNDBump AS LONG ' bump sound
DIM SNDCoin AS LONG ' coin sound
DIM SNDConf AS LONG ' configuration screen sound
DIM SNDFire AS LONG ' bullet firing sound
DIM SNDJump AS LONG ' jump sound
DIM SNDSong AS LONG ' theme song
'______________________________________________________________________________________________________________________
'+---------------+
'| Program setup |
'+---------------+
__INITIALIZE_CONTROLLERS ' controller library initialize
SET_DEFAULT_BUTTONS ' set default input buttons
LOAD_ASSETS ' load demo graphics and sounds
INITIALIZE_VARIABLES ' initialize demo variables
SCREEN _NEWIMAGE(640, 480, 32) ' create view screen
_SNDLOOP SNDSong ' play theme song
'+--------------------------+
'| Main program loop begins |
'+--------------------------+
DO ' begin demo loop
_LIMIT 30 ' 30 frames per second
IF __BUTTON_DOWN(Button.F1) THEN ' player press F1 key?
CONFIGURE_BUTTONS ' yes, configure buttons
END IF
UPDATE_MARIO ' update mario position
DRAW_SCREEN ' draw demo screen
MOVE_MARIO ' check for player inputs
LOOP UNTIL _KEYDOWN(27) ' leave demo when ESC pressed
'+-------------------------------+
'| Free assets from RAM and exit |
'+-------------------------------+
CLEANUP ' remove all assets from memory
SYSTEM ' return to OS
'______________________________________________________________________________________________________________________
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB CONFIGURE_BUTTONS () ' CONFIGURE_BUTTONS |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Allows player to reconfigure keyboard keys, joystick/game pad buttons, and joystick/game pad axes as buttons. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Button AS TYPE_BUTTON ' need access to buttons
SHARED SNDSong AS LONG ' need access to theme song
SHARED SNDConf AS LONG ' need access to configure sound
DIM Menu(8) AS STRING ' horizontal line of menu text
DIM MenuLine AS INTEGER ' current highlighted menu line
DIM CreateMenu AS INTEGER ' -1 when menu needs recreating
DIM m AS INTEGER ' menu counter
DIM s AS INTEGER ' slot counter
DIM KeyHit AS INTEGER ' player keyboard input using _KEYHIT
DIM Hit AS INTEGER ' player keyboard input using INKEY$
__SET_AXIS_THRESHOLD .9 ' set axis threshold to register as a button press
__BUTTON_REASSIGN_ALLOWED ' allow reassigning of buttons
_SNDSTOP SNDSong ' stop theme song
_SNDPLAY SNDConf ' play configure sound
MenuLine = 1 ' highlight starts on line 1
CreateMenu = -1 ' menu needs creating
DO ' begin main loop
_LIMIT 30 ' don't hog the CPU
CLS , _RGB32(92, 148, 252) ' clear screen with light blue
IF __BUTTON_DOWN(Button.F2) THEN ' was F2 key pressed?
SET_DEFAULT_BUTTONS ' yes, set all buttons to default values
CreateMenu = -1 ' menu needs recreated
_SNDPLAY SNDConf ' play configure sound
END IF
IF CreateMenu THEN ' does menu need (re)created?
CreateMenu = 0 ' yes, reset creation flag
Menu(1) = " UP " ' create beginning of each menu item
Menu(2) = " DOWN "
Menu(3) = " LEFT "
Menu(4) = " RIGHT "
Menu(5) = " JUMP "
Menu(6) = " FIRE "
Menu(7) = " RUN "
Menu(8) = " CROUCH "
FOR s = 1 TO 4 ' cycle through 4 slots
Menu(1) = Menu(1) + " " + __BUTTON_NAME$(Button.UP, s) + " " ' add assigned button names to each menu line
Menu(2) = Menu(2) + " " + __BUTTON_NAME$(Button.DOWN, s) + " "
Menu(3) = Menu(3) + " " + __BUTTON_NAME$(Button.LEFT, s) + " "
Menu(4) = Menu(4) + " " + __BUTTON_NAME$(Button.RIGHT, s) + " "
Menu(5) = Menu(5) + " " + __BUTTON_NAME$(Button.JUMP, s) + " "
Menu(6) = Menu(6) + " " + __BUTTON_NAME$(Button.FIRE, s) + " "
Menu(7) = Menu(7) + " " + __BUTTON_NAME$(Button.RUN, s) + " "
Menu(8) = Menu(8) + " " + __BUTTON_NAME$(Button.CROUCH, s) + " "
NEXT s
END IF
COLOR _RGB32(255, 255, 0), _RGB32(0, 0, 255) ' yellow text on blue background
_PRINTMODE _FILLBACKGROUND ' show the background color
LOCATE 2, 25 ' position cursor
PRINT " " ' print header
LOCATE 3, 25
PRINT " CONFIGURE CONTROLLER INPUTS "
LOCATE 4, 25
PRINT " "
LINE (192, 16)-(423, 63), _RGB32(255, 255, 0), B ' draw a box around header
COLOR _RGB32(0, 0, 0) ' black text
_PRINTMODE _KEEPBACKGROUND ' transparent text background
LOCATE 6, 6 ' draw input instructions
PRINT "UP/DOWN: Select Action DEL: Remove Button F2: Reset Defaults"
LOCATE 7, 6
PRINT "ENTER : Configure Button F3: Return to Game"
LOCATE 9, 1
PRINT
PRINT " ACTION METHOD 1 METHOD 2 METHOD 3 METHOD 4 "
PRINT
FOR m = 1 TO 8 ' cycle through 8 menu lines
PRINT " ";
IF m = MenuLine THEN ' is this menu line highlighted?
COLOR _RGB32(255, 255, 0), _RGB32(0, 0, 255) ' yes, yellow text on blue background
_PRINTMODE _FILLBACKGROUND ' show the background color
END IF
PRINT Menu(m) ' print the menu line
COLOR _RGB32(0, 0, 0) ' black text
_PRINTMODE _KEEPBACKGROUND ' transparent text background
PRINT
NEXT m
FOR m = 135 TO 391 STEP 32 ' draw grid lines around menu items
LINE (8, m)-(632, m + 32), _RGB32(0, 0, 0), B
NEXT m
LINE (83, 135)-(83, 423), _RGB32(0, 0, 0)
LINE (219, 135)-(219, 423), _RGB32(0, 0, 0)
LINE (355, 135)-(355, 423), _RGB32(0, 0, 0)
LINE (491, 135)-(491, 423), _RGB32(0, 0, 0)
KeyHit = _KEYHIT ' get any key pressed by player
IF KeyHit = 18432 THEN ' was the UP ARROW key pressed?
MenuLine = MenuLine - 1 ' yes, move highlight up one line
IF MenuLine = 0 THEN MenuLine = 1 ' keep highlight at top if necessary
ELSEIF KeyHit = 20480 THEN ' no, was the DOWN ARROW key pressed?
MenuLine = MenuLine + 1 ' yes, move highlight down one line
IF MenuLine = 9 THEN MenuLine = 8 ' keep highlight at bottom if necessary
ELSEIF KeyHit = 21248 THEN ' no, was the DELETE key pressed?
COLOR _RGB32(255, 255, 0), _RGB32(255, 0, 0) ' yes, yellow text on red background
_PRINTMODE _FILLBACKGROUND ' show the background color
LOCATE 29, 15 ' position cursor
PRINT " PRESS 1, 2, 3, or 4 TO REMOVE METHOD FROM ACTION "; ' display instructions
_DISPLAY ' update screen to show instructions
DO ' begin key press loop
_LIMIT 30 ' don't hog the CPU
Hit = VAL(INKEY$) ' get value of any key pressed
LOOP UNTIL Hit ' leave when value not equal to zero
IF Hit >= 1 AND Hit <= 4 THEN ' is value between 1 and 4?
CreateMenu = -1 ' yes, the menu will need recreated
SELECT CASE MenuLine ' which menu line is highlighted?
CASE 1 ' line 1
__REMOVE_BUTTON Button.UP, Hit ' remove button from chosen slot
CASE 2 ' line 2
__REMOVE_BUTTON Button.DOWN, Hit ' remove button from chosen slot
CASE 3 ' line 3
__REMOVE_BUTTON Button.LEFT, Hit ' etc..
CASE 4
__REMOVE_BUTTON Button.RIGHT, Hit
CASE 5
__REMOVE_BUTTON Button.JUMP, Hit
CASE 6
__REMOVE_BUTTON Button.FIRE, Hit
CASE 7
__REMOVE_BUTTON Button.RUN, Hit
CASE 8
__REMOVE_BUTTON Button.CROUCH, Hit
END SELECT
_SNDPLAY SNDConf ' play configure sound
END IF
_KEYCLEAR ' clear all keyboard buffers
ELSEIF KeyHit = 13 THEN ' no, was the ENTER key pressed?
COLOR _RGB32(255, 255, 0), _RGB32(255, 0, 0) ' yes, yellow text on red background
_PRINTMODE _FILLBACKGROUND ' show background color
LOCATE 29, 12 ' position cursor
PRINT " SELECT KEYBOARD KEY, JOYSTICK AXIS, OR JOYSTICK BUTTON "; ' display instructions
_DISPLAY ' update display to show instructions
CreateMenu = -1 ' the menu will need recreated
SELECT CASE MenuLine ' which menu line is highlighted?
CASE 1 ' line 1
__AUTOASSIGN_BUTTON Button.UP ' assign button/axis to UP button
CASE 2 ' line 2
__AUTOASSIGN_BUTTON Button.DOWN ' assign button/axis to DOWN button
CASE 3 ' line 3
__AUTOASSIGN_BUTTON Button.LEFT ' etc..
CASE 4
__AUTOASSIGN_BUTTON Button.RIGHT
CASE 5
__AUTOASSIGN_BUTTON Button.JUMP
CASE 6
__AUTOASSIGN_BUTTON Button.FIRE
CASE 7
__AUTOASSIGN_BUTTON Button.RUN
CASE 8
__AUTOASSIGN_BUTTON Button.CROUCH
END SELECT
_SNDPLAY SNDConf ' play configure sound
END IF
_DISPLAY ' update screen with changes
LOOP UNTIL __BUTTON_DOWN(Button.F3) ' leave when F3 key pressed
_SNDLOOP SNDSong ' start theme song again
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB CLEANUP () ' CLEANUP |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Removes all sounds and graphics from RAM. (Always clean up after yourself before exiting program) |
'\______________________________________________________________________________________________________________________________________________/
SHARED Sprite() AS LONG ' need access to sprite images
SHARED WorkScreen AS LONG ' need access to work screen
SHARED BackGround AS LONG ' need access to background image
SHARED MysteryBox AS LONG ' need access to mystery box image
SHARED SNDBump AS LONG ' need access to all sounds
SHARED SNDCoin AS LONG
SHARED SNDConf AS LONG
SHARED SNDFire AS LONG
SHARED SNDJump AS LONG
SHARED SNDSong AS LONG
DIM i AS INTEGER ' generic counter
DIM j AS INTEGER ' generic counter
SCREEN 0, 0, 0, 0 ' go to pure text screen
CLS ' clear screen
_SNDCLOSE SNDBump ' remove sounds from RAM
_SNDCLOSE SNDCoin
_SNDCLOSE SNDFire
_SNDCLOSE SNDJump
_SNDCLOSE SNDSong
_SNDCLOSE SNDConf
_FREEIMAGE WorkScreen ' remove images from RAM
_FREEIMAGE BackGround
_FREEIMAGE MysteryBox
FOR i = 1 TO 7
FOR j = 1 TO 6
IF Sprite(i, j) THEN _FREEIMAGE Sprite(i, j) ' remove sprite images from RAM
NEXT j
NEXT i
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB SPAWN_COIN () ' SPAWN_COIN |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Spawns a coin. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Coins() AS TYPE_COIN ' need access to coin array
SHARED Box AS TYPE_RECTANGLE ' need access to mystery box coordinates
SHARED SNDCoin AS LONG ' need access to coin sound
DIM c AS INTEGER ' coin counter
c = 0 ' reset coin counter
DO ' loop through coin array
c = c + 1 ' increment coin counter
LOOP UNTIL Coins(c).InUse = 0 OR c = UBOUND(Coins) ' leave when array scannded
IF Coins(c).InUse THEN ' if index in use then all indexes used
c = c + 1 ' increment coin counter
REDIM _PRESERVE Coins(c) AS TYPE_COIN ' increase size of coin array
END IF
_SNDPLAY SNDCoin ' play coin sound
Coins(c).InUse = -1 ' mark this index in use
Coins(c).y = Box.y1 + 7 ' calculate y coordinate of coin
Coins(c).vector = -5 ' set initial vertical vector
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB UPDATE_COINS () ' UPDATE_COINS |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Updates the position of active coins and draws them to the screen. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Sprite() AS LONG ' need access to sprite images
SHARED Coins() AS TYPE_COIN ' need access to coin array
SHARED Box AS TYPE_RECTANGLE ' need access to mystery box coordinates
DIM c AS INTEGER ' coin counter
c = 0 ' reset coin counter
DO ' loop through coin array
c = c + 1 ' increment coin counter
IF Coins(c).InUse THEN ' is this coin in use?
Coins(c).y = Coins(c).y + Coins(c).vector ' yes, update coin y coordinate
Coins(c).vector = Coins(c).vector * .91 ' decrease vertical vector amount slightly
_PUTIMAGE (Box.x1, Coins(c).y), Sprite(COIN, 1) ' draw coin to screen
IF Coins(c).y < 1 THEN Coins(c).InUse = 0 ' deactivate coin when it reaches top of screen
END IF
LOOP UNTIL c = UBOUND(Coins) ' leave when array scanned
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB DRAW_SCREEN () ' DRAW_SCREEN |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Brings all the components together to create one frame of the demo. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Sprite() AS LONG ' need access to sprite images
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED WorkScreen AS LONG ' need access to the work screen
SHARED BackGround AS LONG ' need access to the background image
SHARED MysteryBox AS LONG ' need access to the mystery box image
'+--------------------+
'| Update view screen |
'+--------------------+
_DEST WorkScreen ' draw on work screen
_PUTIMAGE , BackGround, WorkScreen ' erase work screen with background
_PRINTMODE _KEEPBACKGROUND ' transparent text background
LOCATE 1, 6 ' position cursor
COLOR _RGB32(0, 0, 0) ' black text
PRINT "PRESS F1 TO CONFIGURE BUTTONS" ' print instructions
IF Mario.Facing = -1 THEN ' is mario facing left?
_PUTIMAGE (Mario.Rect.x2, Mario.Rect.y1)-(Mario.Rect.x1, Mario.Rect.y2), Sprite(Mario.Action, Mario.Frame) ' yes, flip sprite horizontally
ELSE ' no, mario is facing right
_PUTIMAGE (Mario.Rect.x1, Mario.Rect.y1), Sprite(Mario.Action, Mario.Frame) ' draw sprite as drawn
END IF
UPDATE_BULLETS ' draw active bullets
UPDATE_COINS ' draw active coins
_PUTIMAGE (144, 48), MysteryBox ' draw mystery box
_DEST 0 ' draw on view screen
_PUTIMAGE , WorkScreen ' stretch work screen (zoom 2X)
_DISPLAY ' update view screen with changes
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB UPDATE_MARIO () ' UPDATE_MARIO |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Updates mario's position on screen and checks for collision between mario and mystery box. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED Box AS TYPE_RECTANGLE ' need access to mystery box coordinates
SHARED FPSFrame AS INTEGER ' need access to master frame counter
SHARED SNDBump AS LONG ' need access to bump sound
FPSFrame = FPSFrame + 1 ' increment master frame counter
IF FPSFrame = 31 THEN FPSFrame = 1 ' reset master frame counter when needed
Mario.x = Mario.x + Mario.Direction * Mario.Speed ' update mario x position
IF Mario.x >= 336 THEN Mario.x = Mario.x - 336 ' move mario to left side of screen
IF Mario.x <= -16 THEN Mario.x = Mario.x + 336 ' move mario to right side of screen
'+---------------------------------+
'| Calculate mario sprite location |
'+---------------------------------+
Mario.Rect.x1 = Mario.x - 15 ' calculate mario rectangular coordinates
Mario.Rect.y1 = Mario.y - 63
Mario.Rect.x2 = Mario.Rect.x1 + 31
Mario.Rect.y2 = Mario.Rect.y1 + 63
IF COLLISION(Mario.Rect, Box) THEN ' has mario collided with mystery box?
_SNDPLAY SNDBump ' play bump sound
'+-------------------------------------+
'| Mario has collided with mystery box |
'+-------------------------------------+
IF Mario.x < Box.x1 - 8 THEN ' yes, is mario at left side of box?
'+----------------------------+
'| Mario hit left side of box |
'+----------------------------+
Mario.Direction = 0 ' yes, stop mario movement
Mario.x = Box.x1 - 17 ' position mario at left side of box
ELSEIF Mario.x > Box.x2 + 8 THEN ' no, is mario at right side of box?
'+-----------------------------+
'| Mario hit right side of box |
'+-----------------------------+
Mario.Direction = 0 ' yes, stop mario movement
Mario.x = Box.x2 + 16 ' position mario at right side of box
ELSE ' no, must have hit box from underneath
'+-------------------------------+
'| Mario hit box from underneath |
'+-------------------------------+
SPAWN_COIN ' create a coin
Mario.y = Box.y2 + 64 ' position mario just underneath box
Mario.Yvel = 0 ' stop upward movement
END IF
'+-----------------------------------+
'| Recalculate mario sprite location |
'+-----------------------------------+
Mario.Rect.x1 = Mario.x - 15 ' recalculate mario rectangular coordinates
Mario.Rect.y1 = Mario.y - 63
Mario.Rect.x2 = Mario.Rect.x1 + 31
Mario.Rect.y2 = Mario.Rect.y1 + 63
END IF
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB MOVE_MARIO () ' MOVE_MARIO |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Moves mario according to player input. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED Button AS TYPE_BUTTON ' need access to buttons
SHARED FPSFrame AS INTEGER ' need access to master frame counter
SHARED SNDJump AS LONG ' need access to jump sound
'+-------------------------------+
'| Check for button/axis presses |
'+-------------------------------+
IF __BUTTON_DOWN(Button.FIRE) THEN FIRE_BULLET ' fire a bullet
IF NOT Mario.Jumping THEN ' is mario currently jumping?
'+---------------------------------------------------+
'| Must not be jumping to walk, run, jump, or crouch |
'+---------------------------------------------------+
IF __BUTTON_DOWN(Button.LEFT) THEN ' no, is player pressing a left button?
'+--------------------+
'| Walk and face left |
'+--------------------+
Mario.Walking = -1 ' yes, remember that mario is walking
Mario.Direction = -1 ' mario is walking to the left
Mario.Facing = -1 ' mario is facing left
Mario.Action = WALK ' use walking sprites
IF FPSFrame MOD Mario.FPS = 0 THEN Mario.Frame = Mario.Frame + 1 ' increment to next walking animation frame
IF Mario.Frame = 7 THEN Mario.Frame = 1 ' reset animation frame counter when necessary
ELSEIF __BUTTON_DOWN(Button.RIGHT) THEN ' no, is player pressing a right button?
'+---------------------+
'| Walk and face right |
'+---------------------+
Mario.Walking = -1 ' yes, remember that mario is walking
Mario.Direction = 1 ' mario is walking to the right
Mario.Facing = 1 ' mario is facing right
Mario.Action = WALK ' use walking sprites
IF FPSFrame MOD Mario.FPS = 0 THEN Mario.Frame = Mario.Frame + 1 ' increment to next walking animation frame
IF Mario.Frame = 7 THEN Mario.Frame = 1 ' reset animation frame counter when necessary
ELSE ' no, mario is standing still
'+--------------+
'| Stop walking |
'+--------------+
Mario.Action = STAND ' use standing sprite
Mario.Frame = 1 ' reset animation frame counter (sprite only has 1 frame)
Mario.Direction = 0 ' mario is standing still
Mario.Walking = 0 ' remember that mario is not walking
END IF
IF Mario.Walking THEN ' is mario currently walking?
'+--------------------------------+
'| Must be walking before running |
'+--------------------------------+
IF __BUTTON_DOWN(Button.RUN) THEN ' yes, is player pressing a run button?
'+---------------+
'| Start running |
'+---------------+
IF NOT Mario.Running THEN ' yes, is mario already running?
Mario.Action = RUNSTART ' no, use getting ready to run sprite
Mario.Frame = 1 ' reset animation frame counter (sprite only has 1 frame)
Mario.RunTimer = Mario.RunTimer + 1 ' increment getting ready to run timer
IF Mario.RunTimer = 5 THEN Mario.Running = -1 ' start mario running after 5 frames have passed
Mario.Direction = 0 ' mario stands still during these 5 frames
ELSE ' yes, mario is already running
Mario.Speed = 4 ' set mario speed
Mario.FPS = 2 ' set animation frames per second (15 FPS)
END IF
ELSE ' no, a run button is not being pressed
'+--------------+
'| Stop running |
'+--------------+
Mario.Speed = 2 ' set mario speed
Mario.FPS = 5 ' set animation frames per second (6 FPS)
Mario.Running = 0 ' mario is no longer running
Mario.RunTimer = 0 ' reset getting ready to run timer
END IF
END IF
IF __BUTTON_DOWN(Button.CROUCH) OR __BUTTON_DOWN(Button.DOWN) THEN ' is player pressing a button to crouch?
Mario.Action = CROUCH ' yes, use crouching sprite
Mario.Frame = 1 ' reset animation frame counter (sprite only has 1 frame)
Mario.Direction = 0 ' mario is standing still
ELSEIF __BUTTON_DOWN(Button.JUMP) OR __BUTTON_DOWN(Button.UP) THEN ' no, is player pressing a button to jump?
_SNDPLAY SNDJump ' play jump sound
Mario.Jumping = -1 ' yes, mario is now jumping
Mario.Yvel = -5 ' set vertical velocity
Mario.Vector = -1 ' set vertical vector direction
Mario.Action = JUMP ' use jumping sprite
Mario.Frame = 1 ' reset animation frame counter (sprite only has 1 frame)
END IF
ELSE ' yes, mario is currently jumping
'+---------------------------+
'| Perform jump arc sequence |
'+---------------------------+
Mario.Vector = Mario.Vector + .2 ' increment vertical vector direction (will change direction at 0)
Mario.Yvel = Mario.Yvel + Mario.Vector ' add vector quantity to vertical velocity
Mario.y = Mario.y + Mario.Yvel ' add vertical velocity to mario y coordinate
IF Mario.y >= Mario.Floor THEN ' has mario hit floor on way down?
'+--------------+
'| Stop jumping |
'+--------------+
Mario.Jumping = 0 ' yes, mario is no longer jumping
Mario.y = Mario.Floor ' place mario onto floor
END IF
END IF
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB UPDATE_BULLETS () ' UPDATE_BULLETS |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Updates location of active bullets and draws them to the screen. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED Sprite() AS LONG ' need access to sprite images
SHARED Bullets() AS TYPE_BULLET ' need access to bullet array
SHARED BulletTimer AS INTEGER ' need access to bullet timer
DIM b AS INTEGER ' bullet counter
IF BulletTimer THEN BulletTimer = BulletTimer - 1 ' decrement bullet timer if needed
b = 0 ' reset bullet counter
DO ' loop through bullet array
b = b + 1 ' increment bullet counter
IF Bullets(b).InUse THEN ' is this bullet active?
Bullets(b).x = Bullets(b).x + Bullets(b).Direction * 6 ' yes, update bullet x coordinate
IF Bullets(b).y < Mario.Floor - 9 THEN ' has bullet reached the floor?
Bullets(b).y = Bullets(b).y + 3 ' no, add to the bullet's y coordinate
ELSE ' yes, bullet at floor
Bullets(b).y = Bullets(b).y - 4 ' bounce bullet back up
END IF
IF Bullets(b).x > 336 OR Bullets(b).x < -16 THEN ' has bullet left screen?
Bullets(b).InUse = 0 ' yes, this bullet no longer active
ELSE ' no, bullet still on screen
_PUTIMAGE (Bullets(b).x - 16, Bullets(b).y - 16), Sprite(FIRE, Bullets(b).Cell) ' draw bullet
Bullets(b).Cell = Bullets(b).Cell + 1 ' increment animation cell
IF Bullets(b).Cell = 5 THEN Bullets(b).Cell = 1 ' reset animation cell when needed
END IF
END IF
LOOP UNTIL b = UBOUND(Bullets) ' leave when array scanned
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB FIRE_BULLET () ' FIRE_BULLET |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Fires a bullet. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED Bullets() AS TYPE_BULLET ' need access to bullet array
SHARED BulletTimer AS INTEGER ' need access to bullet timer
SHARED SNDFire AS LONG ' need access to bullet sound
DIM b AS INTEGER ' bullet counter
IF BulletTimer THEN EXIT SUB ' leave if not time to fire bullet
BulletTimer = 10 ' must wait 10 frames between bullets (3 rounds per second)
b = 0 ' reset bullet counter
DO ' loop through bullet array
b = b + 1 ' increment bullet counter
LOOP UNTIL Bullets(b).InUse = 0 OR b = UBOUND(Bullets) ' leave when array scanned
IF Bullets(b).InUse THEN ' if this index in use then all indexes used
b = b + 1 ' increment bullet counter
REDIM _PRESERVE Bullets(b) AS TYPE_BULLET ' increase size of array
END IF
Bullets(b).InUse = -1 ' mark this index in use
_SNDPLAY SNDFire ' play bullet sound
IF Mario.Facing = 1 THEN ' mario facing right?
Bullets(b).x = Mario.Rect.x2 ' yes, bullet comes from right side of mario
ELSE ' no, mario facing left
Bullets(b).x = Mario.Rect.x1 ' bullet comes from left side of mario
END IF
Bullets(b).y = Mario.Rect.y1 + 31 ' bullet comes from vertical center of mario
Bullets(b).Direction = Mario.Facing ' remember bullet direction
Bullets(b).Cell = 1 ' animation frame 1
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
FUNCTION COLLISION (R1 AS TYPE_RECTANGLE, R2 AS TYPE_RECTANGLE) ' COLLISION |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Detects and reports a collision between two rectangular areas provided, -1 (TRUE) if in collision, 0 (FALSE) otherwise. |
'| |
'| R1 - rectangle 1 |
'| R2 - rectangle 2 |
'\______________________________________________________________________________________________________________________________________________/
COLLISION = 0 ' assume no collision
IF R1.x2 >= R2.x1 THEN ' does R1 overlap R2?
IF R1.x1 <= R2.x2 THEN
IF R1.y2 >= R2.y1 THEN
IF R1.y1 <= R2.y2 THEN
COLLISION = -1 ' yes, report rectangles in state of collision
END IF
END IF
END IF
END IF
END FUNCTION
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB SET_DEFAULT_BUTTONS () ' SET_DEFAULT_BUTTONS |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Sets the default buttons. Will use keyboard and/or joystick 1 if they are detected. |
'\______________________________________________________________________________________________________________________________________________/
SHARED Button AS TYPE_BUTTON ' need access to button array
STATIC Configured AS INTEGER ' -1 when buttons previously created and configured
'+-----------------------------------+
'| Clear previous button assignments |
'+-----------------------------------+
IF Configured THEN ' have buttons been created and configured
__REMOVE_BUTTON Button.UP, 0 ' yes, clear all previous button assignments
__REMOVE_BUTTON Button.DOWN, 0
__REMOVE_BUTTON Button.LEFT, 0
__REMOVE_BUTTON Button.RIGHT, 0
__REMOVE_BUTTON Button.FIRE, 0
__REMOVE_BUTTON Button.RUN, 0
__REMOVE_BUTTON Button.JUMP, 0
__REMOVE_BUTTON Button.CROUCH, 0
END IF
'+-------------------------------------------------------+
'| Configure keyboard keys as buttons if keyboard exists |
'+-------------------------------------------------------+
IF __KEYBOARD_EXISTS THEN ' does keyboard exist?
__ASSIGN_BUTTON Button.UP, __KEYBOARDCID, CLKEY_W ' UP = W KEY [SLOT1]
__ASSIGN_BUTTON Button.DOWN, __KEYBOARDCID, CLKEY_S ' DOWN = S KEY [SLOT1]
__ASSIGN_BUTTON Button.LEFT, __KEYBOARDCID, CLKEY_A ' LEFT = A KEY [SLOT1]
__ASSIGN_BUTTON Button.RIGHT, __KEYBOARDCID, CLKEY_D ' RIGHT = D KEY [SLOT1]
__ASSIGN_BUTTON Button.FIRE, __KEYBOARDCID, CLKEY_RCTRL ' FIRE = RIGHT CONTROL KEY [SLOT1]
__ASSIGN_BUTTON Button.RUN, __KEYBOARDCID, CLKEY_RSHIFT ' RUN = RIGHT SHIFT KEY [SLOT1]
__ASSIGN_BUTTON Button.JUMP, __KEYBOARDCID, CLKEY_SPACEBAR ' JUMP = SPACE BAR KEY [SLOT1]
__ASSIGN_BUTTON Button.CROUCH, __KEYBOARDCID, CLKEY_C ' CROUCH = C KEY [SLOT1]
'+----------------------+
'| Optional assignments |
'+----------------------+
'__ASSIGN_BUTTON Button.UP, __KEYBOARDCID, CLKEY_UP ' UP = UP ARROW KEY [SLOT2]
'__ASSIGN_BUTTON Button.DOWN, __KEYBOARDCID, CLKEY_DOWN ' DOWN = DOWN ARROW KEY [SLOT2]
'__ASSIGN_BUTTON Button.LEFT, __KEYBOARDCID, CLKEY_LEFT ' LEFT = LEFT ARROW KEY [SLOT2]
'__ASSIGN_BUTTON Button.RIGHT, __KEYBOARDCID, CLKEY_RIGHT ' RIGHT = RIGHT ARROW KEY [SLOT2]
'__ASSIGN_BUTTON Button.FIRE, __KEYBOARDCID, CLKEY_LCTRL ' FIRE = LEFT CONTROL KEY [SLOT2]
END IF
'+---------------------------------------------------------------+
'| Configure joystick 1 axes and buttons if it exists (optional) |
'+---------------------------------------------------------------+
'IF __JOYPAD_EXISTS(1) THEN ' does joystick 1 exist?
' __ASSIGN_AXIS Button.UP, __JOYPAD1CID, -2 ' UP = JOYSTICK 1 AXIS 2 [SLOT3 or 1]
' __ASSIGN_AXIS Button.DOWN, __JOYPAD1CID, 2 ' DOWN = JOYSTICK 1 AXIS 2 [SLOT3 or 1]
' __ASSIGN_AXIS Button.LEFT, __JOYPAD1CID, -1 ' LEFT = JOYSTICK 1 AXIS 1 [SLOT3 or 1]
' __ASSIGN_AXIS Button.RIGHT, __JOYPAD1CID, 1 ' RIGHT = JOYSTICK 1 AXIS 1 [SLOT3 or 1]
' __ASSIGN_BUTTON Button.FIRE, __JOYPAD1CID, 1 ' FIRE = JOYSTICK 1 BUTTON 1 [SLOT3 or 1]
' IF __BUTTON_TOTAL(__JOYPAD1CID) > 1 THEN __ASSIGN_BUTTON Button.JUMP, __JOYPAD1CID, 2 ' JUMP = JOYSTICK 1 BUTTON 2 [SLOT2 or 1]
' IF __BUTTON_TOTAL(__JOYPAD1CID) > 2 THEN __ASSIGN_BUTTON Button.RUN, __JOYPAD1CID, 3 ' RUN = JOYSTICK 1 BUTTON 4 [SLOT2 or 1]
' IF __BUTTON_TOTAL(__JOYPAD1CID) >= 3 THEN __ASSIGN_BUTTON Button.CROUCH, __JOYPAD1CID, 4 ' CROUCH = JOYSTICK 1 BUTTON 5 [SLOT2 or 1]
'END IF
Configured = -1 ' buttons have been created and configured
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB LOAD_ASSETS () ' LOAD_ASSETS |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Load the demo's graphics and sounds |
'\______________________________________________________________________________________________________________________________________________/
SHARED Sprite() AS LONG ' need access to sprite images
SHARED WorkScreen AS LONG ' need access to work screen
SHARED BackGround AS LONG ' need access to background image
SHARED MysteryBox AS LONG ' need access to mystery box image
SHARED SNDBump AS LONG ' need access to sounds
SHARED SNDCoin AS LONG
SHARED SNDConf AS LONG
SHARED SNDFire AS LONG
SHARED SNDJump AS LONG
SHARED SNDSong AS LONG
DIM Sheet AS LONG ' demo sprite sheet
DIM Ground AS LONG ' ground square image
DIM i AS INTEGER ' generic counter
SNDBump = _SNDOPEN("CB_Bump.ogg") ' load sounds
SNDCoin = _SNDOPEN("CB_Coin.ogg")
SNDFire = _SNDOPEN("CB_Fire.ogg")
SNDJump = _SNDOPEN("CB_Jump.ogg")
SNDSong = _SNDOPEN("CB_Song.ogg")
SNDConf = _SNDOPEN("CB_Conf.ogg")
Sheet = _LOADIMAGE("CBDemo.PNG", 32) ' sprite sheet image
WorkScreen = _NEWIMAGE(320, 240, 32) ' work screen image
BackGround = _NEWIMAGE(320, 240, 32) ' background image
Sprite(STAND, 1) = _NEWIMAGE(32, 64, 32) ' standing image
Sprite(CROUCH, 1) = _NEWIMAGE(32, 64, 32) ' crouching image
Sprite(RUNSTART, 1) = _NEWIMAGE(32, 64, 32) ' ready to run image
Sprite(JUMP, 1) = _NEWIMAGE(32, 64, 32) ' jumping image
MysteryBox = _NEWIMAGE(32, 32, 32) ' mystery box image
Sprite(COIN, 1) = _NEWIMAGE(32, 32, 32) ' coin image
Ground = _NEWIMAGE(32, 32, 32) ' ground image
_PUTIMAGE , Sheet, MysteryBox, (128, 64)-(159, 95) ' get mystery box image from sprite sheet
_PUTIMAGE , Sheet, Sprite(COIN, 1), (160, 64)-(191, 95) ' get coin image from sprite sheet
_PUTIMAGE , Sheet, Ground, (192, 64)-(223, 95) ' get ground image from sprite sheet
_PUTIMAGE , Sheet, Sprite(STAND, 1), (0, 0)-(31, 64) ' get standing image from sprite sheet
_PUTIMAGE , Sheet, Sprite(CROUCH, 1), (32, 0)-(63, 63) ' get crouching image from sprite sheet
_PUTIMAGE , Sheet, Sprite(RUNSTART, 1), (64, 0)-(95, 63) ' get ready to run image from sprite sheet
_PUTIMAGE , Sheet, Sprite(JUMP, 1), (288, 0)-(319, 63) ' get jumping image from sprite sheet
FOR i = 1 TO 6 ' cycle through 6 animation cells
Sprite(WALK, i) = _NEWIMAGE(32, 64, 32) ' walking animation image cell
_PUTIMAGE , Sheet, Sprite(WALK, i), (64 + i * 32, 0)-(95 + i * 32, 63) ' get walking animation cell from sprite sheet
IF i < 5 THEN ' cycle through 4 animation cells
Sprite(FIRE, i) = _NEWIMAGE(32, 32, 32) ' bullet animation image cell
_PUTIMAGE , Sheet, Sprite(FIRE, i), ((i - 1) * 32, 64)-((i - 1) * 32 + 31, 95) ' get bullet animation cell from sprite sheet
END IF
NEXT i
_DEST BackGround ' draw on background image
CLS , _RGB32(0, 255, 0) ' clear background image in green
FOR i = 0 TO 288 STEP 32 ' cycle through the floor area
_PUTIMAGE (i, 176), Ground ' draw the floor ground blocks
_PUTIMAGE (i, 208), Ground
NEXT i
_FREEIMAGE Ground ' ground image no longer needed
_FREEIMAGE Sheet ' sprite sheet no longer needed
_DEST 0 ' return to main screen
END SUB
' _____________________________________________________________________________________________________________________________________________
'/ \
SUB INITIALIZE_VARIABLES () ' INITIALIZE_VARIABLES |
' _________________________________________________________________________________________________________________________________________|____
'/ \
'| Initialize all demo variables |
'\______________________________________________________________________________________________________________________________________________/
SHARED Button AS TYPE_BUTTON ' need access to buttons
SHARED Mario AS TYPE_MARIO ' need access to mario properties
SHARED Box AS TYPE_RECTANGLE ' need access to box coordinates
Mario.FPS = 5 ' mario animation speed
Mario.Direction = 1 ' mario travel direction (right)
Mario.Facing = 1 ' mario facing direction (right)
Mario.Floor = 176 ' floor that mario can't go beyond
Mario.x = 159 ' x coordinate of mario (bottom center of sprite)
Mario.y = Mario.Floor ' y coordinate of mario (bottom center of sprite)
Mario.Action = STAND ' mario is currently standing
Mario.Frame = 1 ' first animation frame
Mario.Rect.x1 = Mario.x - 15 ' calculate mario sprite rectangular coordinates
Mario.Rect.y1 = Mario.y - 63
Mario.Rect.x2 = Mario.Rect.x1 + 31
Mario.Rect.y2 = Mario.Rect.y1 + 63
Box.x1 = 144 ' mystery box rectangular coordinates
Box.y1 = 48
Box.x2 = Box.x1 + 31
Box.y2 = Box.y1 + 31
__ASSIGN_BUTTON Button.F1, __KEYBOARDCID, CLKEY_F1 ' F1 key
__ASSIGN_BUTTON Button.F2, __KEYBOARDCID, CLKEY_F2 ' F2 key
__ASSIGN_BUTTON Button.F3, __KEYBOARDCID, CLKEY_F3 ' F3 key
END SUB
'$INCLUDE:'CONTROLLER.BM'
RE: Controller Library - TempodiBasic - 05-02-2023
Hi Terry
I stress out " very good controller library!"
about the issue of detecting at will the controllers it stands up on _DEVICES keyword that is in development, so also using your fantastic library I stuck in the same issue.
Thank you for sharing this masterpiece that will grow up togeter QB64pe.
Screenshot of results of my attempt using your library
and here correlate QB64 code
Code: (Select All) '$INCLUDE:'CONTROLLER.BI'
ReDim Shared Ax(1 To 1) As Integer, Bx(1 To 1) As Integer, Wx(1 To 1) As Integer
ReDim Shared Axm As Integer, Bxm As Integer, Wxm As Integer
Dim Kh As Integer
__INITIALIZE_CONTROLLERS ' initialize controller library
Cls
Print " Press ESC to quit and Enter to detect joystick"
Print " JoyStick Axis Buttons Wheels"
__IDENTIFY_CONTROLLERS 'Print IsJoystick%, Axm, Bxm, Wxm
View Print 4 To 24
Kh = 0
While Kh <> 27
Kh = _KeyHit
If (Kh) = 13 Then __IDENTIFY_CONTROLLERS: Print __CONTROLLER_NAME$(3), __BUTTON_TOTAL(3), __AXIS_TOTAL(3) 'Print IsJoystick%, Axm, Bxm, Wxm
Locate 24, 1: Print Kh;
_Limit 30
Wend
End
'*****************************************************************
' JOYSTICK DETECTION
'*****************************************************************
Function IsJoystick% ()
Dim HMD%: HMD% = HowManyDevice%
If HMD% = 0 Then
Print " No input devices!": End
Else
Locate , 1: Print HMD%
End If
If HMD% = 3 Then
Locate , 4: Print "Joystick detected"
IsJoystick% = -1
Axm = _LastAxis(3)
Bxm = _LastButton(3)
Wxm = _LastWheel(3)
Else
' all cases in which HMD% <>3
Locate , 10: Print " NO Joystick!"
IsJoystick% = 0
Axm = 0
Bxm = 0
Wxm = 0
End If
Print HMD%, Axm, Bxm, Wxm
End Function
Function HowManyDevice%
HowManyDevice% = 0 ' error value
HowManyDevice% = _Devices ' value detected
End Function
'*****************************************************************
' END Subs and Function for JOYSTICK DETECTION
'*****************************************************************
'$INCLUDE:'CONTROLLER.BM'
Moreover I agree with you for thanking SMcNeill and all the others of the QB64pe development team.
RE: Controller Library - TempodiBasic - 05-13-2023
Hi Terry
thanks for all your good efforts to show the paths to different purpuses.
Your demo for remapping user input for joystick is very nice.
It is very good.
No plugin/ unplug allowed after program runs, but this is ok, which player does change the controller during the play.
a music gift
GOSSIP by Maneskin
RE: Controller Library - TerryRitchie - 05-13-2023
(05-13-2023, 11:26 AM)TempodiBasic Wrote: Hi Terry
thanks for all your good efforts to show the paths to different purpuses.
Your demo for remapping user input for joystick is very nice.
It is very good.
No plugin/ unplug allowed after program runs, but this is ok, which player does change the controller during the play.
a music gift
GOSSIP by Maneskin
I'm working on adding the ability to notice when new controllers are plugged in and current ones have been disconnected.
|