BlitzBASIC Tetris Clone

This page demonstrates some code needed for a tetris clone that has more features such as: ability to end a game and start a new one, without exiting the program, ability to pause the game, ability to rotate pieces left OR right, ability to drop pieces instantly, the next piece is shown on-screen, ghost piece (for instant drop) is shown, animated line erase, simple animation displayed when player clears lines or levels up, uses some fancier looking blocks, background gridlines.

blitzbasic-tetris-clone-1

 

Start with setting up the graphics:

Graphics 800, 600 ;2D graphics at a resolution of 800x600
SetBuffer BackBuffer() ;do all drawing to the back drawing buffer

Seed the random number generator:

SeedRnd MilliSecs() ;needed to get random numbers

Dimension the arrays that you will need:

Dim Board(9, 22) ;10x20 game board (+3 rows above the board)
Dim BlockColor(7, 2) ;stores r,g,b colors (0-2) for each of the 7 pieces
Dim Piece(28, 3, 3) ;28 (4x4) piece descriptions (7 pieces in each of 4 rotations)
Dim LineToErase(4) ;keeps track of which lines to erase (with animation)

Read in the color data for the pieces:

For iter = 1 To 7 ;loop through seven pieces
  Read BlockColor(iter, 0) ;read the red amount
  Read BlockColor(iter, 1) ;read the green amount
  Read BlockColor(iter, 2) ;read the blue amount
Next
Data 255, 255, 0;yellow ;color of square
Data 0, 128, 255;turquoise ;color of line
Data 0, 0, 255  ;blue ;color of left L
Data 255, 128, 0;orange ;color of right L
Data 255, 0, 0  ;red ;color of left s
Data 0, 255, 0  ;green ;color of right s
Data 128, 0, 255;purple ;color of tee

Read the piece descriptions into the description array:

For iter = 1 To 28 ;loop through 28 descriptions (7x4)
  For yiter = 0 To 3 ;loop through the rows of the description
    For xiter = 0 To 3 ;loop through the columns of the description
      Read Piece(iter, xiter, yiter) ;read in the data (0=blank, 1=filled)
    Next
  Next ;example of right L    0100
Next ;as a 4x4 matrix       0100
;in its 90deg rotation 0110
;piece descriptions ;(right L rot 1) 0000
Data 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;square
Data 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 ;line
Data 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;left L
Data 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;right L
Data 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;left s
Data 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;right s
Data 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;tee up
;rotated 90 degrees cw
Data 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;square
Data 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0 ;line rot 1
Data 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;left L rot 1
Data 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 ;right L rot 1
Data 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ;left s sideways
Data 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;right s sideways
Data 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;tee right
;rotated 180 degrees cw
Data 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;square
Data 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 ;line rot 2
Data 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 ;left L rot 2
Data 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0 ;right L rot 2
Data 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;left s
Data 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;right s
Data 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;tee down
;rotated 270 degrees cw
Data 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;square
Data 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 ;line rot 3
Data 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 ;left L rot 3
Data 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;right L rot 3
Data 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ;left s sideways
Data 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;right s sideways
Data 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ;tee left

We’ll set up some screen origins just so that we don’t have to offset all of our drawing commands.

Global OrigBoardX      = 210 ;board origin
Global OrigBoardY      = 5
Global OrigLevelLinesX = 500 ;level & lines origin
Global OrigLevelLinesY = 186  
Global OrigNextPieceX  = 600 ;next piece origin
Global OrigNextPieceY  = 75
Global OrigMessAreaX   = 500 ;message area origin
Global OrigMessAreaY   = 300
Global OrigKeyMapX     = 0  ;key mapping text origin
Global OrigKeyMapY     = 300

Next, we’ll type in these Global variables so that we can use them anywhere within the code: (notice that EndOfGame is being initialized as True)

Global Level ;current game level
Global Lines ;number of lines remaining to clear to level up
Global EndOfGame = True ;flag used to determine if a game is running or not
Global CurrentPiece ;the current piece (1-7) that is falling
Global CurPieceX ;the current pieces X position
Global CurPieceY ;the Y position
Global CurPieceRot ;the rotation (0-3) of the current piece
Global NextPiece ;the next piece (1-7) that will fall
Global GhostPieceY ;Y position of the Ghost piece
Global RepeatSpeed ;time (milliseconds) between L or R keypresses
Global RepeatDelay ;if true then makes delay between keypresses longer
Global NowTime
Global LastDropTime
Global DropSpeed
Global DropDelay
Global GamePaused
Global PauseTime
Global NumLines
Global ClearLines
Global BlockToErase#
Global Points
Global PointColorFade
Global LevelUpColorFade

And we need just a few more Globals to keep track of keypresses:

Global KeyEsc
Global KeyPause
Global KeyRotate
Global KeyRotateLeft
Global KeyLeft
Global KeyRight
Global KeyDwn
Global KeyInstantDrop
Global KeyN
Global KeyQ

And now we’re ready to type in the Main loop:

Repeat
  Cls
  DrawBoard()
  DrawInfo()
  If GamePaused
    DrawPauseMessage()
  Else
    DrawBoardBlocks()
    DrawNextPiece()
    If Not ClearLines
      If Not EndOfGame Then DrawGhostPiece()
      DrawCurrentPiece()
    EndIf
  EndIf
  ProcessInputs()
  If Not EndOfGame
    If Not ClearLines
      If Not GamePaused
        If KeyDwn
          DropDelay = 35
        Else
          DropDelay = DropSpeed
        EndIf
        NowTime = MilliSecs()
        If (NowTime > LastDropTime + DropDelay) Or KeyInstantDrop
          LastDropTime = NowTime
          If Not DropPiece()
            If Not PlacePiece()
              EndGame()
            EndIf
          EndIf
        EndIf
      EndIf
    Else
      LineClearer()
    EndIf
  Else
    PrintGameOver()
  EndIf

  Flip
Until KeyHit(1);Esc key
End

And now we can enter in each of the functions we’ll need. A function to handle player input:

Function ProcessInputs()
  KeyEsc = KeyHit(1) ;Esc key
  KeyPause = KeyHit(25) Or KeyHit(197) ;P key, Pause key
  KeyRotate = KeyHit(57) Or KeyHit(45) ;spacebar, X key
  KeyRotateLeft = KeyHit(44) ;Z key
  KeyLeft = KeyDown(203) ;left key
  KeyRight = KeyDown(205) ;right key
  KeyDwn = KeyDown(208) ;down key
  KeyInstantDrop = KeyHit(200) ;up key
  KeyN = KeyHit(49) ;N key
  KeyQ = KeyHit(16) ;Q key

  If Not EndOfGame
    If KeyRotate Then RotatePiece() ;space key or X key
    If KeyRotateLeft Then RotatePiece(True); Z key
    If (Not KeyLeft) And (Not KeyRight)
      RepeatDelay = True
    Else
      If RepeatSpeed < NowTime
        If RepeatDelay
          RepeatSpeed = NowTime + 150
          RepeatDelay = False
        Else
          RepeatSpeed = NowTime + 30
        EndIf
        If keyLeft Then MoveLeft()
        If keyRight Then MoveRight()
      EndIf
    EndIf
    If KeyInstantDrop Then CurPieceY = GhostPieceY
    If KeyEsc Or KeyPause
      If GamePaused
        GamePaused = False
        LastDropTime = LastDropTime + MilliSecs() - PauseTime
      Else
        GamePaused = True
        PauseTime = MilliSecs()
      EndIf
    EndIf
    If KeyQ Then EndGame()  ;quit game
  Else
    If KeyN Then StartNewGame()  ;new game
    If KeyEsc Then End
  EndIf
End Function

Unfinished… Download it the full Source Code…

Leave a Reply

Your email address will not be published. Required fields are marked *