topical media & game development
game-xna-intro-XnaTetris-TetrisGame.cs / cs
// 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
{
<summary>
This is the main type for your game
</summary>
public class TetrisGame : BaseGame
{
#region Variables
<summary>
Textures for the background, the box and the blocks.
</summary>
Texture2D backgroundTexture, blockTexture,
backgroundSmallBoxTexture, backgroundBigBoxTexture;
<summary>
Block and background as sprite helpers.
</summary>
SpriteHelper block, background, backgroundSmallBox, backgroundBigBox;
<summary>
TetrisGrid helper, handles all the graphical aspects!
</summary>
TetrisGrid tetrisGrid;
<summary>
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.
</summary>
int level = 0;
<summary>
Highscore
</summary>
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
<summary>
Load all graphics content (just our background texture).
Use this method to make sure a device reset event is handled correctly.
</summary>
<param name="loadAllContent">Load everything?
</param>
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
// Load all our content
backgroundTexture = content.Load<Texture2D>("SpaceBackground");
blockTexture = content.Load<Texture2D>("Block");
backgroundSmallBoxTexture = content.Load<Texture2D>("BackgroundSmallBox");
backgroundBigBoxTexture = content.Load<Texture2D>("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
<summary>
Remember current game time and when we pressed left, right
or down the last time to allow movement after waiting for a key
timeout.
</summary>
int elapsedGameMs = 0;
int pressedLeftMs = 0;
int pressedRightMs = 0;
int pressedDownMs = 0;
<summary>
Allows the game to run logic such as updating the world,
checking for collisions, gathering input and playing audio.
</summary>
<param name="
gameTime">Provides a snapshot of timing values.
</param>
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
<summary>
This is called when the game should draw itself.
</summary>
<param name="
gameTime">Provides a snapshot of timing values.
</param>
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
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.