none
making the player move smoother RRS feed

  • Question

  • gh = 500
    gw = 500
    GraphicsWindow.Height=gh 
    GraphicsWindow.Width = gw
    GraphicsWindow.CanResize = "False"
    GraphicsWindow.KeyDown = move
    GraphicsWindow.KeyUp = stop
    frames = 60 ' really smooth
    player = Shapes.AddRectangle(20, 20)
    playerx = Math.GetRandomNumber(gh)
    playery = Math.GetRandomNumber(gh)
    pdX = 2
    pdY= 2
    Shapes.Move(player, playerx, playery)
    
    numEnemy =1
    For i = 0 to (numEnemy-1) 
      createenemy()
      
    endfor
    
    Sub createenemy
      enemy[i] = Shapes.AddRectangle(15, 15)
      velX[i] = Math.GetRandomNumber(2)
      velY[i] = Math.GetRandomNumber(2)
      
      enemyx[i] = Math.GetRandomNumber(gh-15)
      enemyy[i] = Math.GetRandomNumber(gh-15)
     
    endsub
    
    
    While 1=1
      moveenemy()
      checkcollisionofplayer()
      addscore()
      Program.Delay((1000/frames))
    endwhile
    Sub addscore
      
      EndSub
    Sub moveenemy
      For i = 0 To numEnemy step 1 ' going through all the objects
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])   
        
        If (ex >= gw-10) Or ( ex < 0) Then
          velX[i] = velX[i] * -1
        else
          velX[i] = velX[i]      
        endif
        
        If (ey >= gh - 10) Or ( ey < 0) Then
          velY[i] = velY[i] * -1
        Else
          velY[i] = velY[i]    
          
        EndIf
        
        enemyx[i] = enemyx[i]+ velX[i]
        enemyy[i] = enemyy[i] + velY[i]
        Shapes.Move(enemy[i], enemyx[i], enemyy[i]) 
        
      endfor
    endsub
    
    Sub move
      key = GraphicsWindow.LastKey
      If (key = "A") then
        pdX = -5
        pdY=0
      ElseIf (key = "D") then
        pdX =5
        pdY=0 
      elseif (key = "W") then
        pdY = -5
        pdX =0
      elseif(key = "S") then
        pdY =5
        pdX =0  
      EndIf
      
      If(Shapes.GetLeft(player) <0) or (Shapes.GetLeft(player) > (gw-15)) Then
        
        If(Shapes.GetLeft(player) <0) Then
          playerx = 0
        ElseIf(Shapes.GetLeft(player) > (gw-15)) then
          playerx = gw -15
        EndIf
      Else
        playerx = playerx+pdX
      EndIf
      If((Shapes.Gettop(player) <0) or (Shapes.Gettop(player) > (gh-15))) Then
        
        If(Shapes.Gettop(player) <0) Then
          playery = 0
        ElseIf(Shapes.Gettop(player) > (gh-15)) then
          playery = (gh-15)
        EndIf
      Else
        playery = playery + pdY
      EndIf
      
      Shapes.Move(player, playerx, playery)
    
    EndSub
    Sub checkcollisionofplayer
      
      py = Shapes.GetTop(player)
      px = Shapes.GetLeft(player)
      For i = 0 To numEnemy 
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])   
        
        'checks for top left
        If ((ey >= py) and (ey <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            TextWindow.WriteLine("hit")
          EndIf
        EndIf  
        'checks for top right 
        If ((ey >= py) and (ey <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            TextWindow.WriteLine("hit")
          EndIf
        EndIf 
        'checks for bottom right
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            TextWindow.WriteLine("hit")
          EndIf
        EndIf  
        'checks for bottom left
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            TextWindow.WriteLine("hit")
          EndIf
        EndIf 
      endfor
      
    EndSub
    Sub stop
      
      Shapes.Move(player, playerx, playery)
    EndSub

    the object moves very smooth, but how can i make the player move smoother, and if the enemy can move faster while not compromising smoothness, that would be great.

    Matthew

    Friday, April 29, 2016 6:38 PM

Answers

  • This is probably more of an answer than +litdev would approve of, but I'm remembering how much I would have liked the solution to a problem like this back in my early days.  :-)

    Program.delay() is great when you need to pause a program. For frame pacing... not so much. The problem is that you perform the same delay regardless of how long it took to process the frame. Your program sets the frame rate at 60 times a -- optimistic for most games; very very optimistic for small basic. At the end of every frame you pause for 1000/60, or 16 milliseconds. Now imagine that it takes your game loop 15 milliseconds to process each frame. When you add the two together you end up with 15 * 60 + 16 * 50 or 1700 milliseconds of processing time you are trying to cram into each 1000 milliseconds of actual real time.

    The trick for real time processing is to record a start time before the frame processing starts, and the have a pause loop that spins in place only for the amount of time remaining to complete the frame.

    'An example of a basic game loop, including exact frame pacing.
    frameLength = 1000/60    'Number of milleseconds between animation frames
    CreateShip()
    GraphicsWindow.KeyDown = onKeyDown
    GraphicsWindow.KeyUp = onKeyUp
    
    'Game Loop --------------------
    framestart = Clock.ElapsedMilliseconds          'Start the clock
    While "True"
      processKey()
      moveShip()
      frameDelay()                               'Wait a tick or two between moves
    EndWhile
    
    'Subroutines -------------------
    Sub moveShip
      Shapes.Move(ship, shipX, shipY)
    EndSub
    
    Sub CreateShip
      shipX = GraphicsWindow.Width /2
      shipY = GraphicsWindow.Height / 2
      ship = Shapes.AddEllipse(20,20)
      Shapes.Move(ship,shipX, shipY)
    EndSub
    
    Sub OnKeyDown
      'Only process keys when they are down
      pressed = "True"
    EndSub
    
    Sub OnKeyUp
      'Stop process keys when none are pressed
      pressed = "False"
    EndSub
    
    Sub ProcessKey
      'process the keys once per frame
      If pressed = "True" Then
        key = GraphicsWindow.LastKey
        If key = "Up" Then
          shipY = shipY - 1
        EndIf
      EndIf
    EndSub
    
    Sub frameDelay
      'Precise frame timing. More exact that program.delay() because it only
      'pauses for the length of time remiaining in the current frame, rather than for the 
      'entire time slice of the frame. Even with longer, or shorter frame processing
      'times, each fram will still be exactly frameLength in duration.
      While Clock.ElapsedMilliseconds - framestart < frameLength
      EndWhile
      framestart = Clock.ElapsedMilliseconds
    EndSub

    In addition to an example on frame pacing the above example also shows how to use the keyup and keydown events to manage the fact that GraphicsWindows.LastKey retains its current value forever, until changed.


    Friday, April 29, 2016 7:58 PM
    Answerer

All replies

  • I think the issue is with the auto repeat delay on keys.

    See here for ideas - you need a game loop and store the up and down state of keys rather than key presses.

    Post back if need more help - I don't want to just post solution code.

    Also any GW updates only happen AFTER event subs finish - hence do it all on main UI thread in game loop.
    Friday, April 29, 2016 6:58 PM
    Moderator
  • This is probably more of an answer than +litdev would approve of, but I'm remembering how much I would have liked the solution to a problem like this back in my early days.  :-)

    Program.delay() is great when you need to pause a program. For frame pacing... not so much. The problem is that you perform the same delay regardless of how long it took to process the frame. Your program sets the frame rate at 60 times a -- optimistic for most games; very very optimistic for small basic. At the end of every frame you pause for 1000/60, or 16 milliseconds. Now imagine that it takes your game loop 15 milliseconds to process each frame. When you add the two together you end up with 15 * 60 + 16 * 50 or 1700 milliseconds of processing time you are trying to cram into each 1000 milliseconds of actual real time.

    The trick for real time processing is to record a start time before the frame processing starts, and the have a pause loop that spins in place only for the amount of time remaining to complete the frame.

    'An example of a basic game loop, including exact frame pacing.
    frameLength = 1000/60    'Number of milleseconds between animation frames
    CreateShip()
    GraphicsWindow.KeyDown = onKeyDown
    GraphicsWindow.KeyUp = onKeyUp
    
    'Game Loop --------------------
    framestart = Clock.ElapsedMilliseconds          'Start the clock
    While "True"
      processKey()
      moveShip()
      frameDelay()                               'Wait a tick or two between moves
    EndWhile
    
    'Subroutines -------------------
    Sub moveShip
      Shapes.Move(ship, shipX, shipY)
    EndSub
    
    Sub CreateShip
      shipX = GraphicsWindow.Width /2
      shipY = GraphicsWindow.Height / 2
      ship = Shapes.AddEllipse(20,20)
      Shapes.Move(ship,shipX, shipY)
    EndSub
    
    Sub OnKeyDown
      'Only process keys when they are down
      pressed = "True"
    EndSub
    
    Sub OnKeyUp
      'Stop process keys when none are pressed
      pressed = "False"
    EndSub
    
    Sub ProcessKey
      'process the keys once per frame
      If pressed = "True" Then
        key = GraphicsWindow.LastKey
        If key = "Up" Then
          shipY = shipY - 1
        EndIf
      EndIf
    EndSub
    
    Sub frameDelay
      'Precise frame timing. More exact that program.delay() because it only
      'pauses for the length of time remiaining in the current frame, rather than for the 
      'entire time slice of the frame. Even with longer, or shorter frame processing
      'times, each fram will still be exactly frameLength in duration.
      While Clock.ElapsedMilliseconds - framestart < frameLength
      EndWhile
      framestart = Clock.ElapsedMilliseconds
    EndSub

    In addition to an example on frame pacing the above example also shows how to use the keyup and keydown events to manage the fact that GraphicsWindows.LastKey retains its current value forever, until changed.


    Friday, April 29, 2016 7:58 PM
    Answerer
  • thanks for this, this really really helps. I have never actually new how to do game loops, so this is a new way to think about it. 

    Matthew

    Saturday, April 30, 2016 5:01 PM
  • would you say the collision detector is decent? know any other way that could possibly be more effiecient?

    Matthew

    Saturday, April 30, 2016 5:03 PM
  • In the collision_> is it possible to just have the enemy hit once, and only hurt the player once, not overlapping the damage. if the enemy touches the player, the first time they touch will hurt the player, but it wont continue to make the player lose health if they keep in contact with the enemy. I think my collision is wrongV
    Sub checkcollisionofplayer
      healthloss = 2
      py = Shapes.GetTop(player)
      px = Shapes.GetLeft(player)
      For i = 0 To numEnemy 
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])   
        
        'checks for top left
        If ((ey >= py) and (ey <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            numhit = numhit + 1
            losshealth = "True"
          Else
         
          EndIf
        Else  
        
        EndIf  
        'checks for top right 
        If ((ey >= py) and (ey <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            numhit = numhit + 1
            losshealth = "True"
          Else
         
          EndIf
        Else  
         
        EndIf 
        'checks for bottom right
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            numhit = numhit + 1
            
            losshealth = "True"
          Else
            
          EndIf
        Else  
        
        EndIf  
        'checks for bottom left
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            
            numhit = numhit + 1
            
            losshealth = "True"
          Else
          
          EndIf
        Else  
        
        EndIf 
      endfor
      If losshealth = "True" Then
        health = health - healthloss
      endif
      losshealth="False"
    EndSub


    Matthew

    Saturday, April 30, 2016 10:06 PM
  • Hi Matthew,

    to have the enemy hit once only after a collision, i found this :

    if it detect a collision, something must happen:

    1) go in the opposite direction,

    or 2) create a new ship

    or 3) anything else..... 

    in all cases we have to get out of the sub check collision routine, and go to and other routine that will issue new command to the new ship.

    here i wrote a simple sub call something_happen were the ship that collides, is reset to 0, means new ship, and by the fact it rule the problem of many hits to 1.The reason why it end up with many hits, because after the first detection collision, you ship continue to move in those  ( 20 pixels ) and fill the fomula in your sub colllision check routine.

    What about this:

    gh = 500
    gw = 500
    GraphicsWindow.Height=gh
    GraphicsWindow.Width = gw
    GraphicsWindow.CanResize = "False"
    GraphicsWindow.KeyDown = move
    GraphicsWindow.KeyUp = stop
    frames = 60 ' really smooth
    player = Shapes.AddRectangle(20, 20)
    playerx = Math.GetRandomNumber(gh)
    playery = Math.GetRandomNumber(gh)
    pdX = 2
    pdY= 2
    Shapes.Move(player, playerx, playery)
    numEnemy =1
    For i = 0 to (numEnemy-1)
      createenemy()
     
    endfor
    Sub createenemy
      enemy[i] = Shapes.AddRectangle(15, 15)
      velX[i] = Math.GetRandomNumber(2)
      velY[i] = Math.GetRandomNumber(2)
     
      enemyx[i] = Math.GetRandomNumber(gh-15)
      enemyy[i] = Math.GetRandomNumber(gh-15)
     
    endsub

    While 1=1
      moveenemy()
      checkcollisionofplayer()
      addscore()
      Program.Delay((1000/frames))
    endwhile
    Sub addscore
     
      EndSub
    Sub moveenemy
      For i = 0 To numEnemy step 1 ' going through all the objects
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])  
       
        If (ex >= gw-10) Or ( ex < 0) Then
          velX[i] = velX[i] * -1
        else
          velX[i] = velX[i]     
        endif
       
        If (ey >= gh - 10) Or ( ey < 0) Then
          velY[i] = velY[i] * -1
        Else
          velY[i] = velY[i]   
         
        EndIf
       
        enemyx[i] = enemyx[i]+ velX[i]
        enemyy[i] = enemyy[i] + velY[i]
        Shapes.Move(enemy[i], enemyx[i], enemyy[i])
       
      endfor
    endsub
    Sub move
      key = GraphicsWindow.LastKey
      If (key = "A") then
        pdX = -5
        pdY=0
      ElseIf (key = "D") then
        pdX =5
        pdY=0
      elseif (key = "W") then
        pdY = -5
        pdX =0
      elseif(key = "S") then
        pdY =5
        pdX =0 
      EndIf
     
      If(Shapes.GetLeft(player) <0) or (Shapes.GetLeft(player) > (gw-15)) Then
       
        If(Shapes.GetLeft(player) <0) Then
          playerx = 0
        ElseIf(Shapes.GetLeft(player) > (gw-15)) then
          playerx = gw -15
        EndIf
      Else
        playerx = playerx+pdX
      EndIf
      If((Shapes.Gettop(player) <0) or (Shapes.Gettop(player) > (gh-15))) Then
       
        If(Shapes.Gettop(player) <0) Then
          playery = 0
        ElseIf(Shapes.Gettop(player) > (gh-15)) then
          playery = (gh-15)
        EndIf
      Else
        playery = playery + pdY
      EndIf
     
      Shapes.Move(player, playerx, playery)

    EndSub
    Sub checkcollisionofplayer

      py = Shapes.GetTop(player)
      px = Shapes.GetLeft(player)
      For i = 0 To numEnemy
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])  

        'checks for top left
        If ((ey >= py) and (ey <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            TextWindow.WriteLine("hit")
            something_happen()
          EndIf
        EndIf 
        'checks for top right
        If ((ey >= py) and (ey <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            TextWindow.WriteLine("hit")
            something_happen()
          EndIf
        EndIf
        'checks for bottom right
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            TextWindow.WriteLine("hit")
            something_happen()
          EndIf
        EndIf 
        'checks for bottom left
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            TextWindow.WriteLine("hit")
            something_happen()
          EndIf
        EndIf
      endfor

    EndSub
    Sub stop

      Shapes.Move(player, playerx, playery)
    EndSub

             
    Sub something_happen
      ' we have a colllision or a hit
      ' somethin happen,
      ' 1) ship go in the opposite direction
      ' or
      '2 ) new ship
     
      enemyx[i]=0
      enemyy[i]=0
      EndSub


    • Edited by YLedEditor Sunday, May 1, 2016 9:49 PM orthograph
    Sunday, May 1, 2016 9:43 PM
    Answerer
  • You have the basic idea of a hit bock down. Checking if the corners of one shape are inside the corners of another shape. The more complex the shape, the more comparisons you have to do. Here is a basic example for anyone else who may be following the thread:

    Import Code: XTQ138

    'At the top of your program - Initial Setup
    'Stuff up here only happens once before the main loop
    GraphicsWindow.Show()
    circle = Shapes.AddEllipse(50,50)
    circleX = 0 'Starting place for the circle
    circleY = Math.GetRandomNumber(GraphicsWindow.Height) 'Somewhere on the left side
    cxDir = 1    'The direction the circle is moving --  1 = right and down, -1 = left and up
    cyDir = 1
    
    triangle = Shapes.AddTriangle(25,0,50,50,0,50)
    triangleX = GraphicsWindow.Width
    triangleY = Math.GetRandomNumber(GraphicsWindow.Height) 'Somewhere on the right side
    txDir = -1
    tyDir = -1
    frameRate = 5    'Number of milliseonds each frame (trip through the main program) should take
    frameStart = Clock.ElapsedMilliseconds 'note the time to allow for frame pauses
    
    '----------------------------------------------------------------------------
    
    'Main Program Loop
    'Repeats continuously until the escape key is pressed
    key = "" 
    While GraphicsWindow.LastKey <> "Escape" 'Keep going until the escape key is pressed
      MoveTheCircle()     'Update circle automatically
      MoveTheTriangle()   'Update triangle Automatically
      HitDetect()         'Chcck for collision between shapes - Nest If statments 
      'HitDetectShort()    'Chcck for collision between shapes - One compound if statement 
      FrameWait()         'Pause and wait for just a tick
    endwhile
    
    '----------------------------------------------------------------------------
    
    'Subroutines.
    'Always at the bottom of your program
    'No code outside of a subroutine allowed below.
    
    
    Sub MoveTheCircle
      'called once during each trip through the loop, it moves the circle as needed.
      GraphicsWindow.PenColor = "white"
      GraphicsWindow.DrawRectangle(circleX,circleY,50,50)
      circleX = circleX + cxDir
      If circleX > GraphicsWindow.Width Or circleX < 0 Then 'If off the screen
        cxDir = cxDir * -1  'reverse the direction
      EndIf
      circleY = circleY + cyDir
      If circleY > GraphicsWindow.Height Or circleY < 0 Then 'If off the screen
        cyDir = cyDir * -1  'reverse the direction
      EndIf
      Shapes.Move(circle,circleX,circleY)
      GraphicsWindow.PenColor = "green"
      GraphicsWindow.DrawRectangle(circleX,circleY,50,50)
    EndSub  
    
    Sub MoveTheTriangle
      'called once during each trip through the loop, it moves the triangle  as needed.
      GraphicsWindow.PenColor = "white"
      GraphicsWindow.DrawRectangle(triangleX,triangleY,50,50)
      triangleX = triangleX + txDir
      If triangleX > GraphicsWindow.Width Or triangleX < 0 Then 'If off the screen
        txDir = txDir * -1  'reverse the direction
      EndIf
      triangleY = triangleY + tyDir
      If triangleY > GraphicsWindow.Height Or triangleY < 0 Then 'If off the screen
        tyDir = tyDir * -1  'reverse the direction
      EndIf
      Shapes.Move(triangle,triangleX,triangleY)
      GraphicsWindow.PenColor = "green"
      GraphicsWindow.DrawRectangle(triangleX,triangleY,50,50)
    EndSub  
    
    Sub HitDetect
      'Each object is represented by a single point inside of the compter. Its upper
      'left corner. The object itself usually needs at least four points to describe
      'its full location in two-dimensional space:
      'Upper left = x,y
      'Upper right = x + width, y
      'Lower left = x, y + height
      'Lower right = x + width, y + height
      '       Side note -> you an make your hit boxes more complex. However the more points
      '            you track, the more difficult the math will be, and the more time the comparison
      '            will take. This is why most of the early 8-bit games stuck to rectangular
      '            characters that filled a 16x16 pixel grid.
      
      'To register a hit between the two objects, you have to check each of the four points 
      'to see they inside the other shape. 
      
      'Top left corner of circle inside of triangle?
      '    First check to see if the X of the top right of the circle is inside the triangles hit box
      '    Is the circles X more then the triangles X?  Is the circles X less than the triangles X plus the width of the triangle?
      If circleX > triangleX And circleX < triangleX + 50 Then
        'Next check to see if the Y of the top corner of the circle is inside the triangles hit box
        'Is the circles Y more than the triangles Y? Is the circles Y less than the triangles Y plus the height of the triangle?
        If circleY > triangleY And circleY < triangleY + 50 Then
          ReactToHit()
          
        'Bottom Left corner of circle inside of triangle?
        '    Contine check -- since we already know x is in the right place, we can check the Y for the oppisite corner 
        '    Is the circles Y plus its height more than the triangles Y? Is the circles Y plus its height less than the triangles Y plus the height of the triangle?
        ElseIf circleY + 50 > triangleY And circleY + 60 < triangleY + 50 Then
          ReactToHit()
        EndIf
        
      'Top right corner of circle inside of triangle?
      '    First check to see if the X of the top right of the circle is inside the triangles hit box
      '    Is the circles X plus its width more then the triangles X?  Is the circles X plus its width less than the triangles X plus the width of the triangle?
      ElseIf circleX+50 > triangleX And circleX + 50 < triangleX + 50 Then
        'Next check to see if the Y of the top corner of the circle is inside the triangles hit box
        'Is the circles Y more than the triangles Y? Is the circles Y less than the triangles Y plus the height of the triangle?
        If circleY > triangleY And circleY < triangleY + 50 Then
          ReactToHit()
          
        'Bottom right corner of circle inside of triangle?
        '    Contine check -- since we already know x is in the right place, we can check the Y for the oppisite corner 
        '    Is the circles Y plus its height more than the triangles Y? Is the circles Y plus its height less than the triangles Y plus the height of the triangle?
        ElseIf circleY + 50 > triangleY And circleY + 60 < triangleY + 50 Then
          ReactToHit()
        EndIf
      EndIf
    EndSub
    
    Sub HitDetectShort
      'The giganitic nested if block above can be replaced with a single If statment 
      'if you put parenthesis ( ) around the and blocks and glue them together with or blocks:
      If ((circleX > triangleX And circleX < triangleX + 50) And (circleY > triangleY And circleY < triangleY + 50)) Or ((circleX > triangleX And circleX < triangleX + 50) And (circleY + 50 > triangleY And circleY + 60 < triangleY + 50)) Or ((circleX+50 > triangleX And circleX + 50 < triangleX + 50) And (circleY > triangleY And circleY < triangleY + 50)) Or ((circleX+50 > triangleX And circleX + 50 < triangleX + 50) And (circleY + 50 > triangleY And circleY + 60 < triangleY + 50)) Then
        ReactToHit()
      EndIf
    EndSub
    
    sub ReactToHit
      'When there is a hit, reverse the direction of both shapes.
      cyDir = cyDir * -1
      cxDir = cxDir * -1
      tyDir = tyDir * -1
      txDir = txDir * -1
    EndSub
    
    Sub FrameWait
      While Clock.ElapsedMilliseconds - frameStart < frameRate
        'Sit here and do nothing until the frame clock has run out.
        'This wait keeps the automatic operations, like moving the ball
        'from running too fast. 
        'This technique is better then using Program.Delay() for two reasons:
        '   1)  The wait time is based on when we started the frame, not
        '        when we ended it. In other words, when one of our trips through
        '        the for loop above takes longer than normal, the delay will be 
        '        reduced, so each frame will be exactly the same length.
        '  2) We have the option (even though we are not using it here) of  
        '        doing some extra processing, such as checking the keyboard. 
        '        With Program.Delay() we are stuck, unable to do anything,
        '       until the  delay is complete.
      EndWhile
      frameStart = Clock.ElapsedMilliseconds 'Start  a new frame.
    EndSub



    Monday, May 2, 2016 12:49 PM
    Answerer
  • thats a good idea, but if i wanted the enemy to stay where it was at (relatively) could the enemy have a tracker saying that this enemy is already hit the player, hitpossible = false or something, and when the enemy isnt in collision anymore, it turns back to true?

    Matthew

    Monday, May 2, 2016 1:19 PM
  • thanks for that answer... only issue that i see is that the triangle collision is a rectanlge, not a triangle, no biggie. But great answer, thanks for that, i actually never thought of that. Btw, guys here is the full code that i have so far. IT is runnable and you can leave it how it is, but im going to be making a smart enemy that follows the player-< Import XMG848 . thanks for all the help!!!

    Matthew

    Monday, May 2, 2016 1:23 PM
  • If you want to do more than simply register a hit and move them apart again you will need to set some flags in the same way I set a flag in the key down example above. A variable that says that a hit has already taken place, but the two objects are still in contact:

    If (the two pieces are in the same place) Then
      If (touching = "False") Then
        'Process penalty for hit
    
        'Track the fact that a hit is in action - no new hits while true
        touching = "True"
      EndIf
    Else
      'No longer touching, allow for new hits in the future
      touching = "False"
    EndIf
    After touching is set to "True" the game will no longer register a hit. This will keep the program from registering the fact over and over again the same single event. Once the two are apart, the flag is cleared and they can again react to each other.

    Monday, May 2, 2016 1:40 PM
    Answerer
  • i see, alright. I will try to incorperate this after i finish the smart enemy. Thanks for the help.

    Matthew

    Monday, May 2, 2016 1:42 PM
  • Hi Matthew

    Excellent so far !!!!!  your program XMG848

    MY SCORE: 1850

    can we choose our level ? say beginner, normal, expert , each level with a different speed ?

    Monday, May 2, 2016 1:49 PM
    Answerer
  • would this be the best way to get a shape to go in the direction of the player

    For i = 1 To snumEnemy
        sex = Shapes.GetLeft(smartenemy[i])'SmartEnemyX
        sey = Shapes.Gettop(smartenemy[i])
        
        velX= (playerx-sex)/ math.Abs(playerx-sex) ' velocity will be 1 or -1 accordingly
        vely= (playery-sey)/ math.Abs(playery-sey)


    Matthew


    • Edited by JetFire3201 Monday, May 2, 2016 1:51 PM typos
    Monday, May 2, 2016 1:49 PM
  • I have a theory on that, as the level gets higher, change the frame length (frames to higher than 60, that makes the game go faster. 

    my high score was around 4000, with 10 enemies. let me provide a screen shot.


    Matthew

    Monday, May 2, 2016 1:51 PM

  • Matthew

    Monday, May 2, 2016 1:56 PM
  • very fun game, ! great reflex, mind perception, reaction skill !

    here my new score: 2680

    Monday, May 2, 2016 2:02 PM
    Answerer
  • I'm looking forward to seeing how you will you take to program a smart ennemy ship.!!!  :)
    Monday, May 2, 2016 2:06 PM
    Answerer
  • it wont be that hard, i made this game is java already. im just testing it out on sb. are you having the player move on its own, where you just press the key and the player moves in that direction without you having to hold the key?

    Matthew

    Monday, May 2, 2016 2:11 PM
  • my new score: 4760

    Monday, May 2, 2016 2:15 PM
    Answerer
  • I am trying to incorperate your method, but i cant get it to not hurt the player.

    Look at collisionwithplayer (not the smartenemy one)

    gh = 400
    gw = 400
    GraphicsWindow.Height=gh 
    GraphicsWindow.Width = gw
    GraphicsWindow.CanResize = "False"
    init() ' initialize the saving
    
    variables()' final variables that create the graphics window and all that.
    GraphicsWindow.KeyDown = move ' key events that tell the player to move.
    GraphicsWindow.KeyUp = stop ' nothing there 
    'if you want the player to stop when you let go of the key, go to this method and remove the ' on pressed="False"
    
    framestart = Clock.ElapsedMilliseconds ' getsthe time
    For i = 0 to 13 Step 1 'sets the level you are not on at false, refers to the enemy spawn
      levelat[i] = "False"
    endfor
    smartenemyexists="False" ' refers to the smart enemy, not yet created in this program yet
    numEnemy=1
    createenemy()'initial enemy
    
    '========GAME LOOP===========
    While 1=1
      ProcessKey() 'processes the key at the current frame
      moveenemy() 'moves enemy
      If(smartenemyexists) Then ' if we are starting to cook smartenenemies, then it will start to run the appropriate subroutine
        movesmartenemy() ' nothing there, enemy will follow player around to prevent player from hiding in corners
      EndIf
      setlevel()'sets the level and updates it
      checkcollisionofplayer() ' healthloss and collision
      checkcollisionofplayersmartenemy()
      addscore() ' adds score
      updatehighscore() ' updates the highscore if score goes over it
      adjusthealth() ' event to change number of health
      
      
      enemyspawn() ' depending on level put an enemy, can be changed
      framedelay()'frame delay
    endwhile
    
    Sub init
      path = Program.Directory + "/Collision Game/"
      name = "High Score"
      ext = ".txt"
      filesave = File.ReadContents(path+name+ext) ' reads the last thing in there, your highest score
      
      highscoredisplay =Shapes.AddText("High Score: " +filesave[1])
      Shapes.Move(highscoredisplay, 0,50)
    endsub
    
    Sub variables
      frames = 60
      frameLength = 1000/frames  ' really smooth 0.016 millisecond frame. 1 frame every 0.016 millisecond.
      '==============================  
      player = Shapes.AddRectangle(20, 20)
      playerx = Math.GetRandomNumber(gh)
      playery = Math.GetRandomNumber(gh)
      Shapes.Move(player, playerx, playery)
      '==============================
      
      health = 100
      GraphicsWindow.BrushColor= "Green"
      healthdisplay = Shapes.AddText(health)
      Shapes.Move(healthdisplay, 0, 30)
      '==============================  
      level = 1
      leveldisplay = Shapes.AddText("Level" + level)
      Shapes.Move(leveldisplay, 350,0)
      '==============================  
      GraphicsWindow.BrushColor= "BLue"
      scoredisplay = Shapes.AddText(score)
      Shapes.Move(scoredisplay, 0, 0)  
    endsub
    Sub createenemy
      GraphicsWindow.BrushColor="Red"
      vel = 1
      'each enemy has its own id. 
      touching[numEnemy]="False"
      enemy[numEnemy] = Shapes.AddRectangle(15, 15)
      velX[numEnemy] = vel'Math.GetRandomNumber(vel)
      velY[numEnemy] = 0'Math.GetRandomNumber(vel)
      
      enemyx[numEnemy] = Math.GetRandomNumber(gh-15)
      enemyy[numEnemy] = Math.GetRandomNumber(gh-15)
    endsub
    
    Sub createsmartenemy
      GraphicsWindow.BrushColor="Yellow"
      smartenemy[snumEnemy] = Shapes.AddRectangle(10, 10)
      smartenemyx[snumEnemy] = Math.GetRandomNumber(gh)
      smartenemyy[snumEnemy] = Math.GetRandomNumber(gh)
      touchings[snumEnemy] = "False"
      vels = 2
    EndSub
    
    Sub ProcessKey
      'process the keys once per frame
      If pressed = "True" Then
        key = GraphicsWindow.LastKey
        If (key = "A") then
          pdX = -1
          pdY=0
        ElseIf (key = "D") then
          pdX =1
          pdY=0 
        elseif (key = "W") then
          pdY = -1
          pdX =0
        elseif(key = "S") then
          pdY =1
          pdX =0  
        EndIf
        '===========this is the bounds check, makes sure the player doesnt leave the field.
        If(Shapes.GetLeft(player) <0) or (Shapes.GetLeft(player) > (gw-15)) Then
          
          If(Shapes.GetLeft(player) <0) Then
            playerx = 0
          ElseIf(Shapes.GetLeft(player) > (gw-15)) then
            playerx = gw -15
          EndIf
        Else
          playerx = playerx+pdX
        EndIf
        If((Shapes.Gettop(player) <0) or (Shapes.Gettop(player) > (gh-15))) Then
          
          If(Shapes.Gettop(player) <0) Then
            playery = 0
          ElseIf(Shapes.Gettop(player) > (gh-15)) then
            playery = (gh-15)
          EndIf
        Else
          playery = playery + pdY
        EndIf
        
        Shapes.Move(player, playerx, playery)
        
      EndIf
    EndSub
    
    
    Sub updatehighscore
      If score > filesave[1] Then
        filesave[1] = score
        Shapes.SetText(highscoredisplay,  "Highest score: " +score)
      endif  
    endsub
    
    Sub addscore
      If ( health >0) Then
        score = score +1 
      Else
        GraphicsWindow.ShowMessage("You have lost, your score was " + score, "Game Over")
        savescore()
        Program.End()
      EndIf
      Shapes.SetText(scoredisplay, "Score: " +score)
    EndSub
    
    Sub adjusthealth
      Shapes.SetText(healthdisplay,"Health: " + health)
    endsub
    
    Sub setlevel
      
      If(score < 40) Then ' had issue where the level will jump once, so you will be already on level two.
        Goto skip
      endif  
      If(Math.Remainder(score, 200) = 0) then
        level = level +1 
      EndIf
      skip:
      Shapes.SetText(leveldisplay,"Level: " +level)
      
    endsub
    Sub moveenemy
      For i = 1 To (numEnemy) step 1 ' going through all the objects
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])   
        '===========simple collision================very rudamentary================
        If (ex >= gw-10) Or ( ex < 0) Then
          velX[i] = velX[i] * -1
        else
          velX[i] = velX[i]      
        endif
        
        If (ey >= gh - 10) Or ( ey < 0) Then
          velY[i] = velY[i] * -1
        Else
          velY[i] = velY[i]    
        EndIf
        
        enemyx[i] = enemyx[i]+ velX[i]
        enemyy[i] = enemyy[i] + velY[i]
        Shapes.Move(enemy[i], enemyx[i], enemyy[i]) 
        
      endfor
    endsub
    
    Sub enemyspawn
      
      If(level<9) Then
        If (levelat[level] ="False") Then
          numEnemy=numEnemy+1
          createenemy()
          levelat[level]= "True"
        endif
        
      ElseIf(level>9) then
        if (smartenemyexists="False") then
          smartenemyexists="True"
          If (levelat[level] ="False") Then
            
            snumEnemy=snumEnemy+1
            createsmartenemy()
            levelat[level]= "True"
          endif
        EndIf
      endif
    endsub
    
    Sub movesmartenemy
      For i = 1 To snumEnemy
        sex = Shapes.GetLeft(smartenemy[i])'SmartEnemyX
        sey = Shapes.Gettop(smartenemy[i])
        positionx = (playerx-sex)
        positiony = (playery-sey)
        If (positionx < 0) Then 
          velXS[i]= -vels
        ElseIf (positionx>0) then
          velXS[i] = vels
        Else
          velXS[i]=0
        EndIf
        
        If (positiony < 0) Then 
          velYS[i]= -vels
        ElseIf (positiony>0) then
          velYS[i] = vels
        Else
          velYS[i]=0
        EndIf
        
        smartenemyx[i] =smartenemyx[i] + velXS[i]
        smartenemyy[i] =smartenemyy[i] + velYS[i]
        Shapes.Move(smartenemy[i], smartenemyx[i], smartenemyy[i])
        
      endfor
    EndSub
    
    Sub move
      pressed = "True"
      
    EndSub
    Sub checkcollisionofplayersmartenemy
      For i = 1 To snumEnemy 
        ey = Shapes.GetTop(smartenemy[i])
        ex = Shapes.GetLeft(smartenemy[i])   
        
        'checks for top left
        If(touchings[i]="False") Then
          If ((ey >= py) and (ey <= (py+20))) Then
            If ((ex >= px) and (ex <= (px+20)))Then
              numhit = numhit + 1
              losshealth = "True"
              TextWindow.WriteLine("collision with " + i)
              touching[i]="True"
            Else
              
            EndIf
            
          Else  
            touchings[i]="False"  
            
          EndIf  
          
          'checks for top right 
          If ((ey >= py) and (ey <= (py+20))) Then
            If (((ex+10) >= px) and ((ex+10) <= (px+20)))Then
              numhit = numhit + 1
              losshealth = "True"
              
              touchings[i]="True"
            Else
              touching[i]="False" 
            EndIf
          Else  
            
            
          EndIf 
          'checks for bottom right
          If (((ey+10) >= py) and ((ey+10) <= (py+20))) Then
            If (((ex+10) >= px) and ((ex+10) <= (px+20)))Then
              numhit = numhit + 1
              
              losshealth = "True"
              
              touchings[i]="True"
            Else
              touchings[i]="False" 
            EndIf  
          Else  
            
          EndIf  
          'checks for bottom left
          If (((ey+10) >= py) and ((ey+10) <= (py+20))) Then
            If ((ex >= px) and (ex <= (px+20)))Then
              
              numhit = numhit + 1
              
              losshealth = "True"
              touchings[i]="True"
            Else
              touchings[i]="False" 
            EndIf
          Else  
            
          EndIf 
          
          If losshealth = "True" Then
            health = health - healthloss
          endif
          losshealth="False"
        endif 
        
      endfor
    endsub
    '===========================================================================================
    Sub checkcollisionofplayer
      healthloss = 2
      py = Shapes.GetTop(player)
      px = Shapes.GetLeft(player)
      For i = 1 To numEnemy 
        ey = Shapes.GetTop(enemy[i])
        ex = Shapes.GetLeft(enemy[i])   
        
        'checks for top left
        
        If ((ey >= py) and (ey <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            If(touching[i]="False") Then
              health = health - healthloss
              TextWindow.WriteLine("collision with " + i)
              touching[i]="True"
            Else
              
            EndIf
         Else
            touching[i]="False"
          EndIf
          
        Else  
        EndIf  
        
        'checks for top right 
        If ((ey >= py) and (ey <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            If(touching[i]="False") Then
              health = health - healthloss
              TextWindow.WriteLine("collision with " + i)
              touching[i]="True"
            Else
              
            EndIf
          Else
            touching[i]="False"
          EndIf
        Else       
        EndIf 
        'checks for bottom right
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If (((ex+15) >= px) and ((ex+15) <= (px+20)))Then
            If(touching[i]="False") Then
              health = health - healthloss
              TextWindow.WriteLine("collision with " + i)
              touching[i]="True"
            Else
              
            EndIf
          Else
            touching[i]="False"
          EndIf
          
          
        EndIf  
        'checks for bottom left
        If (((ey+15) >= py) and ((ey+15) <= (py+20))) Then
          If ((ex >= px) and (ex <= (px+20)))Then
            If(touching[i]="False") Then
              health = health - healthloss
              TextWindow.WriteLine("collision with " + i)
              touching[i]="True"
            Else
              
            EndIf
          Else
            touching[i]="False"
          EndIf  
          
        EndIf   
      endfor
    EndSub
    
    Sub stop
      'pressed="False"
      'Shapes.Move(player, playerx, playery)
      
    EndSub
    
    Sub frameDelay'codingCat is the person to thank for this.
      
      
      'Precise frame timing. More exact that program.delay() because it only
      'pauses for the length of time remiaining in the current frame, rather than for the 
      'entire time slice of the frame. Even with longer, or shorter frame processing
      'times, each fram will still be exactly frameLength in duration.
      While Clock.ElapsedMilliseconds - framestart < frameLength ' if the time right now subtracted from the start time is les than frame length, then keep it.
        'do nothing
        
        
      EndWhile
      framestart = Clock.ElapsedMilliseconds
    EndSub
    
    Sub savescore
      path = Program.Directory + "/Collision Game/"
      name = "High Score"
      ext = ".txt"
      
      If(score <= filesave[1]) Then 'if the score you got was less than your highscore, 
        'do not update the score, because that will become the score you got making the high score just a counter for the score you recently got.
        
      Else
        filesave[1] = score
      endif
      File.CreateDirectory(path)
      File.WriteContents(path+name+ext, filesave)
      
      
    endsub



    Matthew

    Monday, May 2, 2016 3:00 PM
  • Scratch that, i fixed it. Had to get each corner by itself. not as a whole.

    here is the import since its really really long. -RTW739

    i havent gotten to the smart enemy yet. 

    Yvan you should get higher this time. 


    Matthew

    Monday, May 2, 2016 3:57 PM
  • Alright, I finished the collision. I will work on adding a boss at the end of level 30 if you get there. and score will quadruple, but it will be hard as trying to catch a rice with chopsticks.(bruce lee reference)

    here is the import-ZTD015

    see how far you can get


    Matthew

    Monday, May 2, 2016 4:13 PM
  • I Press those keys:

    A to go left, D go right, S down, W up

    if i press A , the ship go to the left without stopping, the only way to stop is to press the S key then move the ship to the right, but there must be a way to stop the ship if i don't press any key ?

    What do you think of that ?

    Monday, May 2, 2016 4:13 PM
    Answerer
  • I did it that way so you can move faster, thats how i been able to get that high of a score. Test out the new game. import ztd015 i believe.

    Matthew

    Monday, May 2, 2016 4:15 PM
  • Mathew,

    i try your new version, i love the yellow ship following me everywhere !! wow !! that"s the smart ship isn't !

    for the score, seems this time much easier, nice job !!!

    that's the corner to corner detection i guess. it works!!!!

    Monday, May 2, 2016 4:22 PM
    Answerer
  • yes, thats because the velocity of the enemy doesnt go past 3. so its much slower. I was doing it at the speed where the enemy was at 8.5 velocity diagonal. much much faster. to change the speed of the enemy, go to createenemy and change vel to whatever number you want. can be a negative number.

    my max score now is 2586, with velocity = to 6. the other time was where vel = 3.


    Matthew


    Monday, May 2, 2016 4:29 PM
  • it's getting better and better !!!

    here's my score this time with version ztd015

    i've been trap by the yellow smart ship :)

    2401


    • Edited by YLedEditor Monday, May 2, 2016 7:39 PM smart ship
    Monday, May 2, 2016 7:38 PM
    Answerer