(Total coding time : 22 minutes. I actually timed it ) (And amazingly some ppl on the web actually charge for the source code!! )
Code: Select all
// 'Tetris' Arcade game.code by Mit
#include <Windows.h>
extern "C"
{
#include <StandardDef.h>
#include "Interface.h"
#include "Tetris.h"
}
#define TETRIS_PIECE_ROWS 3
#define TETRIS_PIECE_COLS 3
#define TETRIS_BOX_HEIGHT 210
#define TETRIS_BOX_ROWS 15
#define TETRIS_BLOCK_HEIGHT (TETRIS_BOX_HEIGHT/TETRIS_BOX_ROWS)
#define TETRIS_BOX_WIDTH 200
#define TETRIS_BOX_COLS 8
#define TETRIS_BLOCK_WIDTH (TETRIS_BOX_WIDTH/TETRIS_BOX_COLS)
#define TETRIS_BLOCK_SPOTS (TETRIS_BOX_COLS*TETRIS_BOX_ROWS)
int mnBlocksBoxX = 100; // Top left screen coord of the playing region
int mnBlocksBoxY = 20;
BYTE mabTetrisSpots[TETRIS_BOX_ROWS][ TETRIS_BOX_COLS ];
BYTE mabCurrentBlockShape[TETRIS_PIECE_ROWS][TETRIS_PIECE_COLS];
int mnCurrentBlockPosX = 4;
int mnCurrentBlockPosY = 1;
ulong mulNextMovePieceTime = 0;
ulong mulMoveDelayTime = 1000;
ulong mulNormalMoveDelayTime = 1000;
//-------------------------------------------------
// Function : TetrisCanMoveTo
// Checks that a position is valid for the current piece
//-------------------------------------------------
BOOL TetrisCanMoveTo( int nMoveToX, int nMoveToY )
{
int nX, nY;
int nPieceX, nPieceY;
nX = nMoveToX - 1;
nY = nMoveToY - 1;
for ( nPieceY = 0; nPieceY < 3; nPieceY++ )
{
for ( nPieceX = 0; nPieceX < 3; nPieceX++ )
{
if ( mabCurrentBlockShape[ nPieceY ][ nPieceX ] )
{
if ( ( (nY + nPieceY) >= TETRIS_BOX_ROWS ) ||
( (nX + nPieceX) >= TETRIS_BOX_COLS ) ||
( (nX + nPieceX) < 0 ) ||
( (nY + nPieceY) < 0 ) )
{
return( FALSE );
}
if ( mabTetrisSpots[ nY + nPieceY ][ nX + nPieceX ] != 0 )
{
return( FALSE );
}
}
}
}
return( TRUE );
}
//-------------------------------------------------
// Function : TetrisRotatePiece
// Rotates the current piece
//-------------------------------------------------
void TetrisRotatePiece( void )
{
BYTE mabCopyShape[TETRIS_PIECE_ROWS][TETRIS_PIECE_COLS];
memcpy( &mabCopyShape[0][0], &mabCurrentBlockShape[0][0], TETRIS_PIECE_ROWS*TETRIS_PIECE_COLS*sizeof(BYTE) );
// Fun fun.. manually change the position of the blockparts to rotate it
mabCurrentBlockShape[0][0] = mabCopyShape[2][0];
mabCurrentBlockShape[0][1] = mabCopyShape[1][0];
mabCurrentBlockShape[0][2] = mabCopyShape[0][0];
mabCurrentBlockShape[1][0] = mabCopyShape[2][1];
mabCurrentBlockShape[1][1] = mabCopyShape[1][1];
mabCurrentBlockShape[1][2] = mabCopyShape[0][1];
mabCurrentBlockShape[2][0] = mabCopyShape[2][2];
mabCurrentBlockShape[2][1] = mabCopyShape[1][2];
mabCurrentBlockShape[2][2] = mabCopyShape[0][2];
// Check the rotated piece is in a valid position. If not, restore the original rotation
if ( TetrisCanMoveTo( mnCurrentBlockPosX, mnCurrentBlockPosY ) == FALSE )
{
memcpy( &mabCurrentBlockShape[0][0], &mabCopyShape[0][0], TETRIS_PIECE_ROWS*TETRIS_PIECE_COLS*sizeof(BYTE) );
}
}
//-------------------------------------------------
// Function : TetrisDrawBlock
// Draws a single block on the playing area
//-------------------------------------------------
void TetrisDrawBlock( int nLayer, int nX, int nY,ulong ulCol )
{
nX *= TETRIS_BLOCK_WIDTH;
nY *= TETRIS_BLOCK_HEIGHT;
nX += mnBlocksBoxX;
nY += mnBlocksBoxY;
InterfaceRect( 1, nX, nY, TETRIS_BLOCK_WIDTH, TETRIS_BLOCK_HEIGHT, ulCol );
InterfaceRect( 2, nX, nY, 2, TETRIS_BLOCK_HEIGHT, 0x80D0D0D0 );
InterfaceRect( 2, nX, nY, TETRIS_BLOCK_WIDTH, 2, 0x80D0D0D0 );
InterfaceRect( 2, nX + TETRIS_BLOCK_WIDTH - 2, nY, 2, TETRIS_BLOCK_HEIGHT, 0x80101010 );
InterfaceRect( 2, nX, nY + TETRIS_BLOCK_HEIGHT - 2, TETRIS_BLOCK_WIDTH, 2, 0x80101010 );
}
//-------------------------------------------------
// Function : TetrisCheckRowComplete
// Returns TRUE if the specified row is full of blocks
//-------------------------------------------------
BOOL TetrisCheckRowComplete( int nY )
{
int nX;
for ( nX = 0; nX < TETRIS_BOX_COLS; nX++ )
{
// If any of the blocks in the row are not filled, the line is not complete
if ( mabTetrisSpots[ nY ][ nX ] == 0 )
{
return( FALSE );
}
}
return( TRUE );
}
//-------------------------------------------------
// Function : TetrisRemoveRow
// Removes the specified row and moves the other rows down
//-------------------------------------------------
void TetrisRemoveRow( int nY )
{
int nLoop;
int nX;
for ( nLoop = nY; nLoop > 0; nLoop-- )
{
for ( nX = 0; nX < TETRIS_BOX_COLS; nX++ )
{
mabTetrisSpots[ nLoop ][ nX ] = mabTetrisSpots[ nLoop-1 ][ nX ];
}
}
}
//-------------------------------------------------
// Function : TetrisStorePiece
// Puts the current piece into the background blocks
//-------------------------------------------------
void TetrisStorePiece( void )
{
int nX;
int nY;
int nPieceX;
int nPieceY;
nX = mnCurrentBlockPosX - 1;
nY = mnCurrentBlockPosY - 1;
for ( nPieceY = 0; nPieceY < TETRIS_PIECE_ROWS; nPieceY++ )
{
for ( nPieceX = 0; nPieceX < TETRIS_PIECE_COLS; nPieceX++ )
{
if ( mabCurrentBlockShape[ nPieceY ][ nPieceX ] != 0 )
{
mabTetrisSpots[ nY + nPieceY ][ nX + nPieceX ] = mabCurrentBlockShape[ nPieceY ][ nPieceX ];
}
}
}
// Now check for any complete rows and remove em
for ( nY = TETRIS_BOX_ROWS-1; nY > 0; nY-- )
{
if ( TetrisCheckRowComplete( nY ) == TRUE )
{
TetrisRemoveRow( nY );
nY++;
}
}
}
//-------------------------------------------------
// Function : TetrisUpdate
// Main update function called every frame. Draws the game and moves the current piece if neccessary
//-------------------------------------------------
void TetrisUpdate( void )
{
int nX;
int nY;
int nBlockX;
int nBlockY;
ulong ulTick = GetTickCount();
InterfaceRect( 1, mnBlocksBoxX, mnBlocksBoxY, TETRIS_BOX_WIDTH, TETRIS_BOX_HEIGHT, 0xFF000060 );
// Draw all the blocks in place
for ( nY = 0; nY < TETRIS_BOX_ROWS; nY++ )
{
for ( nX = 0; nX < TETRIS_BOX_COLS; nX++ )
{
switch( mabTetrisSpots[ nY ][ nX ] )
{
case 1:
TetrisDrawBlock( 2,nX, nY, 0xFFD03010 );
break;
default:
break;
}
}
}
// Draw the current block
for ( nY = 0; nY < 3; nY++ )
{
for ( nX = 0; nX < 3; nX++ )
{
nBlockX = (mnCurrentBlockPosX - 1 + nX);
nBlockY = (mnCurrentBlockPosY - 1 + nY);
switch( mabCurrentBlockShape[ nY ][ nX ] )
{
case 1:
TetrisDrawBlock( 2, nBlockX, nBlockY, 0xFFD03010 );
break;
}
}
}
// Update the current blocks position if the time has run out.
if ( mulNextMovePieceTime < ulTick )
{
mulNextMovePieceTime = ulTick + mulMoveDelayTime;
if ( TetrisCanMoveTo( mnCurrentBlockPosX, mnCurrentBlockPosY + 1 ) == TRUE )
{
mnCurrentBlockPosY++;
}
else
{
if ( mnCurrentBlockPosY == 1 )
{
// Game Over!!!
}
else
{ // Spawn a new piece
// First copy the existing
TetrisStorePiece();
mnCurrentBlockPosY = 1;
mnCurrentBlockPosX = 4;
mulMoveDelayTime = mulNormalMoveDelayTime;
}
}
}
}
//-------------------------------------------------
// Function : TetrisInitGraphics
// Initialisation function for the game
//-------------------------------------------------
void TetrisInitGraphics( void )
{
ZeroMemory( mabTetrisSpots, sizeof( BYTE ) * TETRIS_BLOCK_SPOTS );
mabTetrisSpots[ TETRIS_BOX_ROWS-1][0] = 1;
ZeroMemory( mabCurrentBlockShape, sizeof( BYTE ) * TETRIS_PIECE_ROWS * TETRIS_PIECE_COLS );
mabCurrentBlockShape[ 1 ][ 0 ] = 1;
mabCurrentBlockShape[ 1 ][ 1 ] = 1;
mabCurrentBlockShape[ 1 ][ 2 ] = 1;
mabCurrentBlockShape[ 2 ][ 2 ] = 1;
}
//-------------------------------------------------
// Function : TetrisFreeGraphics
// DeInitialisation function for the game
//-------------------------------------------------
void TetrisFreeGraphics( void )
{
}
//-------------------------------------------------
// Function : TetrisKeydown
// Called when a key is pressed
//-------------------------------------------------
BOOL TetrisKeyDown( short key )
{
if ( key == VK_LEFT )
{
if ( TetrisCanMoveTo( mnCurrentBlockPosX - 1, mnCurrentBlockPosY ) == TRUE )
{
mnCurrentBlockPosX--;
}
}
if ( key == VK_UP )
{
TetrisRotatePiece();
}
if ( key == VK_DOWN )
{
mulMoveDelayTime = 50;
mulNextMovePieceTime = 0;
}
if ( key == VK_RIGHT )
{
if ( TetrisCanMoveTo( mnCurrentBlockPosX + 1, mnCurrentBlockPosY ) == TRUE )
{
mnCurrentBlockPosX++;
}
}
return( FALSE );
}
BOOL TetrisKeyUp( short key )
{
return( FALSE );
}