' Inspired by "Code-It-Yourself Breakout in 30 minutes?" -- @javidx9
' https://youtu.be/Il6kREcjdzE
' Updated to olcPixelGameEngineVb

Imports VbPixelGameEngine
Imports VbPixelGameEngine.Color
Imports VbPixelGameEngine.PixelType

Module Program

  Sub Main()
    Dim game As New Breakout
    'If game.ConstructConsole(256, 240, 4, 4) Then
    If game.ConstructConsole(128, 120, 4, 4) Then
      game.Start()
    End If
  End Sub

End Module

Class Breakout
  Inherits PixelGameEngine

  Private m_level() As Char
  Private ReadOnly m_width As Integer = 16
  Private ReadOnly m_height As Integer = 15
  Private ReadOnly m_block As Integer = 8

  Private m_bat As Single = 64.0F

  Private m_ballX As Single = 64.0F
  Private m_ballY As Single = 64.0F
  Private m_ballDx As Single
  Private m_ballDy As Single

  Sub New()
    AppName = "Breakout"
  End Sub

  Protected Overrides Function OnUserCreate() As Boolean

    Dim level = "################"
    level += "#..............#"
    level += "#...11111111...#"
    level += "#...11111111...#"
    level += "#...11....11...#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"
    level += "#..............#"

    ReDim m_level((m_width * m_height) - 1)
    For index = 0 To level.Length - 1
      m_level(index) = level(index)
    Next

    'Dim ang = CSng(Rand / RAND_MAX) * 3.14159F * 2.0F
    Dim ang = 0.6F
    m_ballDx = CSng(Math.Cos(ang))
    m_ballDy = CSng(Math.Sin(ang))

    Return True

  End Function

  Protected Overrides Function OnUserUpdate(elapsedTime As Single) As Boolean

    Dim batWidth = 10
    Dim speed = 40.0F

    Clear()

    If GetKey(Key.LEFT).Held Then m_bat -= 60.0F * elapsedTime
    If GetKey(Key.RIGHT).Held Then m_bat += 60.0F * elapsedTime

    If m_bat - batWidth < m_block Then m_bat = m_block + batWidth
    If m_bat + batWidth > (m_width - 1) * m_block Then m_bat = (m_width - 1) * m_block - batWidth

    Dim oldX = m_ballX
    Dim oldY = m_ballY
    m_ballX += m_ballDx * elapsedTime * speed
    m_ballY += m_ballDy * elapsedTime * speed

    Dim cellOldX = CInt(Fix(oldX / m_block))
    Dim cellOldY = CInt(Fix(oldY / m_block))

    Dim cellNewX = CInt(Fix(m_ballX / m_block))
    Dim cellNewY = CInt(Fix(m_ballY / m_block))

    Dim newCell = m_level(cellNewY * m_width + cellNewX)
    Dim oldCell = m_level(cellOldY * m_width + cellOldX)

    If newCell <> "."c Then

      If newCell = "1"c Then m_level(cellNewY * m_width + cellNewX) = "."c

      If cellNewX <> cellOldX Then m_ballDx *= -1
      If cellNewY <> cellOldY Then m_ballDy *= -1

    End If

    If m_ballY > m_height * m_block - 2 Then
      If m_ballX > m_bat - batWidth AndAlso m_ballX < m_bat + batWidth Then
        m_ballDy *= -1
      Else
        ' Dead
        m_ballX = (m_width / 2.0F) * m_block
        m_ballY = (m_height / 2.0F) * m_block
        Dim ang = CSng(Rand / RAND_MAX) * 3.14159F * 2.0F
        m_ballDx = CSng(Math.Cos(ang))
        m_ballDy = CSng(Math.Sin(ang))
      End If
    End If

    ' Draw Level
    For y = 0 To m_height - 1
      For x = 0 To m_width - 1
        Select Case m_level(y * m_width + x)
          Case "#"c
            Fill(x * m_block, y * m_block, (x + 1) * m_block, (y + 1) * m_block, Solid, FgWhite)
          Case "1"c
            Fill(x * m_block, y * m_block, (x + 1) * m_block, (y + 1) * m_block, Solid, FgGreen)
          Case "."c
            Fill(x * m_block, y * m_block, (x + 1) * m_block, (y + 1) * m_block, Solid, FgBlack)
          Case Else
            Stop
        End Select
      Next
    Next

    FillCircle(m_ballX, m_ballY, 2.0F, Solid, FgYellow)

    DrawLine(m_bat - batWidth, m_height * m_block - 2, m_bat + batWidth, m_height * m_block - 2, Solid, FgWhite)

    Return True

  End Function

End Class
