All pastes #805720 Raw Edit

Someone

public text v1 · immutable
·published 2007-12-04 16:41 UTC
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);
        }
    }
}