none
Only one bullet present in the graphics window at a time RRS feed

  • Question

  • Hi everyone,

    I'm coding a game that involves a moving cannon (up and down) that shoots bullets (space bar). Currently when I hit the space bar multiple bullets fire from the cannon. I'd like only ONE bullet to be present in the graphics window at a time. After the bullet has moved out of the graphics window the player can then shoot another bullet.

    I've attempted this using the sub 'movebullet' (see code below). But I'm not sure if i'm on the right track.

    Thanks in advance :) 

    ______________________________

    '
    • Edited by Sarah H12 Thursday, August 15, 2019 9:50 AM
    Sunday, August 11, 2019 11:30 AM

Answers

  • Hi,

    First a suggestion to not mix your main code between subroutines - put all the subroutines after all your main code.  This makes it easier to read and develop.

    Secondly, the main issue is that the bullet movement is being done asynchronously from the event key press - each time a space is pressed (including auto key repeat):

    1] A new bullet is created (they will eventually grow to large numbers slowing the game)

    2] It is moved in a loop in sub routine 'bullet'

    If another bullet is started before the last one has fully moved the loop is restarted and the last bullet is left orphaned.  Basically when code is performed with an event it can happed at any time (when the event happens) and you may end up with bits of code trying to run at the same time sharing the same variables and resulting all sorts of strange behaviour.

    What I think you need is a 'game loop' that ensures event asychronous behaviour is handled safely.

    I include links to a couple articles that may help with introducing this idea that will aid your game development.  The second article is about ways to handle multiple sprites.

    Small Basic: Dynamic Graphics

    Small Basic: Sprite Arrays

    Simple code to show a basic game loop only allowing bulluet to fire one at a time.

    Initialise()

    'Game Loop
    While ("True")
      start = Clock.ElapsedMilliseconds
     
      If (keys["Space"]) Then
        keys["Space"] = "" 'Space key event handled
        If (bulletX < 0) Then 'Only fire if last bullet isn't moving
          bulletX = gw-50
          bulletY = gh/2
          Shapes.ShowShape(bullet)
        EndIf
      EndIf
     
      moveBullet()
     
      'Delay up to 20ms to keep a constant game speed of 50 fps
      delay = 20 - (Clock.ElapsedMilliseconds-start)
      If (delay > 0) Then
        Program.Delay(delay)
      EndIf
    EndWhile

    'Subroutines
    Sub Initialise
      gw = 500
      gh = 500
      GraphicsWindow.Width = gw
      GraphicsWindow.Height = gh
     
      bullet = Shapes.AddEllipse(20,20) 'Only create one vbullet sprite
      bulletX = -1 'Ready to fire
      Shapes.HideShape(bullet)
     
      GraphicsWindow.KeyDown = OnKeyDown
    EndSub

    Sub moveBullet
      If (bulletX > 0) Then
        bulletX = BulletX-10
        Shapes.Move(bullet,bulletX-10,bulletY-10)
      Else
        bulletX = -1
        Shapes.HideShape(bullet)
      EndIf
    EndSub

    'Event Handlers
    Sub OnKeyDown
      key = GraphicsWindow.LastKey
      keys[key] = "True"
    EndSub
    Sunday, August 11, 2019 12:44 PM
    Moderator

All replies

  • Hi,

    First a suggestion to not mix your main code between subroutines - put all the subroutines after all your main code.  This makes it easier to read and develop.

    Secondly, the main issue is that the bullet movement is being done asynchronously from the event key press - each time a space is pressed (including auto key repeat):

    1] A new bullet is created (they will eventually grow to large numbers slowing the game)

    2] It is moved in a loop in sub routine 'bullet'

    If another bullet is started before the last one has fully moved the loop is restarted and the last bullet is left orphaned.  Basically when code is performed with an event it can happed at any time (when the event happens) and you may end up with bits of code trying to run at the same time sharing the same variables and resulting all sorts of strange behaviour.

    What I think you need is a 'game loop' that ensures event asychronous behaviour is handled safely.

    I include links to a couple articles that may help with introducing this idea that will aid your game development.  The second article is about ways to handle multiple sprites.

    Small Basic: Dynamic Graphics

    Small Basic: Sprite Arrays

    Simple code to show a basic game loop only allowing bulluet to fire one at a time.

    Initialise()

    'Game Loop
    While ("True")
      start = Clock.ElapsedMilliseconds
     
      If (keys["Space"]) Then
        keys["Space"] = "" 'Space key event handled
        If (bulletX < 0) Then 'Only fire if last bullet isn't moving
          bulletX = gw-50
          bulletY = gh/2
          Shapes.ShowShape(bullet)
        EndIf
      EndIf
     
      moveBullet()
     
      'Delay up to 20ms to keep a constant game speed of 50 fps
      delay = 20 - (Clock.ElapsedMilliseconds-start)
      If (delay > 0) Then
        Program.Delay(delay)
      EndIf
    EndWhile

    'Subroutines
    Sub Initialise
      gw = 500
      gh = 500
      GraphicsWindow.Width = gw
      GraphicsWindow.Height = gh
     
      bullet = Shapes.AddEllipse(20,20) 'Only create one vbullet sprite
      bulletX = -1 'Ready to fire
      Shapes.HideShape(bullet)
     
      GraphicsWindow.KeyDown = OnKeyDown
    EndSub

    Sub moveBullet
      If (bulletX > 0) Then
        bulletX = BulletX-10
        Shapes.Move(bullet,bulletX-10,bulletY-10)
      Else
        bulletX = -1
        Shapes.HideShape(bullet)
      EndIf
    EndSub

    'Event Handlers
    Sub OnKeyDown
      key = GraphicsWindow.LastKey
      keys[key] = "True"
    EndSub
    Sunday, August 11, 2019 12:44 PM
    Moderator
  • And a multi-bullet variant where a separate full key press required for firing.  I hope the examples show how to go about it, and further modify to achieve your specific requirements.

    Initialise()
    
    'Game Loop
    While ("True")
      start = Clock.ElapsedMilliseconds
      
      If (keys["Space"] = 1) Then 'Only first press (not auto-repeat) - requires key up between firing
        keys["Space"] = keys["Space"]+1 'Space key event handled
        'Set next free bullet sprite
        For i = 1 To maxBullet
          If (bulletX[i] < 0) Then
            bulletX[i] = gw-50
            bulletY[i] = gh/2
            Shapes.ShowShape(bullet[i])
            i = maxBullet 'End loop since we found a free bullet
          EndIf
        EndFor
      EndIf
      
      moveBullets()
      
      'Delay up to 20ms to keep a constant game speed of 50 fps
      delay = 20 - (Clock.ElapsedMilliseconds-start)
      If (delay > 0) Then
        Program.Delay(delay)
      EndIf
    EndWhile
    
    'Subroutines
    Sub Initialise
      gw = 500
      gh = 500
      GraphicsWindow.Width = gw
      GraphicsWindow.Height = gh
      
      maxBullet = 100
      For i = 1 To maxBullet
        bullet[i] = Shapes.AddEllipse(20,20) 'Only create one vbullet sprite
        bulletX[i] = -1 'Ready to fire
        Shapes.HideShape(bullet[i])
      EndFor
      
      GraphicsWindow.KeyDown = OnKeyDown
      GraphicsWindow.KeyUp = OnKeyUp
    EndSub
    
    Sub moveBullets
      For i = 1 To maxBullet
        If (bulletX[i] > 0) Then
          bulletX[i] = BulletX[i]-10
          Shapes.Move(bullet[i],bulletX[i]-10,bulletY[i]-10)
        Else
          bulletX[i] = -1
          Shapes.HideShape(bullet[i])
        EndIf
      EndFor
    EndSub
    
    'Event Handlers
    Sub OnKeyDown
      key = GraphicsWindow.LastKey
      keys[key] = keys[key]+1
    EndSub
    
    Sub OnKeyUp
      key = GraphicsWindow.LastKey
      keys[key] = 0
    EndSub
    

    Sunday, August 11, 2019 1:13 PM
    Moderator