QB64 Phoenix Edition
BallShoot - A bare bones shooter game easy to expand on. - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Games (https://qb64phoenix.com/forum/forumdisplay.php?fid=57)
+---- Thread: BallShoot - A bare bones shooter game easy to expand on. (/showthread.php?tid=2978)

Pages: 1 2 3 4


BallShoot - A bare bones shooter game easy to expand on. - Dav - 08-24-2024

Here's a bare-bones shooter game example that I *think* is easy to learn from and to expand on.  It's pretty simple.  Shoot the balls, don't let any pass you or touch you.  Move the piece at the bottom LEFT/RIGHT using the arrow keys, SPACE shoots.  ESC quits.   If a ball hits you or you let one pass the game is over.

Nothing much of a game, but it was a lazy Saturday and I just wanted to code something.  Maybe some can make use of it.  It would be easy to expand this little shooter.

- Dav

Note: Get the lastest ballshoot v8 HERE

Code: (Select All)
'=============
'ballshoot.bas
'=============
'A bare-bones small shooter game that you can expand on.
'Coded by Dav, AUG/2024 for QB64PE v3.13

'Move player using arrow keys - SPACE bar shoots.
'Shoot the balls. Don't let any hit you or pass you by.

'This is a basic shooter game that is easy enough to
'learn from and expand on so you can make your own game,
'I used balls as an enemy because I had a ball SUB handy,
'and it had a colorful effect.  I used it for the enemy
'as well has for the shots.  I also used an alpha screen
'clearing method using LINE instead of CLS.  This gave
'all the moving pieces a neat trailing/fade effect.

'Game is over if a ball hits you our you let one pass.

'There are many ways to exand this into something better.
'If you do make more out of it, please share it also.


Randomize Timer

balls = 6 'number of balls at one time
shots = 6 'number of shots allowed on screen

Dim ballx(1 To balls) 'ball x pos
Dim bally(1 To balls) 'ball y pos
Dim balld(1 To balls) 'ball direction
Dim ballr(1 To balls) 'ball radius

Dim shotx(1 To shots) 'shot x pos
Dim shoty(1 To shots) 'shot y pos
Dim shota(1 To shots) 'flag if shot is active


Screen _NewImage(640, 480, 32)
_FullScreen _SquarePixels

'set game defaults
score = 0 'score is zero
shotcount = 0 'no active shots
playerx = _Width / 2 'x pos of player
playery = 475 'y pos of player (this stays same)

'generate random ball info
For i = 1 To balls
    ballx(i) = Int(Rnd * _Width) + 1 'x pos
    bally(i) = Int(Rnd * (_Height / 4)) + 1 'y pos
    balld(i) = Int(Rnd * 3) - 1 'moving direction
    ballr(i) = 10 + Int(Rnd * 20) 'radius
Next

'=== main game loop ===

Do

    'this make the trailing fade effect on screen (cooler than doing CLS)
    Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 75), BF

    'add some screen sparklers
    Line (Rnd * _Width, Rnd * _Height)-Step(Rnd * 3, Rnd * 3), _RGBA(255, 255, 255, Rnd * 200), BF

    'handle all balls
    For i = 1 To balls

        'randomly change ball direction by making a -1, 0 or 1 to add to x pos , sometimes.
        If Rnd < .1 Then balld(i) = Int(Rnd * 3) - 1

        'update ball x/y pos
        ballx(i) = ballx(i) + balld(i) 'new ball x pos, with randomly generated direction
        bally(i) = bally(i) + 1 'drift ball y pos down...

        'make sure ball stays in bounds
        If ballx(i) < ballr(i) Then ballx(i) = ballr(i)
        If ballx(i) > (_Width - ballr(i)) Then ballx(i) = (_Width - ballr(i))

        'if you missed shooting a ball and it goes off screen, end game
        If bally(i) > _Height Then End

        'finally draw ball....
        glowball ballx(i), bally(i), ballr(i), 255, 255, 255, 255

    Next

    'draw player along bottom of screen
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(255, Rnd * 125, Rnd * 128), BF
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(0, 0, Rnd * 255), B

    'handle all active shots...
    For i = 1 To shotcount
        If shota(i) Then
            'draw the shot
            glowball shotx(i), shoty(i), 3, 255, 0, 0, 255
            shoty(i) = shoty(i) - 5 'make shot go up
            'if shot goes up off screen...
            If shoty(i) < 0 Then shota(i) = 0 'set shot active flag off
        End If
    Next

    'left/right arrows move player
    If _KeyDown(19200) Then playerx = playerx - 5 'left arrow, move left
    If _KeyDown(19712) Then playerx = playerx + 5 'right arrow, move right

    'make sure player doesn't go off screen
    If playerx < 0 Then
        playerx = 0
    ElseIf playerx > (_Width - 1) Then
        playerx = (_Width - 1)
    End If

    'Spacebar fires a shot
    If _KeyDown(32) Then
        'look for first inactive shot to shoot
        For i = 1 To UBound(shota)
            'if this one is free, and lastshot time passed...
            If shota(i) = 0 And Timer - lastshot > .2 Then
                shotx(i) = playerx 'give it our x/y
                shoty(i) = playery
                shota(i) = 1 'mark it as active
                'update shot count
                If i > shotcount Then shotcount = i
                lastshot = Timer 'mark time of this shot....
                'Note: I'm using shot timer to prevent too rapid fire of shots
                Exit For
            End If
        Next
    End If

    'see if shot hits a ball
    For i = 1 To balls
        For j = 1 To shotcount
            If shota(j) Then
                If Abs(ballx(i) - shotx(j)) < ballr(i) And Abs(bally(i) - shoty(j)) < ballr(i) Then
                    'flash a circle around hit ball
                    Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 255, 255)
                    'Line (0, 0)-(_Width, _Height), _RGBA(255, 255, 255, 10), BF
                    shota(j) = 0 'set shot active flag off
                    bally(i) = 1 'give ball new y pos (top)
                    ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                    ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                    score = score + 1 'update score
                End If
            End If
        Next
    Next

    'if a ball hits player, end game
    For i = 1 To balls
        If Abs(ballx(i) - playerx) < ballr(i) And Abs(bally(i) - playery) < ballr(i) Then End
    Next

    'show score
    Locate 1, 1: Print "Score: "; score;

    _Display

    _Limit 30

Loop Until _KeyDown(27) 'ESC quits

End

Sub glowball (x, y, size, r, g, b, a)
    t = Timer
    For y2 = y - size To y + size
        For x2 = x - size To x + size
            If Sqr((x2 - x) ^ 2 + (y2 - y) ^ 2) <= size Then
                clr = (size - (Sqr((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)))) / size
                noise = Int(Rnd * 50)
                r = Sin(6.005 * t) * size - y2 + size + 255 * 2
                g = Sin(3.001 * t) * size - x2 + size + 255
                b = Sin(2.001 * x2 / size + t + y2 / size) * r + 255
                t = t + .00195
                PSet (x2, y2), _RGBA(clr * r - noise, clr * g - noise, clr * b - noise, a)
            End If
        Next
    Next
End Sub



RE: BallShoot - A bare bones shooter game easy to expand on. - Pete - 08-25-2024

My avatar is probably better off without shooting himself in the balls again. He had a friend who played your game. Ever here of Deadwood Dick?

I managed a 67 on 5th game while Sam was out partying.

+1

Pete

[Image: il_1080xN.4512423474_swrp.jpg]


RE: BallShoot - A bare bones shooter game easy to expand on. - Dav - 08-25-2024

Hmm, I’ve never heard of that comic book before, and I was a serious comic book collector as a kid.  Will have to look it up.  

67 ain’t too shabby.

- Dav


RE: BallShoot - A bare bones shooter game easy to expand on. - Dav - 08-26-2024

A cancelled gig gave me time to play with this game today.  Made it more like a real game, almost a little fun.  Main changes are:

Added Sound effects using PLAY statements
Added health point count (5).  Out of health points, game over.
(missing a ball or hitting one cost you a health point)
Some balls fall faster than others, more challenging.
Added moving shield that protects balls from your shots.
Added simple ground background for player to move on
Added simple game over message when health out.

See how many balls you can shoot down before running out of health.

- Dav

Code: (Select All)
'=============
'ballshoot.bas v2
'=============
'A bare-bones small shooter game that you can expand on.
'Follow game here: https://qb64phoenix.com/forum/showthread.php?tid=2978
'Coded by Dav, AUG/2024 for QB64PE v3.13

'New for v2:  - Added Sound effects using PLAY
'             - Added simple ground background
'             - Some balls fall faster than others
'             - Added moving shield that protects balls
'             - Added health points.  5 hits, game over.
'             - Added simple game over message

'Move player using arrow keys - SPACE bar shoots.
'Shoot the balls. Don't let any hit you or pass you by.
'A moving shield appears now and then to protect balls.
'See how many balls you can shoot down before dying.

'This is a basic shooter game that is easy enough to
'learn from and expand on so you can make your own game,
'I used balls as an enemy because I had a ball SUB handy,
'and it had a colorful effect.  Used it for shots and
'for the moving shield.  I also used an alpha screen
'clearing method using LINE instead of CLS.  This gave
'all the moving pieces a neat trailing/fade effect.

'If you miss a ball, or a ball hits you, then you loose
'a health point.  If you loose all 6 health point then
'the game is over.

'There are many ways to exand this into something better.
'If you do make more out of it, please share it also.


Randomize Timer

balls = 6 'number of balls at one time
shots = 6 'number of shots allowed on screen

Dim ballx(1 To balls) 'ball x pos
Dim bally(1 To balls) 'ball y pos
Dim balld(1 To balls) 'ball direction
Dim ballr(1 To balls) 'ball radius
Dim balls(1 To balls) 'ball drop speed

Dim shotx(1 To shots) 'shot x pos
Dim shoty(1 To shots) 'shot y pos
Dim shota(1 To shots) 'flag if shot is active


Screen _NewImage(640, 480, 32)
_FullScreen _SquarePixels
_PrintMode _KeepBackground

'========
StartGame:
'========

'set game defaults
score = 0 'score is zero
shotcount = 0 'no active shots
playerx = _Width / 2 'x pos of player
playery = 475 'y pos of player (this stays same)
shieldx = -50
shieldy = 50 + (Rnd * 200)
shieldon = 0
health = 5 'full health

'generate random ball info
For i = 1 To balls
    ballx(i) = Int(Rnd * _Width) + 1 'x pos
    bally(i) = Int(Rnd * (_Height / 4)) + 1 'y pos
    balld(i) = Int(Rnd * 3) - 1 'moving direction
    ballr(i) = 10 + Int(Rnd * 20) 'radius
    balls(i) = Int(Rnd * 2) + 1
Next

'draw ground
c = 0
For y = 400 To _Height
    Line (0, y)-(_Width, y), _RGBA(c / 3, c / 2, c, 225 + Rnd * 25), BF
    c = c + .5: If c = 255 Then c = 255
Next

back& = _CopyImage(_Display) 'copy backgraound as image

'=== main game loop ===

Do

    _PutImage (0, 0)-(_Width, _Height), back& 'put background down

    'this make the trailing fade effect on screen (cooler than doing CLS)
    Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 75), BF

    'add some screen sparklers
    Line (Rnd * _Width, Rnd * 375)-Step(Rnd * 3, Rnd * 3), _RGBA(255, 255, 255, Rnd * 200), BF

    'randomly turn moving shield on from time to time
    If Int(Rnd * 500) = 1 Then shieldon = 1: Play "mbt200l32o3ege"

    'if shield is on...
    If shieldon = 1 Then
        shieldx = shieldx + 2
        'if it moves off screen
        If shieldx > _Width Then
            'shield off
            shieldon = 0
            'reset shield values
            shieldx = -50
            shieldy = 50 + (Rnd * 200)
        Else
            'draw shield
            For s = 1 To 50 Step 5
                glowball shieldx + s, shieldy, 5, 255, 255, 255, 200
            Next
        End If
    End If

    'handle all balls
    For i = 1 To balls

        'randomly change ball direction by making a -1, 0 or 1 to add to x pos , sometimes.
        If Rnd < .1 Then balld(i) = Int(Rnd * 3) - 1

        'update ball x/y pos
        ballx(i) = ballx(i) + balld(i) 'new ball x pos, with randomly generated direction
        bally(i) = bally(i) + balls(i) 'drift ball y pos down...

        'make sure ball stays in bounds
        If ballx(i) < ballr(i) Then ballx(i) = ballr(i)
        If ballx(i) > (_Width - ballr(i)) Then ballx(i) = (_Width - ballr(i))

        'if you missed shooting a ball and it goes off screen, lower health
        If bally(i) > _Height Then
            Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
            Play "mbt200l32o1bfc"
            health = health - 1
            Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
            bally(i) = 1 'give ball new y pos (top)
            ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
            ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
            balls(i) = Int(Rnd * 2) + 1 'new ball speed
        End If

        'finally draw ball....
        glowball ballx(i), bally(i), ballr(i), 255, 255, 255, 255

    Next

    'draw player along bottom of screen
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(255, Rnd * 125, Rnd * 128), BF
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(0, 0, Rnd * 255), B

    'handle all active shots...
    For i = 1 To shotcount
        If shota(i) Then
            'draw the shot
            glowball shotx(i), shoty(i), 3, 255, 0, 0, 255
            shoty(i) = shoty(i) - 5 'make shot go up
            'if shot goes up off screen...
            If shoty(i) < 0 Then shota(i) = 0 'set shot active flag off
            'if shot hits shield then shot off
            If shotx(i) > shieldx And shotx(i) < (shieldx + 50) Then
                If shoty(i) > shieldy And shoty(i) < shieldy + 5 Then
                    Circle (shotx(i), shoty(i)), 3, _RGB(255, 255, 255)
                    Play "mbt200l32o6fb"
                    shota(i) = 0
                End If
            End If
        End If
    Next

    'left/right arrows move player
    If _KeyDown(19200) Then playerx = playerx - 7 'left arrow, move left
    If _KeyDown(19712) Then playerx = playerx + 7 'right arrow, move right

    'make sure player doesn't go off screen
    If playerx < 0 Then
        playerx = 0
    ElseIf playerx > (_Width - 1) Then
        playerx = (_Width - 1)
    End If

    'Spacebar fires a shot
    If _KeyDown(32) Then
        'look for first inactive shot to shoot
        For i = 1 To UBound(shota)
            'if this one is free, and lastshot time passed...
            If shota(i) = 0 And Timer - lastshot > .2 Then
                Play "mbt200l64o4bfag"
                shotx(i) = playerx 'give it our x/y
                shoty(i) = playery
                shota(i) = 1 'mark it as active
                'update shot count
                If i > shotcount Then shotcount = i
                lastshot = Timer 'mark time of this shot....
                'Note: I'm using shot timer to prevent too rapid fire of shots
                Exit For
            End If
        Next
    End If

    'see if shot hits a ball
    For i = 1 To balls
        For j = 1 To shotcount
            If shota(j) Then
                If Abs(ballx(i) - shotx(j)) < ballr(i) And Abs(bally(i) - shoty(j)) < ballr(i) Then
                    'flash a circle around hit ball
                    Play "mbt200l64o2cdefgabag"
                    Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 255, 255)
                    shota(j) = 0 'set shot active flag off
                    bally(i) = 1 'give ball new y pos (top)
                    ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                    ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                    balls(i) = Int(Rnd * 2) + 1 'new ball speed
                    score = score + 1 'update score
                End If
            End If
        Next
    Next

    'if a ball hits player, health decrease
    For i = 1 To balls
        If Abs(ballx(i) - playerx) < ballr(i) And Abs(bally(i) - playery) < ballr(i) Then
            Play "mbt200l32o1bfc"
            Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
            bally(i) = 1 'give ball new y pos (top)
            ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
            ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
            balls(i) = Int(Rnd * 2) + 1 'new ball speed
            Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
            health = health - 1
        End If
    Next

    'show score
    _PrintString (1, 1), "Score:" + Str$(score)

    'draw health status
    hcount = 1
    For h = 1 To 50 Step 10
        If health >= hcount Then
            Line (580 + h, 5)-(580 + h + 5, 10), _RGB(0, 255, 0), BF
        Else
            Line (580 + h, 5)-(580 + h + 5, 10), _RGB(0, 255, 0), B
        End If
        hcount = hcount + 1
    Next

    'if out of health, game over
    If health = 0 Then
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 128), BF
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 255), B
        _PrintMode _KeepBackground
        _PrintString (275, 225), "  GAME OVER"
        _PrintString (275, 245), "OUT OF HEALTH"
        _PrintString (275, 265), "  SCORE:" + Str$(score)
        _Display
        _Delay 3
        End
    End If

    _Display

    _Limit 30

Loop Until _KeyDown(27) 'ESC quits

End

Sub glowball (x, y, size, r, g, b, a)
    t = Timer
    For y2 = y - size To y + size
        For x2 = x - size To x + size
            If Sqr((x2 - x) ^ 2 + (y2 - y) ^ 2) <= size Then
                clr = (size - (Sqr((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)))) / size
                noise = Int(Rnd * 50)
                r = Sin(6.005 * t) * size - y2 + size + 255 * 2
                g = Sin(3.001 * t) * size - x2 + size + 255
                b = Sin(2.001 * x2 / size + t + y2 / size) * r + 255
                t = t + .00195
                PSet (x2, y2), _RGBA(clr * r - noise, clr * g - noise, clr * b - noise, a)
            End If
        Next
    Next
End Sub



RE: BallShoot - A bare bones shooter game easy to expand on. - TerryRitchie - 08-26-2024

Fun, 135.


RE: BallShoot - A bare bones shooter game easy to expand on. - NakedApe - 08-27-2024

That is fun! Very 1977 in so few lines. I want the gun to move faster, but I guess you have to be strategic...


RE: BallShoot - A bare bones shooter game easy to expand on. - SierraKen - 08-27-2024

This is awesome Dav! Kinda like a futuristic version of Space Invaders meets pinball... Smile


RE: BallShoot - A bare bones shooter game easy to expand on. - Dav - 08-27-2024

Hey, thanks guys!   I couldn't stop messing with this tonight, had fun adding things.  New version:

Added 2nd shield, made them both random sizes.
A green health pill drops from time to time, giving you +1 health point
A yellow super pill drops sometimes making you invincible for 15 seconds
Game restarts when over.  Hi score now kept.  Few more tweaks.

- Dav


Code: (Select All)
'=============
'ballshoot.bas v3
'=============
'A bare-bones small shooter game that you can expand on.
'Follow game here: https://qb64phoenix.com/forum/showthread.php?tid=2978
'Coded by Dav, AUG/2024 for QB64PE v3.13

'New for v3:  - Added 2nd moving shield, both now random sizes
'            - Green Health point pill drops randomly
'              (catch it to restore +1 health point)
'            - Yellow super pill gives invincible mode (no hurt)
'              (catch it to be invincible for 15 seconds)
'            - Flashing yellow border when health getting low
'            - Flashing Red border when health critically low
'            - Balls are out of sight when the game starts
'            - Game restarts when over.  ESC quits.
'            - HI SCORE now shown

'Move player using arrow keys - SPACE bar shoots.
'Shoot the balls. Don't let any hit you or pass you by.
'A moving shield appears now and then to protect balls.
'See how many balls you can shoot down before dying.
'Catch green pill to increase your health points +1.
'Catch yellow pill to be invincible for 15 seconds.

'This is a basic shooter game that is easy enough to
'learn from and expand on so you can make your own game,
'I used balls as an enemy because I had a ball SUB handy,
'and it had a colorful effect.  Used it for shots and
'for the moving shield.  I also used an alpha screen
'clearing method using LINE instead of CLS.  This gave
'all the moving pieces a neat trailing/fade effect.

'If you miss a ball, or a ball hits you, then you loose
'a health point.  If you loose all 6 health point then
'the game is over.

'There are many ways to exand this into something better.
'If you do make more out of it, please share it also.


Randomize Timer

balls = 6 'number of balls at one time
shots = 6 'number of shots allowed on screen

Dim ballx(1 To balls) 'ball x pos
Dim bally(1 To balls) 'ball y pos
Dim balld(1 To balls) 'ball direction
Dim ballr(1 To balls) 'ball radius
Dim balls(1 To balls) 'ball drop speed

Dim shotx(1 To shots) 'shot x pos
Dim shoty(1 To shots) 'shot y pos
Dim shota(1 To shots) 'flag if shot is active

Screen _NewImage(640, 480, 32)
_FullScreen _SquarePixels
_PrintMode _KeepBackground

'draw a background to use
c = 0
For y = 425 To _Height
    Line (0, y)-(_Width, y), _RGBA(c / 3, c / 2, c, 225 + Rnd * 25), BF
    c = c + 1: If c = 255 Then c = 255
Next

back& = _CopyImage(_Display) 'copy backgraound as imag

highscore = 0


'========
StartGame:
'========

'set game defaults
score = 0 'score is zero
shotcount = 0 'no active shots
playerx = _Width / 2 'x pos of player
playery = 475 'y pos of player (this stays same)

'shield 1 (moves left to right)
shield1s = 50 + Int(Rnd * 50) 'random sixe 50-100
shield1x = -shield1s 'starting position
shield1y = shield1s + (Rnd * 300)
shield1on = 0

'shield 2 (moves right to left)
shield2s = 50 + Int(Rnd * 50) 'random sixe 50-100
shield2x = _Width + shield2s
shield2y = shield2s + (Rnd * 300)
shield2on = 0

'healthpill
healthpillx = 50 + Int(Rnd * _Width - 100)
healthpilly = -10
healthpillon = 0

health = 5 'start with full health

'superpill
superpillx = 50 + Int(Rnd * _Width - 100)
superpilly = -10
superpillon = 0

'generate random ball info
For i = 1 To balls
    ballx(i) = Int(Rnd * _Width) + 1 'x pos
    bally(i) = Int(Rnd * (_Height / 4)) - 200 'y pos
    balld(i) = Int(Rnd * 3) - 1 'moving direction
    ballr(i) = 10 + Int(Rnd * 20) 'radius
    balls(i) = Int(Rnd * 2) + 1
Next

'=== main game loop ===

Do

    _PutImage (1, 1)-(_Width - 1, _Height - 1), back& 'put background down

    'this make the trailing fade effect on screen (cooler than doing CLS)
    Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 75), BF

    'add some screen sparklers
    Line (Rnd * _Width, Rnd * 400)-Step(Rnd * 3, Rnd * 3), _RGBA(255, 255, 255, Rnd * 200), BF

    'if health is getting low, show flashing yellow border around screen
    If health = 2 Then Line (0, 0)-(_Width - 1, _Height - 1), _RGBA(255, 255, 0, Rnd * 40), B

    'if health is critially low, show flashing red border around screen
    If health = 1 Then Line (0, 0)-(_Width - 1, _Height - 1), _RGBA(255, 0, 0, Rnd * 40), B

    'randomly turn moving shield 1 on from time to time
    If Int(Rnd * 500) = 1 And shield1on = 0 Then shield1on = 1: Play "mbt200l32o3ege"

    'randomly turn moving shield 2 on from time to time
    If Int(Rnd * 500) = 1 And shield2on = 0 Then shield2on = 1: Play "mbt200l32o3ege"

    'if shield 1 is on...
    If shield1on = 1 Then
        shield1x = shield1x + 2
        'if it moves off screen
        If shield1x > _Width Then
            'shield off
            shield1on = 0
            'reset shield values
            shield1s = 50 + Int(Rnd * 50)
            shield1x = -shield1s
            shield1y = 50 + (Rnd * 300)
        Else
            'draw shield 1
            For s = 1 To shield1s Step 5
                glowball shield1x + s, shield1y, 5, 255, 255, 255, 200
            Next
        End If
    End If

    'if shield 2 is on...
    If shield2on = 1 Then
        shield2x = shield2x - 2
        'if it moves off screen
        If shield2x < -shield2s Then
            'shield off
            shield2on = 0
            'reset shield values
            shield2s = 50 + Int(Rnd * 50)
            shield2x = _Width + shield2s
            shield2y = 50 + (Rnd * 300)
        Else
            'draw shield 2
            For s = 1 To shield2s Step 5
                glowball shield2x + s, shield2y, 5, 255, 255, 255, 200
            Next
        End If
    End If

    'randomly drop a health pillfrom time to time
    If Int(Rnd * 600) = 1 And healthpillon = 0 Then healthpillon = 1: Play "mbt200l16o2baga"

    If healthpillon = 1 Then
        healthpilly = healthpilly + 3
        'if it moves off screen
        If healthpilly + 10 > _Height Then
            'healthpill off
            healthpillon = 0
            'reset healthpill values
            healthpillx = 50 + Int(Rnd * _Width - 100)
            healthpilly = -10
            healthpillon = 0
        Else
            'draw healthpill
            Line (healthpillx, healthpilly)-(healthpillx + 10, healthpilly + 10), _RGB(0, 255, 0), BF
        End If

        'if healthpill hits player, add point to health
        If Abs(healthpillx - playerx) < 20 And Abs(healthpilly - playery) < 20 Then
            Play "mbt200l16o2cegec"
            Line (0, 0)-(_Width, _Height), _RGBA(0, 255, 0, 30), BF
            If health < 5 Then health = health + 1
            'reset healthpill values
            healthpillx = 50 + Int(Rnd * _Width - 100)
            healthpilly = -10
            healthpillon = 0
        End If
    End If

    'randomly drop a super pill from time to time (super invincible mode)
    If Int(Rnd * 1000) = 1 And superpillon = 0 And supermode = 0 Then superpillon = 1: Play "mbt200l16o3g,ee,c"

    If superpillon = 1 Then
        superpilly = superpilly + 3
        'if it moves off screen
        If superpilly + 10 > _Height Then
            'superpill off
            superpillon = 0
            'reset superpill values
            superpillx = 50 + Int(Rnd * _Width - 100)
            superpilly = -10
            superpillon = 0
        Else
            'draw superpill
            Line (superpillx, superpilly)-(superpillx + 10, superpilly + 10), _RGB(255, 255, 0), BF
        End If

        'if superpill hits player, start invincible mode
        If Abs(superpillx - playerx) < 20 And Abs(superpilly - playery) < 20 Then
            Play "mbt200l16o2c,eg,eo3c,o2ge"
            Line (0, 0)-(_Width, _Height), _RGBA(255, 255, 0, 30), BF
            supermode = 1: supertime = Timer
            'reset healthpill values
            superpillx = 50 + Int(Rnd * _Width - 100)
            superpilly = -10
            superpillon = 0
        End If
    End If

    'handle all balls
    For i = 1 To balls

        'randomly change ball direction by making a -1, 0 or 1 to add to x pos , sometimes.
        If Rnd < .1 Then balld(i) = Int(Rnd * 3) - 1

        'update ball x/y pos
        ballx(i) = ballx(i) + balld(i) 'new ball x pos, with randomly generated direction
        bally(i) = bally(i) + balls(i) 'drift ball y pos down...

        'make sure ball stays in bounds
        If ballx(i) < ballr(i) Then ballx(i) = ballr(i)
        If ballx(i) > (_Width - ballr(i)) Then ballx(i) = (_Width - ballr(i))

        'if you missed shooting a ball and it goes off screen, lower health
        If bally(i) > _Height Then
            'hurt health only if not in spuermode
            If supermode = 0 Then
                Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
                Play "mbt200l32o1bfc"
                health = health - 1
                Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
            End If
            bally(i) = 1 'give ball new y pos (top)
            ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
            ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
            balls(i) = Int(Rnd * 2) + 1 'new ball speed
        End If

        'finally draw ball....
        glowball ballx(i), bally(i), ballr(i), 255, 255, 255, 255

    Next

    'draw player along bottom of screen
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(255, Rnd * 125, Rnd * 128), BF
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(0, 0, Rnd * 255), B

    'if in supermode, give a protective shield
    If supermode = 1 Then Circle (playerx, playery), 10, _RGB(255, 255, 0)

    'handle all active shots...
    For i = 1 To shotcount
        If shota(i) Then
            'draw the shot
            glowball shotx(i), shoty(i), 3, 255, 0, 0, 255
            shoty(i) = shoty(i) - 5 'make shot go up
            'if shot goes up off screen...
            If shoty(i) < 0 Then shota(i) = 0 'set shot active flag off
            'if shot hits shield1 then shot off
            If shotx(i) > shield1x And shotx(i) < (shield1x + shield1s) Then
                If shoty(i) > shield1y And shoty(i) < shield1y + 5 Then
                    Circle (shotx(i), shoty(i)), 5, _RGB(255, 255, 255)
                    Play "mbt200l32o6fb"
                    shota(i) = 0
                End If
            End If
            'if shot hits shield2 then shot off
            If shotx(i) > shield2x And shotx(i) < (shield2x + shield2s) Then
                If shoty(i) > shield2y And shoty(i) < shield2y + 5 Then
                    Circle (shotx(i), shoty(i)), 5, _RGB(255, 255, 255)
                    Play "mbt200l32o6fb"
                    shota(i) = 0
                End If
            End If

        End If
    Next

    'left/right arrows move player
    If _KeyDown(19200) Then playerx = playerx - 7 'left arrow, move left
    If _KeyDown(19712) Then playerx = playerx + 7 'right arrow, move right

    'make sure player doesn't go off screen
    If playerx < 0 Then
        playerx = 0
    ElseIf playerx > (_Width - 1) Then
        playerx = (_Width - 1)
    End If

    'Spacebar fires a shot
    If _KeyDown(32) Then
        'look for first inactive shot to shoot
        For i = 1 To UBound(shota)
            'if this one is free, and lastshot time passed...
            If shota(i) = 0 And Timer - lastshot > .2 Then
                Play "mbt200l64o4bfag"
                shotx(i) = playerx 'give it our x/y
                shoty(i) = playery
                shota(i) = 1 'mark it as active
                'update shot count
                If i > shotcount Then shotcount = i
                lastshot = Timer 'mark time of this shot....
                'Note: I'm using shot timer to prevent too rapid fire of shots
                Exit For
            End If
        Next
    End If

    'see if shot hits a ball
    For i = 1 To balls
        For j = 1 To shotcount
            If shota(j) Then
                If Abs(ballx(i) - shotx(j)) < ballr(i) And Abs(bally(i) - shoty(j)) < ballr(i) Then
                    'flash a circle around hit ball
                    Play "mbt200l64o2cdefgabag"
                    Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 255, 255)
                    shota(j) = 0 'set shot active flag off
                    bally(i) = 1 'give ball new y pos (top)
                    ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                    ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                    balls(i) = Int(Rnd * 2) + 1 'new ball speed
                    score = score + 1 'update score
                End If
            End If
        Next
    Next

    'if a ball hits player, health decrease
    For i = 1 To balls
        If Abs(ballx(i) - playerx) < ballr(i) And Abs(bally(i) - playery) < ballr(i) Then
            'only if not in supermode
            If supermode = 0 Then
                Play "mbt200l32o1bfc"
                Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
                bally(i) = 1 'give ball new y pos (top)
                ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                balls(i) = Int(Rnd * 2) + 1 'new ball speed
                Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
                health = health - 1
            End If
        End If
    Next

    'show player score
    _PrintString (2, 2), "SCORE:" + Str$(score)

    If score >= highscore Then highscore = score

    'show HI Score
    _PrintString (300, 2), "HI:" + Str$(highscore)

    'draw health status
    hcount = 1
    For h = 1 To 50 Step 10
        If health >= hcount Then
            Line (580 + h, 5)-(580 + h + 5, 10), _RGB(0, 255, 0), BF
        Else
            Line (580 + h, 5)-(580 + h + 5, 10), _RGB(0, 255, 0), B
        End If
        hcount = hcount + 1
    Next

    'if in supermode, check supertimer.  If over 15 seconds, tunn off
    If supermode = 1 Then
        If Timer - supertime > 15 Then supermode = 0
    End If

    'if out of health, game over
    If health = 0 Then
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 128), BF
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 255), B
        _PrintMode _KeepBackground
        _PrintString (275, 225), "  GAME OVER"
        _PrintString (275, 245), "OUT OF HEALTH"
        _PrintString (275, 265), "  SCORE:" + Str$(score)
        _Display
        _Delay 5
        Cls: _Display
        GoTo StartGame
    End If

    _Display

    _Limit 30

Loop Until _KeyDown(27) 'ESC quits

End

Sub glowball (x, y, size, r, g, b, a)
    t = Timer
    For y2 = y - size To y + size
        For x2 = x - size To x + size
            If Sqr((x2 - x) ^ 2 + (y2 - y) ^ 2) <= size Then
                clr = (size - (Sqr((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)))) / size
                noise = Int(Rnd * 50)
                r = Sin(6.005 * t) * size - y2 + size + 255 * 2
                g = Sin(3.001 * t) * size - x2 + size + 255
                b = Sin(2.001 * x2 / size + t + y2 / size) * r + 255
                t = t + .00195
                PSet (x2, y2), _RGBA(clr * r - noise, clr * g - noise, clr * b - noise, a)
            End If
        Next
    Next
End Sub



RE: BallShoot - A bare bones shooter game easy to expand on. - SierraKen - 08-27-2024

Wild stuff! I forgot to tell you that this game is VERY hard... I can only play for like 5 seconds until the game is over. It's because too many balls come down at once and it's impossible to get them all. It might help if you added mouse support to your shooter. That way you can shoot more of them. I really hope you make this easier because it's really fun.


RE: BallShoot - A bare bones shooter game easy to expand on. - Dav - 08-27-2024

Yeah, it's kinda hard for me too, @SierraKen.  Not very hard for Terry though it looks like, lol.  I've given us some more help in this version.  Starts easier, but gets harder.  You can play longer now.  New for v4:

Increased health points max to 7
Increased number of active shots you can have.
Increased health status display (easier to notice)
Balls don't reappear so quickly at first, but as time moves on they will.
Shields move across with a wobble now, are in the way longer.
Added game start and game over sound effects.
Few more tweaks...

- Dav

Code: (Select All)
'=============
'ballshoot.bas v4
'=============
'A bare-bones small shooter game that you can expand on.
'Follow game here: https://qb64phoenix.com/forum/showthread.php?tid=2978
'Coded by Dav, AUG/2024 for QB64PE v3.13

'New for v4:  - Added game start and game over sound effects.
'            - Balls don't reappear so quickly at first, but
'              as time moves on they respawn more frequently.
'            - Increased health max to 7, live longer and prosper.
'            - Increased number of active shots you can have.
'              (that's right, you now have a seven shooter)
'            - Increased health status display (easier to notice)
'            - Shields move across with a wobble, in the way more.
'              (have to give the enemy something more too...)
'            - Fade out screen when game over (looks better)
'            - Added New Hi Score notice after game, if you got it.

'Move player using arrow keys - SPACE bar shoots.
'Shoot the balls. Don't let any hit you or pass you by.
'A moving shield appears now and then to protect balls.
'See how many balls you can shoot down before dying.
'Catch green pill to increase your health points +1.
'Catch yellow pill to be invincible for 15 seconds.

'This is a basic shooter game that is easy enough to
'learn from and expand on so you can make your own game,
'I used balls as an enemy because I had a ball SUB handy,
'and it had a colorful effect.  Used it for shots and
'for the moving shield.  I also used an alpha screen
'clearing method using LINE instead of CLS.  This gave
'all the moving pieces a neat trailing/fade effect.

'If you miss a ball, or a ball hits you, then you loose
'a health point.  If you loose all 6 health point then
'the game is over.

'There are many ways to exand this into something better.
'If you do make more out of it, please share it also.


Randomize Timer

balls = 6 'number of balls at one time
shots = 7 'number of shots allowed on screen

Dim ballx(1 To balls) 'ball x pos
Dim bally(1 To balls) 'ball y pos
Dim balld(1 To balls) 'ball direction
Dim ballr(1 To balls) 'ball radius
Dim balls(1 To balls) 'ball drop speed

Dim shotx(1 To shots) 'shot x pos
Dim shoty(1 To shots) 'shot y pos
Dim shota(1 To shots) 'flag if shot is active

Screen _NewImage(640, 480, 32)
_FullScreen _SquarePixels
_PrintMode _KeepBackground

'draw a background to use
c = 0
For y = 425 To _Height
    Line (0, y)-(_Width, y), _RGBA(c / 3, c / 2, c, 225 + Rnd * 25), BF
    c = c + 1: If c = 255 Then c = 255
Next

back& = _CopyImage(_Display) 'copy backgraound as imag

highscore = 0


'========
StartGame:
'========

'start sound effect
Play "mbt200l16o2e,gg,o3cc,el8e,gl16c,el4c,e,g"

'set game defaults
score = 0 'score is zero
shotcount = 0 'no active shots
playerx = _Width / 2 'x pos of player
playery = 475 'y pos of player (this stays same)
respawny = -300

'shield 1 (moves left to right)
shield1s = 50 + Int(Rnd * 50) 'random sixe 50-100
shield1x = -shield1s 'starting position
shield1y = shield1s + (Rnd * 300)
shield1on = 0

'shield 2 (moves right to left)
shield2s = 50 + Int(Rnd * 50) 'random sixe 50-100
shield2x = _Width + shield2s
shield2y = shield2s + (Rnd * 300)
shield2on = 0

'healthpill
healthpillx = 50 + Int(Rnd * _Width - 100)
healthpilly = -10
healthpillon = 0

healthmax = 7
health = 7 'start with full health

'superpill
superpillx = 50 + Int(Rnd * _Width - 100)
superpilly = -10
superpillon = 0

'generate random ball info
For i = 1 To balls
    ballx(i) = Int(Rnd * _Width) + 1 'x pos
    bally(i) = Int(Rnd * (_Height / 4)) + respawny 'y pos
    balld(i) = Int(Rnd * 3) - 1 'moving direction
    ballr(i) = 10 + Int(Rnd * 20) 'radius
    balls(i) = Int(Rnd * 2) + 1
Next

'=== main game loop ===

Do

    _PutImage (1, 1)-(_Width - 1, _Height - 1), back& 'put background down

    'this make the trailing fade effect on screen (cooler than doing CLS)
    Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 75), BF

    'add some screen sparklers
    Line (Rnd * _Width, Rnd * 400)-Step(Rnd * 3, Rnd * 3), _RGBA(255, 255, 255, Rnd * 200), BF

    'if health is getting low, show flashing yellow border around screen
    If health = 2 Then Line (0, 0)-(_Width - 1, _Height - 1), _RGBA(255, 255, 0, Rnd * 40), B

    'if health is critially low, show flashing red border around screen
    If health = 1 Then Line (0, 0)-(_Width - 1, _Height - 1), _RGBA(255, 0, 0, Rnd * 40), B

    'randomly turn moving shield 1 on from time to time
    If Int(Rnd * 500) = 1 And shield1on = 0 Then shield1on = 1: Play "mbt200l32o3ege"

    'randomly turn moving shield 2 on from time to time
    If Int(Rnd * 500) = 1 And shield2on = 0 Then shield2on = 1: Play "mbt200l32o3ege"

    'if shield 1 is on...
    If shield1on = 1 Then
        If Rnd < .1 Then wobble = Int(Rnd * 3) - 1
        shield1x = shield1x + 2 + wobble
        'if it moves off screen
        If shield1x > _Width Then
            'shield off
            shield1on = 0
            'reset shield values
            shield1s = 50 + Int(Rnd * 50)
            shield1x = -shield1s
            shield1y = 50 + (Rnd * 300)
        Else
            'draw shield 1
            For s = 1 To shield1s Step 5
                glowball shield1x + s, shield1y, 5, 255, 255, 255, 200
            Next
        End If
    End If

    'if shield 2 is on...
    If shield2on = 1 Then
        If Rnd < .1 Then wobble = Int(Rnd * 3) - 1
        shield2x = shield2x - 1 - wobble
        'if it moves off screen
        If shield2x < -shield2s Then
            'shield off
            shield2on = 0
            'reset shield values
            shield2s = 50 + Int(Rnd * 50)
            shield2x = _Width + shield2s
            shield2y = 50 + (Rnd * 300)
        Else
            'draw shield 2
            For s = 1 To shield2s Step 5
                glowball shield2x + s, shield2y, 5, 255, 255, 255, 200
            Next
        End If
    End If

    'randomly drop a health pillfrom time to time
    If Int(Rnd * 600) = 1 And healthpillon = 0 Then healthpillon = 1: Play "mbt200l16o2baga"

    If healthpillon = 1 Then
        healthpilly = healthpilly + 3
        'if it moves off screen
        If healthpilly + 10 > _Height Then
            'healthpill off
            healthpillon = 0
            'reset healthpill values
            healthpillx = 50 + Int(Rnd * _Width - 100)
            healthpilly = -10
            healthpillon = 0
        Else
            'draw healthpill
            Line (healthpillx, healthpilly)-(healthpillx + 10, healthpilly + 10), _RGB(0, 255, 0), BF
        End If

        'if healthpill hits player, add point to health
        If Abs(healthpillx - playerx) < 20 And Abs(healthpilly - playery) < 20 Then
            Play "mbt200l16o2cegec"
            Line (0, 0)-(_Width, _Height), _RGBA(0, 255, 0, 30), BF
            If health < healthmax Then health = health + 1
            'reset healthpill values
            healthpillx = 50 + Int(Rnd * _Width - 100)
            healthpilly = -10
            healthpillon = 0
        End If
    End If

    'randomly drop a super pill from time to time (super invincible mode)
    If Int(Rnd * 1000) = 1 And superpillon = 0 And supermode = 0 Then superpillon = 1: Play "mbt200l16o3g,ee,c"

    If superpillon = 1 Then
        superpilly = superpilly + 3
        'if it moves off screen
        If superpilly + 10 > _Height Then
            'superpill off
            superpillon = 0
            'reset superpill values
            superpillx = 50 + Int(Rnd * _Width - 100)
            superpilly = -10
            superpillon = 0
        Else
            'draw superpill
            Line (superpillx, superpilly)-(superpillx + (10), superpilly + (10)), _RGB(255, 255, 0), BF
        End If

        'if superpill hits player, start invincible mode
        If Abs(superpillx - playerx) < 20 And Abs(superpilly - playery) < 20 Then
            Play "mbt200l16o2c,eg,eo3c,o2ge"
            Line (0, 0)-(_Width, _Height), _RGBA(255, 255, 0, 30), BF
            supermode = 1: supertime = Timer
            'reset healthpill values
            superpillx = 50 + Int(Rnd * _Width - 100)
            superpilly = -10
            superpillon = 0
        End If
    End If

    'handle all balls
    For i = 1 To balls

        'randomly change ball direction by making a -1, 0 or 1 to add to x pos , sometimes.
        If Rnd < .1 Then balld(i) = Int(Rnd * 3) - 1

        'update ball x/y pos
        ballx(i) = ballx(i) + balld(i) 'new ball x pos, with randomly generated direction
        bally(i) = bally(i) + balls(i) 'drift ball y pos down...

        'make sure ball stays in bounds
        If ballx(i) < ballr(i) Then ballx(i) = ballr(i)
        If ballx(i) > (_Width - ballr(i)) Then ballx(i) = (_Width - ballr(i))

        'if you missed shooting a ball and it goes off screen, lower health
        If bally(i) > _Height Then
            'hurt health only if not in spuermode
            If supermode = 0 Then
                Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
                Play "mbt200l32o1bfc"
                health = health - 1
                Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
            End If
            bally(i) = respawny 'new y pos
            ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
            ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
            balls(i) = Int(Rnd * 2) + 1 'new ball speed
        End If

        'finally draw ball....
        glowball ballx(i), bally(i), ballr(i), 255, 255, 255, 255

    Next

    'draw player along bottom of screen
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(255, Rnd * 125, Rnd * 128), BF
    Line (playerx - 5, playery - 5)-(playerx + 5, playery + 5), _RGB(0, 0, Rnd * 255), B

    'if in supermode, give a protective shield
    If supermode = 1 Then Circle (playerx, playery), 10, _RGB(Rnd * 255, Rnd * 255, Rnd * 255)

    'handle all active shots...
    For i = 1 To shotcount
        If shota(i) Then
            'draw the shot
            glowball shotx(i), shoty(i), 3, 255, 0, 0, 255
            shoty(i) = shoty(i) - 5 'make shot go up
            'if shot goes up off screen...
            If shoty(i) < 0 Then shota(i) = 0 'set shot active flag off
            'if shot hits shield1 then shot off
            If shotx(i) > shield1x And shotx(i) < (shield1x + shield1s) Then
                If shoty(i) > shield1y And shoty(i) < shield1y + 5 Then
                    Circle (shotx(i), shoty(i)), 5, _RGB(255, 255, 255)
                    Play "mbt200l32o6fb"
                    shota(i) = 0
                End If
            End If
            'if shot hits shield2 then shot off
            If shotx(i) > shield2x And shotx(i) < (shield2x + shield2s) Then
                If shoty(i) > shield2y And shoty(i) < shield2y + 5 Then
                    Circle (shotx(i), shoty(i)), 5, _RGB(255, 255, 255)
                    Play "mbt200l32o6fb"
                    shota(i) = 0
                End If
            End If

        End If
    Next

    'left/right arrows move player
    If _KeyDown(19200) Then playerx = playerx - 7 'left arrow, move left
    If _KeyDown(19712) Then playerx = playerx + 7 'right arrow, move right

    'make sure player doesn't go off screen
    If playerx < 0 Then
        playerx = 0
    ElseIf playerx > (_Width - 1) Then
        playerx = (_Width - 1)
    End If

    'Spacebar fires a shot
    If _KeyDown(32) Then
        'look for first inactive shot to shoot
        For i = 1 To UBound(shota)
            'if this one is free, and lastshot time passed...
            If shota(i) = 0 And Timer - lastshot > .2 Then
                Play "mbt200l64o4bfag"
                shotx(i) = playerx 'give it our x/y
                shoty(i) = playery
                shota(i) = 1 'mark it as active
                'update shot count
                If i > shotcount Then shotcount = i
                lastshot = Timer 'mark time of this shot....
                'Note: I'm using shot timer to prevent too rapid fire of shots
                Exit For
            End If
        Next
    End If

    'see if shot hits a ball
    For i = 1 To balls
        For j = 1 To shotcount
            If shota(j) Then
                If Abs(ballx(i) - shotx(j)) < ballr(i) And Abs(bally(i) - shoty(j)) < ballr(i) Then
                    'flash a circle around hit ball
                    Play "mbt200l64o2cdefgabag"
                    Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 255, 255)
                    shota(j) = 0 'set shot active flag off
                    bally(i) = respawny 'y pos
                    ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                    ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                    balls(i) = Int(Rnd * 2) + 1 'new ball speed
                    score = score + 1 'update score
                End If
            End If
        Next
    Next

    'if a ball hits player, health decrease
    For i = 1 To balls
        If Abs(ballx(i) - playerx) < ballr(i) And Abs(bally(i) - playery) < ballr(i) Then
            'only if not in supermode
            If supermode = 0 Then
                Play "mbt200l32o1bfc"
                Circle (ballx(i), bally(i)), ballr(i), _RGB(255, 0, 0)
                bally(i) = respawny
                ballx(i) = Int(Rnd * _Width) + 1 'give ball a new x pos
                ballr(i) = 10 + Int(Rnd * 20) 'give ball new radius
                balls(i) = Int(Rnd * 2) + 1 'new ball speed
                Line (0, 0)-(_Width, _Height), _RGBA(255, 0, 0, 30), BF
                health = health - 1
            End If
        End If
    Next

    'increase respawning y pos of balls as time goes on
    'this makes them come down more frequently as you go
    If respawny < 0 Then respawny = respawny + .1

    'show player score
    _PrintString (2, 2), "SCORE:" + Str$(score)

    If score >= highscore Then highscore = score

    'show HI Score
    Color _RGB(255, 255, 0)
    _PrintString (300, 2), "HI:" + Str$(highscore)
    Color _RGB(255, 255, 255)

    'draw health status
    hcount = 1
    For h = 1 To (healthmax * 10) Step 10
        If health >= hcount Then
            Line (560 + h, 5)-(560 + h + 5, 15), _RGB(0, 255, 0), BF
        Else
            Line (560 + h, 5)-(560 + h + 5, 15), _RGB(0, 255, 0), B
        End If
        hcount = hcount + 1
    Next

    'if in supermode, check supertimer.  If over 15 seconds, tunn off
    If supermode = 1 Then
        If Timer - supertime > 15 Then supermode = 0
    End If

    'if out of health, game over
    If health = 0 Then
        'game over sound effect
        Play "mbt200l32o4b,ga,fg,ef,de,cd,o3bo4c,o3ab,ga,fg,ef,de,cd,o2bo3c,o2ab,ga,fg,el8f,d"
        'fade out screen to black
        For f = 1 To 100
            Line (0, 0)-(_Width, _Height), _RGBA(0, 0, 0, 20), BF
            _Display
            _Delay .01
        Next
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 128), BF
        Line (250, 200)-(400, 300), _RGBA(128, 128, 128, 255), B
        _PrintString (275, 225), "  GAME OVER"
        _PrintString (275, 245), "OUT OF HEALTH"
        _PrintString (275, 265), "  SCORE:" + Str$(score)
        If score = highscore Then _PrintString (275, 340), "NEW HI SCORE!"
        _Display
        _Delay 6
        Cls: _Display
        GoTo StartGame
    End If

    _Display

    _Limit 30

Loop Until _KeyDown(27) 'ESC quits

End

Sub glowball (x, y, size, r, g, b, a)
    t = Timer
    For y2 = y - size To y + size
        For x2 = x - size To x + size
            If Sqr((x2 - x) ^ 2 + (y2 - y) ^ 2) <= size Then
                clr = (size - (Sqr((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y)))) / size
                noise = Int(Rnd * 50)
                r = Sin(6.005 * t) * size - y2 + size + 255 * 2
                g = Sin(3.001 * t) * size - x2 + size + 255
                b = Sin(2.001 * x2 / size + t + y2 / size) * r + 255
                t = t + .00195
                PSet (x2, y2), _RGBA(clr * r - noise, clr * g - noise, clr * b - noise, a)
            End If
        Next
    Next
End Sub