2
votes

I am new to xna programming I need a little help here...

I build a 2D game, with static background In my current screen there are the background image, 4 large images on the left and i need to draw 16 small images (50x50 more or less) on the right

So this is my method to update the location of the 16 images on the left It is called only once by the Update

private void letterLblsLocation() 
    {
        if (letterLbls.Count != 0)
        {
            letterlblposition = new Vector2(0f, 0f);
            lblvector = new Vector2(0f, 0f);
            int col = 1;
            int lblsize = ScreenManager.GraphicsDevice.Viewport.Height / 15;
            for (int lbl = 0; lbl < letterLbls.Count; lbl++)
            {
                letterlblposition.X = ScreenManager.GraphicsDevice.Viewport.Width - (col * lblsize);
                letterlblposition.Y += 5 + lblsize;
                if (letterlblposition.Y > ScreenManager.GraphicsDevice.Viewport.Height - lblsize)
                {

                    col = col + 3;
                    letterlblposition.Y = 5 + lblsize;
                }
                recsOnRight.Add(new Rectangle((int)letterlblposition.X, (int)letterlblposition.Y, lblsize, lblsize));

                lblvector.X = recsOnRight[lbl].X + 5;
                lblvector.Y = recsOnRight[lbl].Y;
                letterLbls[lbl].Position = lblvector;
            }
        }
    }

This is my Update method

public override void Update(GameTime gameTime, bool otherScreenHasFocus,bool coveredByOtherScreen)
    {
        base.Update(gameTime, otherScreenHasFocus, false);



        // Gradually fade in or out depending on whether we are covered by the pause screen.
        if (coveredByOtherScreen)
            pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
        else
            pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

        if (IsActive)
        {
            if(questionNeeded)
            {
                ChooseWord();
                ChooseLettersOnRight();
                LabelsWithLetters();
                letterLblsLocation();
            }


        }
    }

And this is my Draw method

public override void Draw(GameTime gameTime)
    {

        spriteBatch.Begin();
        spriteBatch.Draw(background, new Rectangle(0, 0, ScreenManager.GraphicsDevice.Viewport.Width, ScreenManager.GraphicsDevice.Viewport.Height), Color.White);
        if (!questionNeeded)
        {
            for (int i = 0; i < 16; i++)
            {
                if (i < 4)
                {
                    Texture2D helpTexture = questionToDisplay.pic[i];
                    Rectangle helpRect = questionToDisplay.picRecs[i];
                    spriteBatch.Draw(helpTexture, helpRect, Color.White);
                }
                spriteBatch.Draw(labelSquare, recsOnRight[i], Color.White);
                }
            }

        spriteBatch.End();

Now my problem is that when I try to draw the 16 spritebatch on right the game becomes slow Is there a way to draw the 16 pics only once and redraw them only when the player clicks on one of them? Or a way to merge them in order to draw one large image and not 16 smaller? Or since I have a very little experience here, is there anything in this code that must change that makes the game runs slow when I draw this pics?

Thanks in advance

3
16 sprites should not even have a noticeable performance impact. Unless their resolution is extremely high. Are you sure the problem is caused by the draw code?Nico Schertler
Nico if I remove this for loop then the speed is back to normal again... so this is why is thought the problem was in the Draw, and as for the resolution the pic I try to load there is a simple blue square 100x100 pixelsnansyg21

3 Answers

2
votes

You are initializing your Graphics Device, SpriteBatch, SpriteFont and Textures during your Draw call. This is really bad.

Move these initializations into a LoadContent() function outside of your Draw function, and only initialize this once.

1
votes

Well I just removed the for loop from draw method then call spriteBatch.Draw 16 times, one for each sprite. Yes obviously this is not the best solution, yet it worked and the speed is up to normal again. Also I moved all the initializations out of Draw or Update as Jon mentioned before they do make the code faster.

0
votes

There is no places in your code snippet that can slow down application a lot. Try test Draw and Update methods using stopwatch. With fps 60 (by default) it should be no more than 1/60s in total. Try localize what exactly part slow down your game.

What about drawing images only once it's not correct. XNA is not WinForms, and Draw() calls each frame and you should clear screen and redraw all you want show to player. Game loop is simple: once call Initialize() and LoadContent, then in 'endless' cicle calls Update and Draw with some frequency and once call of the UnloadContent in the end.

If you want change image after click by them that you need to have two images - clicked and unclicked, and some variable to keep state of each of them. You check mouse/keybord input in Update method, change variable state and in the Draw method decide what image pass to spritebatch.Draw() call. Also if you have some complex scene that consists of a lot sprites you can draw it to render target only once after each update and then draw it like one solid texture ('lot' mean 100s, like in Terraria, but not 16 blue rects).