-3
\$\begingroup\$

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);
    }
}
\$\endgroup\$
5
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – House
    Commented Jan 24, 2013 at 22:24
  • \$\begingroup\$ 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." \$\endgroup\$
    – ashes999
    Commented Jan 24, 2013 at 22:28
  • \$\begingroup\$ @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? \$\endgroup\$
    – Nick
    Commented Jan 24, 2013 at 23:33
  • \$\begingroup\$ @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. \$\endgroup\$
    – House
    Commented Jan 24, 2013 at 23:41
  • \$\begingroup\$ @Byte56 gotcha, I'll try to keep that in mind in the future. Thanks \$\endgroup\$
    – Nick
    Commented Jan 24, 2013 at 23:47

2 Answers 2

5
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ Is creating textures really that slow? Really? \$\endgroup\$
    – ashes999
    Commented Jan 24, 2013 at 22:27
  • 1
    \$\begingroup\$ new Texture2D + SetData twice, for each of 920 squares, each draw? Quite likely \$\endgroup\$ Commented Jan 24, 2013 at 22:29
  • \$\begingroup\$ 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); \$\endgroup\$
    – user9790
    Commented Jan 24, 2013 at 23:28
  • \$\begingroup\$ This was the ticket. It seems pretty obvious now... Thank you! \$\endgroup\$
    – Nick
    Commented Jan 24, 2013 at 23:45
0
\$\begingroup\$

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);
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .