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.
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…