Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm creating a "simple" Tetris style game for a beginner project. My problem is when I added the background (tiled look consisting of a bunch of squares), the game got very slow. It has to have something to do with the way I am drawing the background but I am not sure of any way to improve it. I thought about using an image as the background, but I really want to be able to have the gameboard size customizable. Here is my code:

GameBoard

public class GameBoard
{
    private List<Square> Squares;

    public GameBoard()
    {
        Squares = new List<Square>();

        BuildBoard();
    }

    private void BuildBoard()
    {
        for (int x = 0; x < 40; x++)
        {
            for (int y = 0; y < 24; y++)
            {
                Squares.Add(new Square(new Point(x, y), new Color(50, 50, 0)));
            }
        }
    }

    public void Draw(SpriteBatch batch)
    {
        foreach (Square square in Squares)
            square.Draw(batch);
    }
}

Square

public class Square
{
    private const int HEIGHT = 20;
    private const int WIDTH = 20;

    public Point Position;
    public Rectangle Rectangle;
    public Color Color;

    public Square(Point Location, Color color)
    {
        Position = new Point(Location.X * 20, Location.Y * 20);
        Color = color;
        Rectangle = new Rectangle(Position.X, Position.Y, WIDTH, HEIGHT);
    }

    public void Move(int xMove, int yMove)
    {
        Position.X += xMove;
        Position.Y += yMove;
        Rectangle = new Rectangle(Position.X, Position.Y, WIDTH, HEIGHT);
    }

    public void MoveRight()
    {
        Position.X += 20;
        Rectangle = new Rectangle(Position.X, Position.Y, WIDTH, HEIGHT);
    }

    public void MoveLeft()
    {
        Position.X -= 20;
        Rectangle = new Rectangle(Position.X, Position.Y, WIDTH, HEIGHT);
    }

    public void MoveDown()
    {
        Position.Y += 20;
        Rectangle = new Rectangle(Position.X, Position.Y, WIDTH, HEIGHT);
    }

    public void Draw(SpriteBatch batch)
    {
        Texture2D squareTexture = new Texture2D(batch.GraphicsDevice, 1, 1);
        Texture2D borderTexture = new Texture2D(batch.GraphicsDevice, 1, 1);

        squareTexture.SetData(new[] { Color });
        borderTexture.SetData(new[] { Color.Black });

        batch.Draw(squareTexture, Rectangle, Color);
        batch.Draw(borderTexture, new Rectangle(Position.X, Position.Y, 2, HEIGHT), Color);
        batch.Draw(borderTexture, new Rectangle(Position.X, Position.Y, WIDTH, 2), Color);
        batch.Draw(borderTexture, new Rectangle(Position.X + 18, Position.Y, 2, HEIGHT), Color);
        batch.Draw(borderTexture, new Rectangle(Position.X, Position.Y + 18, WIDTH, 2), Color);
    }
}

Game1.cs

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    GameBoard board;
    Shape shape;

    int downTicker;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
        this.TargetElapsedTime = TimeSpan.FromMilliseconds(50);
        downTicker = 0;
    }

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        shape = new Shape(Color.Blue);
        board = new GameBoard();
    }

    protected override void UnloadContent()
    {
        spriteBatch.Dispose();
    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();
        downTicker++;

        Debug.WriteLine(TargetElapsedTime.Milliseconds);
        if (downTicker == 10)
        {
            //shape.MoveDown();
            downTicker = 0;
        }

        if (Keyboard.GetState().IsKeyDown(Keys.Right))
            shape.MoveRight();
        if (Keyboard.GetState().IsKeyDown(Keys.Left))
            shape.MoveLeft();
        if (Keyboard.GetState().IsKeyDown(Keys.Down))
            shape.MoveDown();

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);
        spriteBatch.Begin();
        board.Draw(spriteBatch);
        shape.Draw(spriteBatch);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}
share|improve this question

closed as too localized by Byte56, Trevor Powell, John McDonald, ashes999, Josh Petrie Jan 25 '13 at 16:04

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.If this question can be reworded to fit the rules in the help center, please edit the question.

2  
I think this is a bit too localized for the site. I also think John has given you the answer you need. I'm voting to close. –  Byte56 Jan 24 '13 at 22:24
    
Just use a background. CS2 is free now officially (from Adobe), so you should have no excuse for not creating something that's "good enough." –  ashes999 Jan 24 '13 at 22:28
    
@Byte56 I'm not sure I understand what you mean by "too localized" Is there another stack exchange site that would be better suited for this question? –  Nick Jan 24 '13 at 23:33
    
@Nick Too localized because it's unlikely that any future users would find it useful, since it's particular to your code. There's not another stack exchange site to ask on, but the FAQ lists a few sites where you can ask. –  Byte56 Jan 24 '13 at 23:41
    
@Byte56 gotcha, I'll try to keep that in mind in the future. Thanks –  Nick Jan 24 '13 at 23:47

2 Answers 2

up vote 6 down vote accepted

I believe the issue is that you're creating a pair of textures, for each draw, for each square:

Texture2D squareTexture = new Texture2D(batch.GraphicsDevice, 1, 1);
Texture2D borderTexture = new Texture2D(batch.GraphicsDevice, 1, 1);

squareTexture.SetData(new[] { Color });
borderTexture.SetData(new[] { Color.Black });

If you create these outside of the draw loop and keep them for the entire lifespan of the Square, your performance should improve greatly.

share|improve this answer
    
Is creating textures really that slow? Really? –  ashes999 Jan 24 '13 at 22:27
1  
new Texture2D + SetData twice, for each of 920 squares, each draw? Quite likely –  John McDonald Jan 24 '13 at 22:29
    
You shouldn't create a new texture for every square as you can easily just reuse the across all Square instances. You don't even need a seperate squareTexture and borderTexture, just make a 1x1 texture with Color.White pixel color and draw the texture with whatever color with Spritebatch.Draw(Texture2D, Rectangle, Color); –  Jaakko Lipsanen Jan 24 '13 at 23:28
    
This was the ticket. It seems pretty obvious now... Thank you! –  Nick Jan 24 '13 at 23:45

To extend on John McDonald's answer (i don't have comment permissions sorry). You should be able to ceate two textures in your GameBoard and pass them into each square that you generate, instead of the color property

Outside of the question but useful anyway:

In your Square constructor change the line:

Position = new Point(Location.X * 20, Location.Y * 20);

To:

Position = new Point(Location.X * WIDTH, Location.Y * HEIGHT);
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.