[SOLVED] Texture loading during splash screen display

Hello,

I would like to give some feedback to the player between clicking the executable of the game and the game actually appearing. Since there are loads of textures to load (takes around 10 - 15 seconds as of now), the player is currently waiting too long in my opinion.

The obvious solution would be to display a splash screen and load the textures (and maybe other assets) in the background. What would be the best option to do so? Can I even use the GraphicsDevice within a background thread? So far, I get a System.InvalidOperationException.

Do you have any suggestions on how to best approach this?

How about loading from Update with a game state and not from LoadContent methods ^_^y

        GameState _GameState        = GameState.SplashScreen;
        int       _LoadingPercent   = 1;
        string    _LoadingLabel     = "";

        /// <summary>
        /// MAIN UPDATE
        /// </summary>       
        protected override void Update(GameTime gameTime)
        {

            switch (_GameState)
            {

                case GameState.SplashScreen:
                    {
                        if ( LoadingRoutine() == 1) _GameState = GameState.MainMenu;
                        break;
                    }

                case GameState.MainMenu:
                    {
                        int mOptionResult = MainMenuRoutine();
                        //
                        if (mOptionResult == 1) _GameState = GameState.Playing;
                        if (mOptionResult == 2) _GameState = GameState.Option;
                        if (mOptionResult == 3) _GameState = GameState.Exit;
                        //
                        break;
                    }

                case GameState.Option:
                    {
                        if (OptionRoutine() == 1) _GameState = GameState.MainMenu;
                        break;
                    }

                case GameState.Playing:
                    {
                        if (PlayingRoutine() == 1) _GameState = GameState.MainMenu;
                        break;
                    }

                case GameState.Exit:
                    {
                        QuitRoutine(); break;
                    }
            }
            

            base.Update(gameTime);
        }

      
        /// <summary>
        /// Loading routine
        /// </summary>
        /// <returns></returns>
        private int LoadingRoutine()
        {

            if (_LoadingPercent == 1)
            {
                // Load some of your content here      

                _LoadingLabel   = "Loading 10%";
                _LoadingPercent = 10;
                return 0;
            }
            else if (_LoadingPercent == 10)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 20%";
                _LoadingPercent = 20;
                return 0;                
            }
            else if (_LoadingPercent == 20)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 30%";
                _LoadingPercent = 30;
                return 0;
            }
            else if (_LoadingPercent == 30)
            {
                // Load some of your content here
                
                _LoadingLabel   = "Loading 40%";
                _LoadingPercent = 40;
                return 0;
            }
            else if (_LoadingPercent == 40)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 50%";
                _LoadingPercent = 50;
                return 0;
            }
            else if (_LoadingPercent == 50)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 60%";
                _LoadingPercent = 60;
                return 0;
            }
            else if (_LoadingPercent == 60)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 70%";
                _LoadingPercent = 70;
                return 0;
            }
            else if (_LoadingPercent == 70)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 80%";
                _LoadingPercent = 80;
                return 0;
            }
            else if (_LoadingPercent == 80)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 90%";
                _LoadingPercent = 90;
                return 0;
            }
            else if (_LoadingPercent == 90)
            {
                // Load some of your content here

                _LoadingLabel   = "Loading 100%";
                _LoadingPercent = 100;
                return 0;
            }
            else if (_LoadingPercent == 100)
            {

                // Load some of your content here

            }

            return 1; // Done loading all assets from here
        }

You can just divide your total contents by 10, If you have 50 contents load 5 contents every 10% you can play with the percent on how you want it to display by 5% with 20 calls on the loading routine and divide all your contents by 5.

1 Like

Hi @DexterZ,

Thanks, that’s a good idea, I’ll check it out and will tell you how it worked out.

1 Like

"loading takes around 10 - 15 seconds as of now"

If you will use all the content in your scene or stage that’s fine, but if you have multiple stage and you load everything that’s inefficient IMO, the beauty of loading from Update via game state is that you can load only the content that will be used for the current scene or stage, just unload the previously loaded content before leaving the stage and revise the loading state to something like this.

    case GameState.LoadStageContent
           {
               if ( _Stage == 1 && LoadingRoutine1() == 1) _GameState = GameState.Playing;
               if ( _Stage == 2 && LoadingRoutine2() == 1) _GameState = GameState.Playing;
               if ( _Stage == 3 && LoadingRoutine3() == 1) _GameState = GameState.Playing;
               if ( _Stage == 4 && LoadingRoutine4() == 1) _GameState = GameState.Playing;
               if ( _Stage == 5 && LoadingRoutine5() == 1) _GameState = GameState.Playing;
               break;
           }

It works pretty well, thanks! The initial problem I had was that during heavy loading, the draw call can be skipped a few times. So, sometimes, it would show the splash screen and sometimes not. I now wait for the first draw call to start the loading process.

Only one thing remains: Somehow, the splash screen bleeds over into the main game (is displayed on top of my menu, in fact, for a split second), once I start displaying it. This seems to be caused by changing the window size between splash screen display and normal game display. Any suggestions?

instead of the giant if (loadingPercent == value) you can also use an IEnumerable and call “one step” every frame. In example, create a loading function:

IEnumerable<bool> loadingFuntion ()
{
    loadThing1();
    yield return true; 

    loadThing2();
    yield return true;

    loadThing3();
    yield return true;

    loadThing4();
    yield return true;

    loadThing5();
}

and then create an enumerator the first frame:

IEnumerator<bool> loadingCoroutine=loadingFuntion ().GetEnumerator();

and each frame, call

loadingCoroutine.MoveNext();

This will execute every step of the loadingFunction until it finds a “yield return”.

When MoveNext returns true, all the things in the loadingFunction will have been loaded and can skip to the next state in your game FSM.

Not pretty sure I will use that on my end, but yes there’s a lot of other implementations to do this, but I will not use collection’s IEnumarable for a simple task of operant conditioning, if or switch will suffice, much easier to code, read and understand and without using System.collection’s assembly.

Cheers ^_^Y

It works pretty well, thanks

Glad it works on your end, but your problem now is not related to displaying the loading percentage it’s more on how you implement your rendering routine for your drawables entities.

The initial problem I had was that during heavy loading, the draw call can be skipped a few times. So, sometimes, it would show the splash screen and sometimes not. I now wait for the first draw call to start the loading process.

I’m not sure whether you are using an engine or how you handle your drawable entities and how you implement your rendering parts. Assuming your just using plain MonoGame, when you say splash screen in my understanding this your background sprite image as shown below and the yellow label string is just a sprite font drawn using DrawString

This two are the only one I load first from my LoadingContent method:

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            //*>> Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //*>> Initial asset laoding

            // 1. Load your sprite font
            // 2. Load the Splash Background image
               

            //*>> Entities creation

            // 1. Create a sprite entity for your Backround sprite add it your collection of sprite
            // 2. Create Label entity using your sprite font just update the text of this 
            //    entity on your LoadingRoutine

        }

Only one thing remains: Somehow, the splash screen bleeds over into the main game (is displayed on top of my menu, in fact, for a split second), once I start displaying it. This seems to be caused by changing the window size between splash screen display and normal game display. Any suggestions?

Things to search for are rendering order of spritebatch and dept order, I’ll give u a hint there’s a SpriteSortMode order on spritebatch Begin method and there is LayerDepth overload on Draw call. A DepthOrder properties on your 2D entities would be nice and pass that as DepthOrder when Drawing.

Good idea, thanks, I was not aware of using enumerables this way.

Thanks again, I’ll check it out.

1 Like