Search code examples
c#visual-studiomonogame

Moving Draw() code to a Class


I'm creating a game in monogame, and I've loaded tiles in my game inside the Draw() function like so:

protected override void Draw(GameTime gameTime)
{
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();   
        spriteBatch.Draw(danChar, charPosition, Color.White);

        // loop below loads the 'grass' tiles only

        // assuming gameworld size of 770x450
        for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
        {
            position = new Vector2(i, 392); // places incrementation into vector position
            spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
            if (i == 744)
            {
                i = i + 26; // fills last space between 744 and 770
                position = new Vector2(i, 392);
            }
            spriteBatch.Draw(gameTile, position, Color.White); 
        }

        // loop below loads the brick tiles only (ones without grass)

        spriteBatch.End();  // ends the spriteBatch call
        base.Draw(gameTime);
}

However I would prefer that this was a separate class rather than being placed directly into the draw function, however I'm not too sure how to do this and would appreciate any help given.

Thanks in advance!


Solution

  • If you just want to move the code as is to another class, create your class (e.g. something like GameWorld seems to appropriate for your code)

    public class GameWorld
    {
        // You may wish to move your gameTile definition into this class if it is the only
        // class that uses it, and handle the content loading for it in here.
        // e.g. if you're currently loading the texture in the LoadContent method in your game
        // class, create a LoadContent method here and pass in ContentManger as a parameter.
        // I've passed in the texture as a parameter to the Draw method in this example to
        // simplify as I'm not sure how you're managing your textures.
    
        public void Draw(SpriteBatch spriteBatch, GameTime gameTime, Texture2D gameTile)
        {
            // loop below loads the 'grass' tiles only
    
            // assuming gameworld size of 770x450
            for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
            {
                Vector2 position = new Vector2(i, 392); // places incrementation into vector position
                spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
                if (i == 744)
                {
                    i = i + 26; // fills last space between 744 and 770
                    position = new Vector2(i, 392);
                }
                spriteBatch.Draw(gameTile, position, Color.White); 
            }
    
            // loop below loads the brick tiles only (ones without grass)   
        }
    }
    

    Then the Draw method in your Game class would look like

    protected override void Draw(GameTime gameTime)
    {
            GraphicsDevice.Clear(Color.CornflowerBlue);
    
            spriteBatch.Begin();   
            spriteBatch.Draw(danChar, charPosition, Color.White);
    
            // Assuming you've created/loaded an instance of the GameWorld class
            // called gameWorld in Initialize/LoadContent
            gameWorld.Draw(spriteBatch, gameTime, gameTile);
    
            spriteBatch.End();  // ends the spriteBatch call
            base.Draw(gameTime);
    }
    

    Just make sure you're calling the Draw methods in the correct order. e.g. you want your player to appear above any background tiles.

    I believe the default SpriteSortMode is Deferred which draws in the order the calls are made (i.e. from the back to the front).

    You can specify a different SpriteSortMode in your call to spriteBatch.Begin() if you need to but for a simple game just move the Draw calls around.

    More info on SpriteSortMode at MSDN if needed.

    Similarly you can chain your Update, LoadContent methods into these classes if you wish, making sure to pass in anything you need as arguments.

    Update:

    To define gameWorld as an instance of the GameWorld class, you define it near the top of your game class, then typically initialize it in the Initialize method.

    So your game class will look something like

    public class MyGameName : Microsoft.Xna.Framework.Game
    {
        private SpriteBatch spriteBatch;
        // other variable declarations
    
        // Add a declaration for gameWorld
        private GameWorld gameWorld;
    
        protected override Initialize()
        {
            // Add the following line to initialize your gameWorld instance
            gameWorld = new GameWorld();
        }
    
        // other existing code - your LoadContent, Update, Draw methods etc.
    }