04-25-2024, 05:43 PM
(This post was last modified: 04-25-2024, 05:45 PM by TerryRitchie.)
You can also control a player's fire rate by using a latching method that keeps track of a key's current state (pressed or released).
I made a quick demo to show how this can be used in a game.
I have no idea why my comments get skewed when posting using the QB tags? This happens when exporting to HTML as well. I wish someone would look into this.
I made a quick demo to show how this can be used in a game.
I have no idea why my comments get skewed when posting using the QB tags? This happens when exporting to HTML as well. I wish someone would look into this.
Code: (Select All)
'+-----------------------------------------------------------------------------------+
'| Controlling Bullets |
'| |
'| "Wearing the player out" |
'| ---------------------- |
'| |
'| This method forces the player to release the fire button to fire the next bullet. |
'| This allows the player to rapid fire as fast as they can push the button which in |
'| turn wears the player out. |
'| |
'| A "latching" method is used to keep track of the fire button's current state. |
'| This method is also used in the player's ship movements to keep the game from |
'| registering the UP and DOWN arrow keys being pressed at the same time and the |
'| RIGHT and LEFT arrows keys from being pressed at the same time as well. |
'| |
'| |
'| This method can be combined with frame timers to limit the number of bullets per |
'| second as well. |
'| |
'| Demo by Terry Ritchie 04/25/24 |
'+-----------------------------------------------------------------------------------+
OPTION _EXPLICIT ' force declaration of all variables
'+-----------------------+
'| Define game constants |
'+-----------------------+
CONST SCREENWIDTH% = 800 ' game screen width
CONST SCREENHEIGHT% = 600 ' game screen height
CONST BUTTONUP% = 0 ' button position is up (depressed)
CONST BUTTONDOWN% = 1 ' button position is down (pressed)
'+-----------------------------+
'| Define variables structures |
'+-----------------------------+
TYPE KEY ' DEFINE KEYBOARD KEY
Key AS INTEGER ' scan code of key
Position AS INTEGER ' position of keyboard key (the "latch")
END TYPE
TYPE BUTTON ' DEFINE GAME BUTTONS
North AS KEY ' up arrow key
South AS KEY ' down arrow key
East AS KEY ' right arrow key
West AS KEY ' left arrow key
Fire AS KEY ' space bar key
END TYPE
TYPE BULLET ' DEFINE BULLET
Active AS INTEGER ' bullet active (y/n)
x AS INTEGER ' center x coordinate of bullet
y AS INTEGER ' center y coordinate of bullet
Speed AS SINGLE ' bullet speed
END TYPE
TYPE SHIP ' DEFINE PLAYER SHIP
x AS INTEGER ' center x coordinate of ship
y AS INTEGER ' center y coordinate of ship
MaxX AS INTEGER ' maximum x coordinate of ship \
MaxY AS INTEGER ' maximum y coordinate of ship \ Ship bounding box
MinX AS INTEGER ' minimum x coordinate of ship /
MinY AS INTEGER ' minimum y coordinate of ship /
END TYPE
'+------------------+
'| Define variables |
'+------------------+
DIM Button AS BUTTON ' game buttons
REDIM Bullet(0) AS BULLET ' player bullet array
DIM Ship AS SHIP ' player ship
'+----------------------+
'| Initialize variables |
'+----------------------+
Button.North.Key = 18432 ' up arrow key scan code
Button.South.Key = 20480 ' down arrow key scan code
Button.East.Key = 19712 ' right arrow key scan code
Button.West.Key = 19200 ' left arrow key scan code
Button.Fire.Key = 32 ' space bar key scan code
Ship.x = 20 ' initial ship x coordinate
Ship.y = (SCREENHEIGHT - 1) \ 2 ' initial ship y coordinate
Ship.MinX = 20 ' ship minimum x coordinate
Ship.MinY = 20 ' ship minimum y coordinate
Ship.MaxX = SCREENWIDTH \ 2 - 1 ' ship maximum x coordinate
Ship.MaxY = SCREENHEIGHT - 21 ' ship maximum y coordinate
'+--------------------------------------------------------------------------------------------------------------------+
'| BEGIN MAIN PROGRAM |
'+--------------------------------------------------------------------------------------------------------------------+
SCREEN _NEWIMAGE(SCREENWIDTH, SCREENHEIGHT, 32) ' enter game graphics screen
DO ' begin main program loop
_LIMIT 60 ' nice and smooth at 60 FPS
CLS ' clear the game screen
DisplayDirections ' display game's directions
'+-----------------------------------+
'| Update the player's ship position |
'+-----------------------------------+
MoveShip ' update and draw player ship
'+-----------------------------------------------+
'| Test for the fire button in the down position |
'+-----------------------------------------------+
IF _KEYDOWN(Button.Fire.Key) THEN ' fire button pressed? (space bar key)
'+------------------------------------------------------------------------------+
'| Test if the fire button has been released since the last time it was pressed |
'+------------------------------------------------------------------------------+
IF Button.Fire.Position = BUTTONUP THEN ' yes, has fire button been released?
'+------------------------------------------------------------+
'| Set the fire button into the down position and fire bullet |
'+------------------------------------------------------------+
Button.Fire.Position = BUTTONDOWN ' yes, latch fire button in down position
FireBullet Ship.x + 15, Ship.y ' fire a bullet from the nose of the ship
END IF
ELSE ' no, fire button is not pressed
Button.Fire.Position = BUTTONUP ' latch fire button in up position
END IF
'+------------------------------------+
'| Update the active bullet positions |
'+------------------------------------+
ManageBullets ' update and draw all active bullets
_DISPLAY ' update game screen with changes
LOOP UNTIL _KEYDOWN(27) ' leave main loop when ESC pressed
SYSTEM ' return to the operating system
'+--------------------------------------------------------------------------------------------------------------------+
'| END MAIN PROGRAM |
'+--------------------------------------------------------------------------------------------------------------------+
'+--------------------------------------------------------------------------------------------------------------------+
'| Declare subroutines and functions |
'+--------------------------------------------------------------------------------------------------------------------+
' ____________________________________________________________________________________________________________________
'/ \
SUB DisplayDirections () ' DisplayDirections |
' ________________________________________________________________________________________________________________/
'/ \
'| Displays the game's directions to the player. |
'\________________________________________________________________________________________________________________/
LOCATE 2, 2
PRINT "FORCE PLAYER TO PRESS AND RELEASE FIRE KEY"
LOCATE 4, 2
PRINT " - ARROW KEYS TO MOVE"
LOCATE 5, 2
PRINT " - SPACE BAR TO FIRE"
LOCATE 6, 2
PRINT " - ESC TO LEAVE GAME"
END SUB
' ____________________________________________________________________________________________________________________
'/ \
SUB MoveShip () ' MoveShip |
' ________________________________________________________________________________________________________________/
'/ \
'| Updates the ship location according to player keypresses then draws the ship on the game screen. |
'\________________________________________________________________________________________________________________/
SHARED Button AS BUTTON ' need access to game buttons
SHARED Ship AS SHIP ' need access to player ship
'+---------------------------------+
'| Check for forward ship movement |
'+---------------------------------+
IF _KEYDOWN(Button.East.Key) THEN ' forward thrust button pressed? (right arrow key)
IF Button.West.Position = BUTTONUP THEN ' yes, is the reverse button pressed?
Button.East.Position = BUTTONDOWN ' no, latch forward button in down position
Ship.x = Ship.x + 5 ' move ship forward
IF Ship.x > Ship.MaxX THEN Ship.x = Ship.MaxX ' keep x within upper limit
END IF
ELSE ' no, forward thrust button is not pressed
Button.East.Position = BUTTONUP ' latch forward thrust button in up position
END IF
'+---------------------------------+
'| Check for reverse ship movement |
'+---------------------------------+
IF _KEYDOWN(Button.West.Key) THEN ' reverse button pressed? (left arrow key)
IF Button.East.Position = BUTTONUP THEN ' yes, is the forward thrust button pressed?
Button.West.Position = BUTTONDOWN ' no, latch reverse button in down position
Ship.x = Ship.x - 5 ' move ship backward
IF Ship.x < Ship.MinX THEN Ship.x = Ship.MinX ' keep x within lower limit
END IF
ELSE ' no, reverse button is not pressed
Button.West.Position = BUTTONUP ' latch reverse button in up position
END IF
'+--------------------------------+
'| Check for upward ship movement |
'+--------------------------------+
IF _KEYDOWN(Button.North.Key) THEN ' upward button pressed? (up arrow key)
IF Button.South.Position = BUTTONUP THEN ' yes, is the downward button pressed?
Button.North.Position = BUTTONDOWN ' no, latch upward button in down position
Ship.y = Ship.y - 5 ' move ship upward
IF Ship.y < Ship.MinY THEN Ship.y = Ship.MinY ' keep y within lower limit
END IF
ELSE ' no, upward button is not pressed
Button.North.Position = BUTTONUP ' latch upward button in up position
END IF
'+----------------------------------+
'| Check for downward ship movement |
'+----------------------------------+
IF _KEYDOWN(Button.South.Key) THEN ' downward button pressed? (down arrow key)
IF Button.North.Position = BUTTONUP THEN ' yes, is the upward button pressed?
Button.South.Position = BUTTONDOWN ' no, latch downward button in down position
Ship.y = Ship.y + 5 ' move ship downward
IF Ship.y > Ship.MaxY THEN Ship.y = Ship.MaxY ' keep y within upper limit
END IF
ELSE ' no, downward button is not pressed
Button.South.Position = BUTTONUP ' latch downward button in up position
END IF
'+------------------+
'| Draw player ship |
'+------------------+
LINE (Ship.x - 15, Ship.y - 10)-(Ship.x - 15, Ship.y + 10) ' draw triangular ship
LINE -(Ship.x + 15, Ship.y)
LINE -(Ship.x - 15, Ship.y - 10)
END SUB
' ____________________________________________________________________________________________________________________
'/ \
SUB ManageBullets () ' ManageBullets |
' ________________________________________________________________________________________________________________/
'/ \
'| Updates and draws all currently active bullets to the game screen. |
'\________________________________________________________________________________________________________________/
SHARED Bullet() AS BULLET ' need access to player bullet array
DIM Index AS INTEGER ' array index counter
'+------------------------------------------+
'| Scan the bullet array for active bullets |
'+------------------------------------------+
Index = -1 ' reset index counter value
DO ' begin array search loop
Index = Index + 1 ' increment array index counter
IF Bullet(Index).Active THEN ' is this bullet active?
'+------------------------------------------------------+
'| This bullet is active, update its location and speed |
'+------------------------------------------------------+
Bullet(Index).x = Bullet(Index).x + Bullet(Index).Speed ' yes, move bullet to the right
Bullet(Index).Speed = Bullet(Index).Speed * 1.05 ' increase speed slightly
'+-----------------------------------------------------+
'| Check to see if the bullet has left the game screen |
'+-----------------------------------------------------+
IF Bullet(Index).x >= _WIDTH(0) - 1 THEN ' has bullet left the game screen?
'+------------------------------------------------+
'| This bullet has left the screen, deactivate it |
'+------------------------------------------------+
Bullet(Index).Active = 0 ' yes, deactivate bullet
ELSE ' no, bullet still on game screen
'+----------------------------------------------+
'| This bullet is still on game screen, draw it |
'+----------------------------------------------+
CIRCLE (Bullet(Index).x, Bullet(Index).y), 5 ' draw the bullet
PAINT (Bullet(Index).x, Bullet(Index).y) ' paint the bullet
END IF
END IF
LOOP UNTIL Index = UBOUND(Bullet) ' leave when all indexes checked
END SUB
' ____________________________________________________________________________________________________________________
'/ \
SUB FireBullet (x AS INTEGER, y AS INTEGER) ' FireBullet |
' ________________________________________________________________________________________________________________/
'/ \
'| Initiates a bullet at the supplied coordinates |
'| |
'| x,y - the on screen coordinates where the bullet will materialize |
'\________________________________________________________________________________________________________________/
SHARED Bullet() AS BULLET ' need access to player bullet array
DIM Index AS INTEGER ' array index counter
'+-------------------------------------------------------+
'| Scan the bullet array for an index that is not active |
'+-------------------------------------------------------+
Index = -1 ' reset index counter
DO ' begin array search loop
Index = Index + 1 ' increment array index counter
LOOP UNTIL Index = UBOUND(Bullet) OR Bullet(Index).Active = 0 ' leave when inactive found or at end of array
'+------------------------------------------------------------------------------+
'| Test if the index value from the search loop yielded an inactive array index |
'+------------------------------------------------------------------------------+
IF Bullet(Index).Active THEN ' was an inactive array index found?
'+------------------------------------------------------------------------------------------------------+
'| No inactive bullets were found in the array so the array size will need to be increased by one. The |
'| maximum size of the array will eventually be determined by the speed of the player's button presses. |
'+------------------------------------------------------------------------------------------------------+
Index = Index + 1 ' no, increase the array index size
REDIM _PRESERVE Bullet(Index) AS BULLET ' resize the array while preserving exisiting data
END IF
'+---------------------------------------------------+
'| Add the new bullet's information the bullet array |
'+---------------------------------------------------+
Bullet(Index).x = x ' new bullet's x coordinate
Bullet(Index).y = y ' new bullet's y coordinate
Bullet(Index).Speed = 5 ' new bullet's initial speed
Bullet(Index).Active = 1 ' this array index is active
SOUND 880, .5 ' awesome bullet sound
END SUB


, and moving the mouse events outside the update loop is different. Doing your fix, Steve, doesn't solve the problem for me, it just made the timer not work at all 'cept for the beep. Terry, your demo doesn't work on my system either. Pete, thanks, I'll give your sub a try, but I have my doubts. bplus, I'm not using bullets here, just a laser beam to blast away. Terry, I'll try the method from your latest post - cycle counting makes sense. Thanks, everybody.
The recent list of PRs included a lot of Mac-related updates.
I mean, it works well...
