// Project: XnaTetris, File: TetrisGame.cs
// Namespace: XnaTetris, Class: TetrisGame
// Path: C:\code\XnaBook\XnaTetris, Author: Abi
// Code lines: 16, Size of file: 298 Bytes
// Creation date: 24.11.2006 03:56
// Last modified: 25.11.2006 13:21
// Generated with Commenter by abi.exDream.com
#region Using directives
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using XnaTetris.Helpers;
using XnaTetris.Graphics;
using XnaTetris.Game;
using XnaTetris.Sounds;
#endregion
namespace XnaTetris
{
///
/// This is the main type for your game
///
public class TetrisGame : BaseGame
{
#region Variables
///
/// Textures for the background, the box and the blocks.
///
Texture2D backgroundTexture, blockTexture,
backgroundSmallBoxTexture, backgroundBigBoxTexture;
///
/// Block and background as sprite helpers.
///
SpriteHelper block, background, backgroundSmallBox, backgroundBigBox;
///
/// TetrisGrid helper, handles all the graphical aspects!
///
TetrisGrid tetrisGrid;
///
/// Level, which sets the difficulty. Starts at level 1 until
/// we reach level 10 (which is 10 times as fast), then there
/// is no limit, but the game does not get any harder.
///
int level = 0;
///
/// Highscore
///
int highscore;
#endregion
#region Properties
public SpriteHelper BlockSprite
{
get
{
return block;
} // get
} // BlockSprite
#endregion
#region Constructor
public TetrisGame()
{
// Create components
tetrisGrid = new TetrisGrid(this,
new Rectangle(512 - 200, 40, 400, 768 - (40 + 44)),
new Rectangle(512 - 480 + 10, 40, 290 - 50, 280));
this.Components.Add(tetrisGrid);
} // TetrisGame
#endregion
#region Load content
///
/// Load all graphics content (just our background texture).
/// Use this method to make sure a device reset event is handled correctly.
///
/// Load everything?
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// Load all our content
backgroundTexture = content.Load("SpaceBackground");
blockTexture = content.Load("Block");
backgroundSmallBoxTexture = content.Load("BackgroundSmallBox");
backgroundBigBoxTexture = content.Load("BackgroundBigBox");
// Create all sprites
block = new SpriteHelper(blockTexture, null);
background = new SpriteHelper(backgroundTexture, null);
backgroundSmallBox = new SpriteHelper(backgroundSmallBoxTexture, null);
backgroundBigBox = new SpriteHelper(backgroundBigBoxTexture, null);
} // if
base.LoadGraphicsContent(loadAllContent);
} // LoadGraphicsContent(loadAllContent)
#endregion
#region Update
///
/// Remember current game time and when we pressed left, right
/// or down the last time to allow movement after waiting for a key
/// timeout.
///
int elapsedGameMs = 0;
int pressedLeftMs = 0;
int pressedRightMs = 0;
int pressedDownMs = 0;
///
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input and playing audio.
///
/// Provides a snapshot of timing values.
protected override void Update(GameTime gameTime)
{
int oldGameMs = elapsedGameMs;
int frameMs = (int)gameTime.ElapsedGameTime.TotalMilliseconds;
elapsedGameMs += frameMs;
// Game tick time, 1000 for difficutly=0, 100 for difficutly=9
int gameTickTime = 1000 / (level + 1);
if (elapsedGameMs / gameTickTime != oldGameMs / gameTickTime ||
tetrisGrid.movingDownWasBlocked == true)
tetrisGrid.Update();
if (tetrisGrid.lines / 10 > level)
{
level++;
Sound.Play(Sound.Sounds.Victory);
} // if
// Handle input, we have 2 modes: Immediate response if one of the
// keys is pressed to move our block and after a timeout we move even
// more. This is a slight change, but has a nice impact on the game
// feeling as controlling the current block feels more natural.
if (Input.KeyboardLeftPressed ||
Input.GamePadLeftPressed)
pressedLeftMs += frameMs;
else
pressedLeftMs = 0;
if (Input.KeyboardRightPressed ||
Input.GamePadRightPressed)
pressedRightMs += frameMs;
else
pressedRightMs = 0;
if (Input.KeyboardDownPressed ||
Input.GamePadDownPressed ||
Input.Keyboard.IsKeyDown(Keys.Space) ||
Input.GamePadAPressed)
pressedDownMs += frameMs;
else
pressedDownMs = 0;
if (Input.KeyboardLeftJustPressed ||
Input.GamePadLeftJustPressed ||
pressedLeftMs > 200)
{
if (pressedLeftMs > 75)
pressedLeftMs -= 75;
tetrisGrid.MoveBlock(TetrisGrid.MoveTypes.Left);
} // if
else if (Input.KeyboardRightJustPressed ||
Input.GamePadRightJustPressed ||
pressedRightMs > 200)
{
if (pressedRightMs > 75)
pressedRightMs -= 75;
tetrisGrid.MoveBlock(TetrisGrid.MoveTypes.Right);
} // else if
else if (Input.KeyboardDownJustPressed ||
Input.GamePadDownJustPressed ||
Input.KeyboardSpaceJustPressed ||
Input.GamePadAJustPressed ||
pressedDownMs > 150)
{
if (pressedDownMs > 50)
pressedDownMs -= 50;
tetrisGrid.MoveBlock(TetrisGrid.MoveTypes.Down);
} // else if
else if (Input.KeyboardUpJustPressed ||
Input.GamePadUpJustPressed)
{
tetrisGrid.RotateBlock();
} // else
if (tetrisGrid.score > highscore)
highscore = tetrisGrid.score;
if (tetrisGrid.gameOver &&
(Input.KeyboardSpaceJustPressed ||
Input.GamePadAJustPressed))
{
tetrisGrid.gameOver = false;
tetrisGrid.score = 0;
tetrisGrid.lines = 0;
level = 0;
tetrisGrid.Restart();
} // if
// Update title
//obs: Window.Title = "Xna Tetris - Level " + (level + 1) +
// " - Score " + tetrisGrid.score +
// " - Highscore " + highscore;
base.Update(gameTime);
} // Update(gameTime)
#endregion
#region Draw
///
/// This is called when the game should draw itself.
///
/// Provides a snapshot of timing values.
protected override void Draw(GameTime gameTime)
{
// Don't render background boxes or tetris grid for unit tests
if (isUnitTest)
{
base.Draw(gameTime);
return;
} // if
// Render background
background.Render();
// Draw background boxes for all the components
backgroundBigBox.Render(new Rectangle(
(512 - 200) - 15, 40 - 12, 400 + 23, (768 - (40 + 41)) + 16));
backgroundSmallBox.Render(new Rectangle(
(512 - 480) - 15 + 10, 40 - 10, 290 - 30, 300));
backgroundSmallBox.Render(new Rectangle(
(512 + 240) - 15 - 10, 40 - 10, 290 - 30, 190));
// Show tetris grid in center of screen
tetrisGrid.Draw(gameTime);
// Show current level, score, etc.
TextureFont.WriteText(512 + 230, 50, "Level: ");
TextureFont.WriteText(512 + 400, 50, (level + 1).ToString());
TextureFont.WriteText(512 + 230, 90, "Score: ");
TextureFont.WriteText(512 + 400, 90, tetrisGrid.score.ToString());
TextureFont.WriteText(512 + 230, 130, "Lines: ");
TextureFont.WriteText(512 + 400, 130, tetrisGrid.lines.ToString());
TextureFont.WriteText(512 + 230, 170, "Highscore: ");
TextureFont.WriteText(512 + 400, 170, highscore.ToString());
base.Draw(gameTime);
} // Draw(gameTime)
#endregion
#region Start game
static bool isUnitTest = true;
public static void StartGame()
{
isUnitTest = false;
using (TetrisGame game = new TetrisGame())
{
game.Run();
} // using
} // StartGame()
#endregion
#region Unit tests
#if DEBUG
#region TestBackgroundBoxes
public static void TestBackgroundBoxes()
{
TestGame.Start("TestBackgroundBoxes",
delegate
{
// Render background
TestGame.game.background.Render();
// Draw background boxes for all the components
TestGame.game.backgroundBigBox.Render(new Rectangle(
(512 - 200) - 15, 40 - 12, 400 + 23, (768 - 40) + 16));
TestGame.game.backgroundSmallBox.Render(new Rectangle(
(512 - 480) - 15, 40 - 10, 290 - 30, 300));
TestGame.game.backgroundSmallBox.Render(new Rectangle(
(512 + 240) - 15, 40 - 10, 290 - 30, 190));
});
} // TestBackgroundBoxes()
#endregion
#region TestEmptyGrid
public static void TestEmptyGrid()
{
TestGame.Start("TestEmptyGrid",
delegate
{
// Render background
TestGame.game.background.Render();
// Draw background box
TestGame.game.backgroundBigBox.Render(new Rectangle(
(512 - 200) - 15, 40 - 12, 400 + 23, (768 - 40) + 16));
// Show TetrisGrid component inside that box
TestGame.game.tetrisGrid.Draw(new GameTime());
});
} // TestEmptyGrid()
#endregion
#region TestNextBlock
public static void TestNextBlock()
{
TestGame.Start("TestNextBlock",
delegate
{
// Render background
TestGame.game.background.Render();
// Draw background box
TestGame.game.backgroundSmallBox.Render(new Rectangle(
(512 - 480) - 15, 40 - 10, 290 - 30, 300));
// Show NextBlock component inside that box
TestGame.game.tetrisGrid.nextBlock.Draw(new GameTime());
});
} // TestNextBlock()
#endregion
#region TestScoreboard
public static void TestScoreboard()
{
int level = 3, score = 350, highscore = 1542, lines = 13;
TestGame.Start("TestScoreboard",
delegate
{
// Draw background box
TestGame.game.backgroundSmallBox.Render(new Rectangle(
(512 + 240) - 15, 40 - 10, 290 - 30, 190));
// Show tetris grid in center of screen
TestGame.game.tetrisGrid.Draw(new GameTime());
// Show current level, score, etc.
TextureFont.WriteText(512 + 240, 50, "Level: ");
TextureFont.WriteText(512 + 420, 50, (level + 1).ToString());
TextureFont.WriteText(512 + 240, 90, "Score: ");
TextureFont.WriteText(512 + 420, 90, score.ToString());
TextureFont.WriteText(512 + 240, 130, "Lines: ");
TextureFont.WriteText(512 + 420, 130, lines.ToString());
TextureFont.WriteText(512 + 240, 170, "Highscore: ");
TextureFont.WriteText(512 + 420, 170, highscore.ToString());
});
} // TestScoreboard()
#endregion
#region TestFallingBlockAndLineKill
public static void TestFallingBlockAndLineKill()
{
// Just use the game itself to test the falling blocks.
// This was previously done differently, but due the changes made
// over the development time it was easier to get rid of this
// unit test and implement everything directly into the game.
StartGame();
} // TestFallingBlockAndLineKill()
#endregion
#endif
#endregion
} // class TetrisGame
} // namespace XnaTetris