// Project: XnaTetris, File: TetrisGrid.cs
// Namespace: XnaTetris, Class: TetrisGrid
// Path: C:\code\XnaBook\XnaTetris, Author: Abi
// Code lines: 16, Size of file: 298 Bytes
// Creation date: 21.11.2006 03:56
// Last modified: 26.11.2006 13:21
// Generated with Commenter by abi.exDream.com
#region Using directives
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using XnaTetris.Helpers;
using XnaTetris.Sounds;
#endregion
namespace XnaTetris
{
///
/// TetrisGrid helper class to manage the grid and all block types for
/// the tetris game.
///
public class TetrisGrid : Microsoft.Xna.Framework.DrawableGameComponent
{
#region Constants
public const int GridWidth = 12;
public const int GridHeight = 20;
///
/// Block types we can have for each new block that falls down.
///
public enum BlockTypes
{
Empty,
Block,
Triangle,
Line,
RightT,
LeftT,
RightShape,
LeftShape,
} // enum BlockTypes
///
/// Number of block types we can use for each grid block.
///
public static readonly int NumOfBlockTypes =
#if XBOX360
8;
#else
EnumHelper.GetSize(typeof(BlockTypes));
#endif
///
/// Block colors for each block type.
///
public static readonly Color[] BlockColor = new Color[]
{
new Color( 60, 60, 60, 128 ), // Empty, color unused
new Color( 50, 50, 255, 255 ), // Line, blue
new Color( 160, 160, 160, 255 ), // Block, gray
new Color( 255, 50, 50, 255 ), // RightT, red
new Color( 255, 255, 50, 255 ), // LeftT, yellow
new Color( 50, 255, 255, 255 ), // RightShape, teal
new Color( 255, 50, 255, 255 ), // LeftShape, purple
new Color( 50, 255, 50, 255 ), // Triangle, green
}; // Color[] BlockColor
///
/// Unrotated shapes
///
public static readonly int[][,] BlockTypeShapesNormal = new int[][,]
{
// Empty
new int[,] { { 0 } },
// Line
new int[,] { { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 }, { 0, 1, 0 } },
// Block
new int[,] { { 1, 1 }, { 1, 1 } },
// RightT
new int[,] { { 1, 1 }, { 1, 0 }, { 1, 0 } },
// LeftT
new int[,] { { 1, 1 }, { 0, 1 }, { 0, 1 } },
// RightShape
new int[,] { { 0, 1, 1 }, { 1, 1, 0 } },
// LeftShape
new int[,] { { 1, 1, 0 }, { 0, 1, 1 } },
// LeftShape
new int[,] { { 0, 1, 0 }, { 1, 1, 1 }, { 0, 0, 0 } },
}; // BlockTypeShapesNormal
#endregion
#region Variables
///
/// Remember game for accessing textures and sprites
///
TetrisGame game = null;
///
/// Precalculated Rotated shapes
///
static int[,][,] BlockTypeShapes;
///
/// The actual grid, contains all blocks,
/// including the currently falling block.
///
BlockTypes[,] grid = new BlockTypes[GridWidth, GridHeight];
///
/// Use this simple array to see where the floating parts are.
/// Simply check from bottom up and putting stuff in the next line.
///
bool[,] floatingGrid = new bool[GridWidth, GridHeight];
///
/// When game is over, this is set to true, start over then!
///
public bool gameOver = false;
///
/// Remember current block type and rotation
///
int currentBlockType = 0;
int currentBlockRot = 0;
Point currentBlockPos;
///
/// Next block game component, does not only store the next block type,
/// but also displays it.
///
internal NextBlock nextBlock;
///
/// Grid rectangle for drawing.
///
Rectangle gridRect;
#endregion
#region Constructor
public TetrisGrid(TetrisGame setGame, Rectangle setGridRect,
Rectangle setNextBlockRect)
: base(setGame)
{
game = setGame;
gridRect = setGridRect;
nextBlock = new NextBlock(game, setNextBlockRect);
game.Components.Add(nextBlock);
} // TetrisGrid(game)
#endregion
#region Initialize
public override void Initialize()
{
// Precalculate Rotated shapes, for all types
BlockTypeShapes = new int[NumOfBlockTypes, 4][,];
for (int type = 0; type < NumOfBlockTypes; type++)
{
int[,] shape = BlockTypeShapesNormal[type];
int width = shape.GetLength(0);
int height = shape.GetLength(1);
// Init all precalculated shapes
BlockTypeShapes[type, 0] = new int[height, width];
BlockTypeShapes[type, 1] = new int[width, height];
BlockTypeShapes[type, 2] = new int[height, width];
BlockTypeShapes[type, 3] = new int[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
BlockTypeShapes[type, 0][y, x] = shape[(width - 1) - x, y];
BlockTypeShapes[type, 1][x, y] = shape[x, y];
BlockTypeShapes[type, 2][y, x] = shape[x, (height - 1) - y];
BlockTypeShapes[type, 3][x, y] =
shape[(width - 1) - x, (height - 1) - y];
} // for for
} // for
Restart();
AddRandomBlock();
base.Initialize();
} // Initialize()
#endregion
#region Restart
public void Restart()
{
for ( int x=0; x
/// Adds a random block in the top middle
///
public void AddRandomBlock()
{
// Randomize block type and rotation
currentBlockType = (int)nextBlock.SetNewRandomBlock();
currentBlockRot = RandomHelper.GetRandomInt(4);
// Get precalculated shape
int[,] shape = BlockTypeShapes[currentBlockType,currentBlockRot];
int xPos = GridWidth/2-shape.GetLength(0)/2;
// Center block at top most position of our grid
currentBlockPos = new Point(xPos, 0);
// Add new block
for ( int x=0; x 0 )
{
// Check if there is already something
if (grid[x + xPos, y] != BlockTypes.Empty)
{
// Then game is over dude!
gameOver = true;
Sound.Play(Sound.Sounds.Lose);
} // if
else
{
grid[x + xPos, y] = (BlockTypes)currentBlockType;
floatingGrid[x + xPos, y] = true;
} // else
} // for for if
// Add 1 point per block!
score++;
} // AddRandomBlock()
#endregion
#region Move block
public enum MoveTypes
{
Left,
Right,
Down,
} // enum MoveTypes
///
/// Remember if moving down was blocked, this increases
/// the game speed because we can force the next block!
///
public bool movingDownWasBlocked = false;
///
/// Move current floating block to left, right or down.
/// If anything is blocking, moving is not possible and
/// nothing gets changed!
///
/// Returns true if moving was successful, otherwise false
public bool MoveBlock(MoveTypes moveType)
{
// Clear old pos
for ( int x=0; x= GridWidth ||
grid[x+1,y] != BlockTypes.Empty )
anythingBlocking = true;
else if ( newPosNum < 4 )
{
newPos[newPosNum] = new Point( x+1, y );
newPosNum++;
} // else if
} // for for if
} // if (right)
else if ( moveType == MoveTypes.Down )
{
for ( int x=0; x= GridHeight ||
grid[x,y+1] != BlockTypes.Empty )
anythingBlocking = true;
else if ( newPosNum < 4 )
{
newPos[newPosNum] = new Point( x, y+1 );
newPosNum++;
} // else if
} // for for if
if ( anythingBlocking == true )
movingDownWasBlocked = true;
} // if (down)
// If anything is blocking restore old state
if ( anythingBlocking ||
// Or we didn't get all 4 new positions?
newPosNum != 4 )
{
for ( int x=0; x 0 )
{
if ( currentBlockPos.X+x >= GridWidth ||
currentBlockPos.Y+y >= GridHeight ||
currentBlockPos.X+x < 0 ||
currentBlockPos.Y+y < 0 ||
grid[currentBlockPos.X+x,currentBlockPos.Y+y] != BlockTypes.Empty )
anythingBlocking = true;
else if ( newPosNum < 4 )
{
newPos[newPosNum] = new Point(
currentBlockPos.X+x, currentBlockPos.Y+y );
newPosNum++;
} // else if
} // for for if
// If anything is blocking restore old state
if ( anythingBlocking ||
// Or we didn't get all 4 new positions?
newPosNum != 4 )
{
for ( int x=0; x
/// Update whole field, move current floating stuff down
/// and check if any full lines are given.
/// Note: Do not use the override Update(gameTime) method here,
/// Update is ONLY called when 1000ms have passed (level 1), or
/// 100ms for level 10.
///
public void Update()
{
if (gameOver)
return;
// Try to move floating stuff down
if (MoveBlock(MoveTypes.Down) == false ||
movingDownWasBlocked)
{
// Failed? Then fix floating stuff, not longer moveable!
for ( int x=0; x0; yDown-- )
for ( int x=0; x= 2)
score += 5;
if (linesKilled >= 3)
score += 10;
if (linesKilled >= 4)
score += 25;
// Add new block at top
AddRandomBlock();
} // if
} // Update()
#endregion
#region Draw
public override void Draw(GameTime gameTime)
{
// Show next block
nextBlock.Draw(gameTime);
// Calc sizes for block, etc.
int blockWidth = gridRect.Width / GridWidth;
int blockHeight = gridRect.Height / GridHeight;
if ( blockWidth < 2 )
blockWidth = 2;
if ( blockHeight < 2 )
blockHeight = 2;
for ( int x=0; x