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.

OK, I added a loading screen to my game, and in order for the game able to update and show a loading screen and load stuff in the background I came to the concludsion that I needed to host the loading function on a thread. When I did this, the loading times doubled, if not tripled in length, can anyone thing why this is so?

I set the thread to the highest priority but that hasn't seemed to help (note, this is my first time ever using threads):

        gameScreen = new GameScreen(content);

        loadingThread = new Thread(gameScreen.LoadContent);
        loadingThread.Priority = ThreadPriority.Highest;
        loadingThread.Start();

        gameScreen.ScreenState = ScreenState.Loading;

EDIT:

Loading Screen Class:

    Thread loadingThread;

    Screen gameScreen;

    public LoadingScreen(ContentManager content)
        : base(content)
    {
    }

    public override void LoadContent()
    {
        Texture2D background = content.Load<Texture2D>("Screens\\Loading\\Textures\\background");
        Texture2D dropshadow = content.Load<Texture2D>("Screens\\Loading\\Textures\\dropshadow");
        Texture2D logo = content.Load<Texture2D>("Screens\\Loading\\Textures\\logo");

        Sprite background_sprite = new Sprite(background, new Vector2(0, 0));

        int tiles = Variables.SCREEN_WIDTH / dropshadow.Width;

        Sprite dropshadow_sprite_top = new Sprite(dropshadow, new Vector2(0, 0));
        dropshadow_sprite_top.ScaleY(65);
        tiles = Variables.SCREEN_WIDTH / dropshadow_sprite_top.ScaledWidth + (Variables.SCREEN_WIDTH % dropshadow_sprite_top.ScaledWidth == 0 ? 0 : 1);
        dropshadow_sprite_top.TileX(tiles);

        Sprite dropshadow_sprite_bottom = new Sprite(dropshadow, new Vector2(0, Variables.SCREEN_HEIGHT - dropshadow.Height));
        dropshadow_sprite_bottom.ScaleY(65);
        dropshadow_sprite_bottom.Position = new Vector2(0, Variables.SCREEN_HEIGHT - dropshadow_sprite_bottom.ScaledHeight);
        dropshadow_sprite_bottom.TileX(tiles);
        dropshadow_sprite_bottom.FlipY();

        Sprite logo_sprite = new Sprite(logo, new Vector2(Variables.SCREEN_WIDTH - logo.Width, Variables.SCREEN_HEIGHT - logo.Height));
        logo_sprite.ScaleX(45);

        logo_sprite.Position = new Vector2(Variables.SCREEN_WIDTH - logo_sprite.ScaledWidth - 10, Variables.SCREEN_HEIGHT - logo_sprite.ScaledHeight - 10);

        sprites.Add(background_sprite);
        sprites.Add(dropshadow_sprite_top);
        sprites.Add(dropshadow_sprite_bottom);
        sprites.Add(logo_sprite);

        gameScreen = new GameScreen(content);

        loadingThread = new Thread(gameScreen.LoadContent);
        loadingThread.Priority = ThreadPriority.Highest;
        loadingThread.Start();

        gameScreen.ScreenState = ScreenState.Loading;
    }

    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
    } 

    public override Screen RequestedScreen()
    {
        if (gameScreen.ScreenState == ScreenState.Idle)
        {
            return gameScreen;
        }

        return this;
    }

    public override void Draw(SpriteBatch spriteBatch)
    {
        base.Draw(spriteBatch);
    }

...

In the GameScreen class:

    public override void LoadContent()
    {
        world.LoadContent(content);
        playerRender.LoadContent(content);
        skyRenderer.LoadContent(world, content);

        screenState = ScreenState.Idle;
    }

...

In the game1.cs

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);

        Variables.TILE_ALAIS = new GUI.SpriteSheet(Content.Load<Texture2D>("Textures\\Sheets\\terrain"), new Vector2(16, 16));
        Variables.BLOCKSELECTOR_TEXTURE = Content.Load<Texture2D>("Textures\\Sprites\\blockselector");
        OutputBuffer.BUFFER_FONT = Content.Load<SpriteFont>("Fonts\\statusfont");
        Variables.STATUS_FONT = OutputBuffer.BUFFER_FONT;

        screen = new MainScreen(Content);
        screen.LoadContent();

        frameRateCounter.LoadContent(Content);
    }

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


        if (screen != screen.RequestedScreen())
        {
            screen = screen.RequestedScreen();
            screen.LoadContent();
        }

        screen.Update(gameTime);
        frameRateCounter.Update(gameTime);
        ProcessInput();

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

        spriteBatch.Begin();
        screen.Draw(spriteBatch);
        //frameRateCounter.Draw(gameTime, spriteBatch);
        spriteBatch.End();

        base.Draw(gameTime);
    }

The requested screen function asks the current screen if it should change. The MainScreen.RequestedScreen() just returns LoadingScreen, when then if it has finished building the world and etc. It returns a instance of the game screen class whoose LoadContent method has been threaded.

Any ideas?

share|improve this question
    
For one thing, you don't have to do that if you want the loading screen updating, although if you need it to update smoothly, then sure. That is, if your loading occurs in small enough chunks, your screen will still update at some fair rate. Perhaps only applicable if you want a loading bar on a static background, with no animation as such. Re your threads, you're creating a loading thread just once, yes? –  Nick Wiggill Jan 25 '12 at 10:37
1  
I think you should provide more detail about what your main thread does during this time, and what the load thread actually does -- particularly if they are accesses anything shared that you might be locking. –  Josh Petrie Jan 25 '12 at 16:04
add comment

closed as too localized by Tetrad Jan 26 '12 at 7:17

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.

4 Answers

If the loading screen is rendering, make sure it is not also locking resources which the loading thread needs to use.

Easy way to tell if the loading screen is chewing up resources due to rendering too often - put a 1000ms Sleep in the render loop of the loading screen, and see if your loading performance comes back to normal.

share|improve this answer
    
+1 This is often the problem in XNA in my experience, loading graphics content through the pipeline will actually lock the graphics device. So if your loading screen is rendering as fast as possible, the background thread will have to wait to acquire that lock and it will all be very slow. –  Oskar Duveborn Jan 25 '12 at 17:41
    
Yes, in regards to your question the loading screen does render, I am plaining to add a progress bar, I'll try to turn v-sych on in the loading screen. Nope, that didn't seem to help. –  Darestium Jan 25 '12 at 22:04
add comment

From the code given there is no definite way of knowing what goes wrong, so this is just a guess and a general piece of advice.

You must make sure that your loading screen use as few resources as possible, it should be a simple rendering task that is run as infrequent as possible. The loading screen thread should itself limit the update rate. Depending on the content it will probably take somewhere between 10 and 30 frames per second to make fluid animation, but typically fluid loading screens ain't that important, so you might go as low as 1 frame per second.

Of course you should also make sure that your threads as far as possible do not need a lock on the same resource, though if they do, the above will greatly limit the damage.

share|improve this answer
    
I just added some extra code in the post. –  Darestium Jan 25 '12 at 21:57
    
I'm not very good at reading OO spaghetti, but all I see is 8 overrides and no timing control. What is keeping all this together? –  eBusiness Jan 25 '12 at 23:26
    
hehe, OK, I fixed my problem (it had to do with me loading the content twice) and I really have no idea what you would call spaghetti code but I am sure mine is worse then that. Any ideas how I can not produce spaghetti code :D –  Darestium Jan 26 '12 at 0:13
    
Stop overriding stuff for starters. I wonder, is that how XNA works? Do you really have to write a bunch of overrides? As much as overriding can be a useful tool, it is under normal circumstances not an essential one, and use where not justified will usually lead to less readable code. –  eBusiness Jan 26 '12 at 10:45
add comment
up vote 1 down vote accepted

OK, I fixed my problem - it had to do with me loading the content twice.

share|improve this answer
add comment

Are you using a DrawableGameComponent? If so, when you add the Component, Initialize and LoadContent get called by the framework.

What I did was have a method that created a component and added it inside a thread.

public void InitAndLoadComponent()
{
    gameScreen = new GameScreen(this,content);
    Components.Add(gameScreen);
}

Share more of your code and perhaps I can help more.

share|improve this answer
add comment

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