rendered paste body//#define DEBUGGRAPHICS
using System;
using System.Collections.Generic;
using System.Text;
using FDS.Fathom;
using Microsoft.Xna.Framework;
using FDS.Fathom.Graphics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Vectris
{
public enum GridState
{
Play,
Explosion,
Moving,
Lose
}
public class GameGrid : DrawableFathomComponent
{
private string[] messages = new string[] {
"Damn!",
"Nice!",
"Awesome!",
"Rad!",
"Whoa!!",
"Crazy!!",
"WTF!!!"
};
private int rows = 9;
private int columns = 19;
private float gridWidth;
private float gridHeight;
private float gridX;
private float gridY;
private float blockWidth;
private float blockHeight;
private float timeToDrop = 1;
private float timeToDropElapsed = 0;
private float moveSideTime = 0.150f;
private float rotateTime = 0.150f;
private float explosionTime = 0.250f;
private float movingTime = 0.250f;
private float moveSideElapsed;
private float rotateElapsed;
private float explosionElapsed;
private float movingElapsed;
private float particleCount = 1;
private VectorParticleSystem particleSys;
private ExplosionParticleSystem explosionParticles;
private ExplosionSmokeParticleSystem explosionSmokeParticles;
private LineBatch lineBatch;
private BaseShape currentShape;
private List<Block> blocks;
private List<List<Block>> rowsToBreak;
private List<List<Block>> rowsToMove;
private GridState gridState;
private List<BreakMessage> breakMessages;
public List<Block> Blocks { get { return blocks; } }
public BaseShape CurrentShape
{
get { return currentShape; }
set { currentShape = value; }
}
public float BlockWidth { get { return blockWidth; } }
public float BlockHeight { get { return blockHeight; } }
public float X { get { return gridX; } }
public float Y { get { return gridY; } }
public float Width { get { return gridWidth; } }
public float Height { get { return gridHeight; } }
public GameGrid(Game game)
: base(game)
{
}
private SpriteFont messageFont;
protected override void LoadContent()
{
base.LoadContent();
gridState = GridState.Play;
rowsToMove = new List<List<Block>>();
blocks = new List<Block>();
breakMessages = new List<BreakMessage>();
messageFont = Engine.Content.Load<SpriteFont>("Content/Fonts/MessageFont");
moveSideElapsed = moveSideTime;
rotateElapsed = rotateTime;
explosionElapsed = explosionTime;
movingElapsed = movingTime;
blockWidth = 38;
blockHeight = 38;
gridX = Engine.Width * 0.30f;
gridY = Engine.Height * 0.025f;
gridWidth = blockWidth * rows;
gridHeight = blockHeight * columns;
explosionParticles = new ExplosionParticleSystem(Game, 10);
explosionSmokeParticles = new ExplosionSmokeParticleSystem(Game, 10);
lineBatch = new LineBatch(GraphicsDevice);
particleSys = new VectorParticleSystem(Game);
Game.Components.Add(particleSys);
Game.Components.Add(explosionParticles);
Game.Components.Add(explosionSmokeParticles);
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; timeToDropElapsed += elapsed;
if (gridState != GridState.Lose && timeToDropElapsed >= timeToDrop)
{
timeToDropElapsed = 0;
if (CheckCollision(CurrentShape, new Vector3(0, BlockHeight, 0), Quaternion.Identity))
{
SnapToGrid(CurrentShape, new Vector3(0, BlockHeight, 0));
NewShape();
CheckLines();
if (CheckCollision(CurrentShape, Vector3.Zero, Quaternion.Identity))
{
gridState = GridState.Lose;
}
}
else
{
CurrentShape.Position += new Vector3(0, BlockHeight, 0);
}
}
List<BreakMessage> toRemove = new List<BreakMessage>();
for (int i = 0; i < breakMessages.Count; i++)
{
breakMessages[i].LifeTime -= elapsed;
if (breakMessages[i].LifeTime <= 0)
{
toRemove.Add(breakMessages[i]);
}
}
for (int i = 0; i < toRemove.Count; i++)
{
breakMessages.Remove(toRemove[i]);
}
if (gridState == GridState.Lose)
{
UpdateLoseState(gameTime);
}
else if (gridState == GridState.Explosion)
{
UpdateExplosionState(gameTime);
}
else if (gridState == GridState.Moving)
{
UpdateMovingState(gameTime);
}
else
{
UpdateGameplayState(gameTime);
}
}
private void UpdateExplosionState(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
for (int i = 0; i < rowsToBreak.Count; i++)
{
for (int a = 0; a < rowsToBreak[i].Count; a++)
{
float minX = rowsToBreak[i][a].Vertices[0].X;
float maxX = rowsToBreak[i][a].Vertices[2].X;
float minY = rowsToBreak[i][a].Vertices[1].Y;
float maxY = rowsToBreak[i][a].Vertices[3].Y;
Vector2 explosionOrigin =
new Vector2(minX + ((maxX - minX) / 2),
minY + ((maxY - minY) / 2));
explosionParticles.AddParticles(explosionOrigin);
explosionSmokeParticles.AddParticles(explosionOrigin);
for (int j = 0; j < particleCount; j++)
{
explosionOrigin =
new Vector2(Utility.RandomFloatMinMax(minX, maxX),
Utility.RandomFloatMinMax(minY, maxY));
float xSpeed = Utility.RandomMinMax(-100, 100);
float ySpeed = Utility.RandomMinMax(-100, 100);
float rotation = Utility.RandomFloatMinMax(0, MathHelper.Pi);
float lifeTime = Utility.RandomMinMax(1, 4);
float rotationSpeed = Utility.RandomFloatMinMax(0, MathHelper.Pi * 3);
VertexPositionColor[] vertices = new VertexPositionColor[] {
new VertexPositionColor(new Vector3(Utility.RandomMinMax(-3, -1), 0, 0), rowsToBreak[i][a].Color),
new VertexPositionColor(new Vector3(Utility.RandomMinMax(1, 3), 0, 0), rowsToBreak[i][a].Color)
};
particleSys.Add(explosionOrigin, new Vector2(xSpeed, ySpeed), lifeTime, rotation, rotationSpeed, vertices);
}
Blocks.Remove(rowsToBreak[i][a]);
}
}
explosionElapsed -= elapsed;
if (explosionElapsed <= 0)
{
explosionElapsed = explosionTime;
gridState = GridState.Moving;
}
}
private void UpdateMovingState(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
for (int i = 0; i < rowsToMove.Count; i++)
{
for (int j = 0; j < rowsToMove[i].Count; j++)
{
for (int k = 0; k < rowsToMove[i][j].Vertices.Length; k++)
{
rowsToMove[i][j].Vertices[k] += new Vector2(0, blockHeight);
}
}
}
rowsToMove.Clear();
movingElapsed = movingTime;
gridState = GridState.Play;
}
private void UpdateGameplayState(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
moveSideElapsed += elapsed;
rotateElapsed += elapsed;
if (InputState.KeyboardKeyPressed(Keys.A) && moveSideElapsed > moveSideTime)
{
moveSideElapsed = 0;
if (!CheckCollision(CurrentShape, new Vector3(-BlockWidth, 0, 0), Quaternion.Identity))
{
CurrentShape.Position -= new Vector3(BlockWidth, 0, 0);
}
}
if (InputState.KeyboardKeyPressed(Keys.D) && moveSideElapsed > moveSideTime)
{
moveSideElapsed = 0;
if (!CheckCollision(CurrentShape, new Vector3(BlockWidth, 0, 0), Quaternion.Identity))
{
CurrentShape.Position += new Vector3(BlockWidth, 0, 0);
}
}
if (InputState.KeyboardKeyPressed(Keys.S))
{
timeToDropElapsed = 0;
if (moveSideElapsed > moveSideTime)
{
moveSideElapsed = 0;
if (CheckCollision(CurrentShape, new Vector3(0, BlockHeight, 0), Quaternion.Identity))
{
SnapToGrid(CurrentShape, new Vector3(0, BlockHeight, 0));
NewShape();
CheckLines();
if (CheckCollision(CurrentShape, Vector3.Zero, Quaternion.Identity))
{
gridState = GridState.Lose;
}
}
else
{
CurrentShape.Position += new Vector3(0, BlockHeight, 0);
}
}
}
if (InputState.KeyboardKeyJustPressed(Keys.Q) && rotateElapsed > rotateTime)
{
rotateElapsed = 0;
if (!CheckCollision(CurrentShape, Vector3.Zero, Quaternion.CreateFromYawPitchRoll(0, 0, -MathHelper.PiOver2)))
{
CurrentShape.Rotation *= Quaternion.CreateFromYawPitchRoll(0, 0, -MathHelper.PiOver2);
}
}
if (InputState.KeyboardKeyJustPressed(Keys.E) && rotateElapsed > rotateTime)
{
rotateElapsed = 0;
if (!CheckCollision(CurrentShape, Vector3.Zero, Quaternion.CreateFromYawPitchRoll(0, 0, MathHelper.PiOver2)))
{
CurrentShape.Rotation *= Quaternion.CreateFromYawPitchRoll(0, 0, MathHelper.PiOver2);
}
}
if (InputState.KeyboardKeyJustPressed(Keys.Space))
{
SnapToGrid(CurrentShape, new Vector3(0, gridY + gridHeight, 0));
NewShape();
CheckLines();
if (CheckCollision(CurrentShape, Vector3.Zero, Quaternion.Identity))
{
gridState = GridState.Lose;
}
}
if (CurrentShape != null)
{
CurrentShape.Update(gameTime);
}
}
private void UpdateLoseState(GameTime gameTime)
{
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
int count = Blocks.Count;
for (int i = 0; i < count; i++)
{
Block b = Blocks[i];
b.Color = Utility.RandomColor();
Blocks[i] = b;
}
if (Utility.RandomDouble() > 0.96)
{
explosionParticles.AddParticles(new Vector2(Utility.Random(Engine.Width), Utility.Random(Engine.Height)));
}
}
public override void Draw(GameTime gameTime)
{
base.Draw(gameTime);
Matrix proj = Matrix.CreateOrthographicOffCenter(0, Engine.Width, Engine.Height, 0, 0, 1);
Renderer.PrimitiveBatch.BasicEffect.Projection = proj;
Renderer.PrimitiveBatch.BasicEffect.World = Matrix.Identity;
Renderer.PrimitiveBatch.Begin(PrimitiveType.LineList);
for (int x = 0; x < rows; x++)
{
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + x * blockWidth, gridY), new Color(0x10, 0x10, 0x10));
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + x * blockWidth, gridY + gridHeight), new Color(0x10, 0x10, 0x10));
}
for (int y = 0; y < columns; y++)
{
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX, gridY + y * blockHeight), new Color(0x10, 0x10, 0x10));
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + gridWidth, gridY + y * blockHeight), new Color(0x10, 0x10, 0x10));
}
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX, gridY), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX, gridY + gridHeight), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX, gridY), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + gridWidth, gridY), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + gridWidth, gridY), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + gridWidth, gridY + gridHeight), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX, gridY + gridHeight), Color.Blue);
Renderer.PrimitiveBatch.AddVertex(new Vector2(gridX + gridWidth, gridY + gridHeight), Color.Blue);
Renderer.PrimitiveBatch.End();
Renderer.PrimitiveBatch.Begin(PrimitiveType.LineList);
if (CurrentShape != null && CurrentShape.Blocks != null)
{
Renderer.PrimitiveBatch.BasicEffect.World = CurrentShape.World;
Renderer.PrimitiveBatch.BasicEffect.CommitChanges();
for (int i = 0; i < CurrentShape.Blocks.Length; i++)
{
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[0], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[1], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[0], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[2], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[2], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[3], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[1], CurrentShape.Blocks[i].Color);
Renderer.PrimitiveBatch.AddVertex(CurrentShape.Blocks[i].Vertices[3], CurrentShape.Blocks[i].Color);
}
}
Renderer.PrimitiveBatch.End();
Renderer.PrimitiveBatch.Begin(PrimitiveType.LineList);
for (int i = 0; i < Blocks.Count; i++)
{
Block block = Blocks[i];
Renderer.PrimitiveBatch.BasicEffect.World = Matrix.Identity;
Renderer.PrimitiveBatch.BasicEffect.CommitChanges();
Renderer.PrimitiveBatch.AddVertex(block.Vertices[0], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[1], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[0], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[2], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[2], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[3], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[1], block.Color);
Renderer.PrimitiveBatch.AddVertex(block.Vertices[3], block.Color);
}
Renderer.PrimitiveBatch.End();
Renderer.SpriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.None);
for (int i = 0; i < breakMessages.Count; i++)
{
Vector2 position = new Vector2(breakMessages[i].Position.X, breakMessages[i].Position.Y) +
new Vector2(Utility.RandomFloatMinMax(1, 3), Utility.RandomFloatMinMax(1, 3));
Renderer.SpriteBatch.DrawString(messageFont, breakMessages[i].Message,
position, Utility.RandomColor());
}
Renderer.SpriteBatch.End();
#if DEBUGGRAPHICS
Renderer.PrimitiveBatch.BasicEffect.World = Matrix.Identity;
Renderer.PrimitiveBatch.Begin(PrimitiveType.LineList);
GraphicsDevice.RenderState.PointSize = 4f;
for (int i = 0; i < Blocks.Count; i++)
{
Block block = Blocks[i];
OrientedBoundingBox bb = block.BoundingBox;
VertexPositionColor[] verts = new VertexPositionColor[] {
new VertexPositionColor(new Vector3(new Vector2(bb.Min.X, bb.Min.Y), 0), Color.White),
new VertexPositionColor(new Vector3(new Vector2(bb.Max.X, bb.Max.Y), 0), Color.White)
};
GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList, verts, 0, 2);
}
for (int i = 0; i < columns; i++)
{
float row = Y + (blockHeight * i) + (blockHeight / 2);
Vector2 start = new Vector2(X, row);
Vector2 end = new Vector2(X + Width, row);
OrientedBoundingBox bb = new OrientedBoundingBox(new Vector3(start, 0), new Vector3(end, 0));
Renderer.PrimitiveBatch.AddVertex(start, Color.White);
Renderer.PrimitiveBatch.AddVertex(end, Color.White);
}
GraphicsDevice.RenderState.PointSize = 1f;
Renderer.PrimitiveBatch.End();
#endif
}
public void AddShapeToGrid()
{
if (CurrentShape != null)
{
for (int i = 0; i < CurrentShape.Blocks.Length; i++)
{
Block b = new Block();
b.Vertices = new Vector2[CurrentShape.Blocks.Length];
for (int a = 0; a < b.Vertices.Length; a++)
{
b.Vertices[a] = Vector2.Transform(CurrentShape.Blocks[i].Vertices[a], CurrentShape.World);
}
b.Visible = CurrentShape.Visible;
b.Color = CurrentShape.Blocks[i].Color;
Blocks.Add(b);
}
CurrentShape = null;
}
}
public void NewShape()
{
AddShapeToGrid();
BaseShape shape = null;
switch (Utility.Random(7))
{
case 0: shape = new LineShape(Game); break;
case 1: shape = new LShape(Game); break;
case 2: shape = new BackwardLShape(Game); break;
case 3: shape = new TShape(Game); break;
case 4: shape = new SShape(Game); break;
case 5: shape = new ZShape(Game); break;
default: shape = new BlockShape(Game); break;
}
shape.GameGrid = this;
shape.Position = shape.StartPosition;
shape.Initialize();
CurrentShape = shape;
}
private void CheckLines()
{
rowsToBreak = new List<List<Block>>();
particleSys.BasicEffect.Projection = Matrix.CreateOrthographicOffCenter(0, Engine.Width, Engine.Height, 0, 0, 1);
for (int i = columns - 1; i >= 0; i--)
{
float row = Y + (blockHeight * i) + (blockHeight / 2);
Vector3 start = new Vector3(X, row, 0);
Vector3 end = new Vector3(X + Width, row, 0);
List<Block> blocks = new List<Block>();
OrientedBoundingBox bb = new OrientedBoundingBox(start, end);
bb.Transforms = Matrix.Identity;
for (int a = 0; a < Blocks.Count; a++)
{
if (bb.Intersects(Blocks[a].BoundingBox))
{
blocks.Add(Blocks[a]);
}
}
if (blocks.Count == rows)
{
BreakMessage message = new BreakMessage();
message.Message = messages[Utility.Random(messages.Length)];
message.LifeTime = 1;
message.Position = new Vector3(Utility.RandomFloatMinMax(start.X, end.X), Utility.RandomFloatMinMax(start.Y - blockHeight, end.Y - blockHeight), 0);
breakMessages.Add(message);
rowsToBreak.Add(blocks);
for (int j = i - 1; j >= 0; j--)
{
rowsToMove.Add(new List<Block>());
row = Y + (blockHeight * j) + (blockHeight / 2);
start = new Vector3(X, row, 0);
end = new Vector3(X + Width, row, 0);
bb = new OrientedBoundingBox(start, end);
bb.Transforms = Matrix.Identity;
for (int k = 0; k < Blocks.Count; k++)
{
Block b = Blocks[k];
if (bb.Intersects(b.BoundingBox))
{
rowsToMove[rowsToMove.Count - 1].Add(b);
}
}
}
}
}
if (rowsToBreak.Count > 0)
{
gridState = GridState.Explosion;
}
}
public bool CheckCollision(BaseShape moveShape, Vector3 deltaMovement, Quaternion deltaRotation)
{
bool collision = false;
List<Block> collisionObjects = Blocks;
Vector3 position = moveShape.Position + deltaMovement;
Quaternion rotation = moveShape.Rotation * deltaRotation;
Matrix world = Matrix.CreateScale(moveShape.Scale) *
Matrix.CreateFromQuaternion(rotation) *
Matrix.CreateTranslation(position);
if (collisionObjects == null)
{
return false;
}
for (int k = 0; k < moveShape.Blocks.Length && !collision; k++)
{
for (int i = 0; i < moveShape.Blocks[k].Vertices.Length && !collision; i++)
{
Vector2 vector = Vector2.Transform(moveShape.Blocks[k].Vertices[i], world);
if (vector.X <= X - 1 || vector.X >= X + Width + 1 ||
vector.Y <= Y - 1 || vector.Y >= Y + Height + 1)
{
collision = true;
}
}
}
for (int i = 0; i < collisionObjects.Count && !collision; i++)
{
Block blockA = collisionObjects[i];
if (!blockA.Visible)
{
continue;
}
OrientedBoundingBox bba = blockA.BoundingBox;
bba.Transforms = Matrix.Identity;
for (int k = 0; k < moveShape.Blocks.Length && !collision; k++)
{
Block blockB = moveShape.Blocks[k];
if (!blockB.Visible)
{
continue;
}
OrientedBoundingBox bbb = blockB.BoundingBox;
bbb.Transforms = world;
collision = bba.Intersects(bbb);
}
}
return collision;
}
internal void SnapToGrid(BaseShape shape, Vector3 collisionDelta)
{
int y = -1;
shape.Position += collisionDelta;
while (CheckCollision(shape, new Vector3(0, y, 0), Quaternion.Identity))
{
y--;
}
shape.Position += new Vector3(0, y, 0);
float delta = (shape.Position.Y - shape.StartPosition.Y) % blockHeight;
shape.Position += new Vector3(0, -delta, 0);
}
}
}