Skip to content
enbacode edited this page Oct 24, 2014 · 5 revisions

After installing and configuring Sharpex2D, it's time to get your first rectangle on screen. We could do that by overriding the Draw method of our game class, but I highly recommend using Sharpex2D's SceneManager straight from the beginning as it will ease handling game states as your code base grows.

Overview

What's a scene?

A scene, sometimes also called screen or state, is a part of your game flow that is logically and visually seperated from other scenes. Imagine the following:

  • Your game shall begin with an intro
  • After five seconds, the menu screen shall be shown
    • If the user hits 'start', the game begins
      • Pressing ESC will take the user back to the main menu
    • If the user hits 'options', the options menu shall be shown
    • If the user hits 'exit', menu screen will be closed
  • Credits are shown
  • After credits finished or user hits any key, your dev logo is shown for 5 seconds
  • Program closes

That is what scenes are for. Each of that segments such as intro, main menu and credits screen can be represented as a scene object, which together build the ultimate game flow.

Preparing the SceneManager

The Game class by default has a SceneManager property, so all we have to do is telling our game to use it. Navigate to OnInitialize. Before returning the EngineConfiguration, add this line:

this.GameComponentManager.Add(this.SceneManager);

Creating a new Scene

Now let's create an intro scene. In solution explorer, head to your project source files and add a new folder called "Scenes". Inside, create a new class called IntroScene and add the following includes:

using Sharpex2D.Math;
using Sharpex2D.Rendering;
using Sharpex2D.Rendering.Scene;

Let your class inherit from Scene (Sharpex2D.Rendering.Scene namespace) and implement all abstract members. You should get something linke this:

using Sharpex2D;
using Sharpex2D.Math;
using Sharpex2D.Rendering;
using Sharpex2D.Rendering.Scene;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SGLTest.Scenes
{
    class IntroScene : Scene
    {
        public override void Update(Sharpex2D.GameTime gameTime)
        {
           
        }

        public override void Draw(Sharpex2D.Rendering.SpriteBatch spriteBatch, Sharpex2D.GameTime gameTime)
        {
            
        }

        public override void Initialize()
        {
            
        }

        public override void LoadContent(Sharpex2D.Content.ContentManager content)
        {
            
        }
    }
}

Explanation of these functions:

  • Initialize is where you instanciate and set all non-resource objects (such as integers, lists, strings etc.)
  • LoadContent does the same for resources
  • Update is called as often as possible. This is the place to handle all your game logic, for example processing input, calculating positions etc.
  • Draw is where you define what to draw and how to draw it.

Go back to your MainGame class. In LoadContent, do the following:

public override void OnLoadContent()
{
    this.SceneManager.AddScene(new Scenes.IntroScene());
    this.SceneManager.ActiveScene = this.SceneManager.Get<Scenes.IntroScene>();
}

What we do here is telling the SceneManager to manage an IntroScene object. The second line defines that the currently active scene is the one of type IntroScene.

Note: The SceneManager does only handle one object per type. This makes it possible to select scenes by only using the type of the scene. Another positive effect is that scene states will be "saved" when deactivating them.

Give it some life

Let's test if we did everything well by getting rid of that ugly blue background and change it to black.

public override void Draw(Sharpex2D.Rendering.SpriteBatch spriteBatch, Sharpex2D.GameTime gameTime)
{
    SGL.Components.Get<GraphicsDevice>().ClearColor = Color.Black;
}

If you start your project and get a black screen instead of a blue, you did everything well.

Let's also greet the user with a little message. So let's add a font and draw a Text centured to the screen. I'll skip the explanation of creating fonts here as it is already described in the Drawing article.

You can center the font by placing it at half the size of the screen and then offsetting it by half it's size. The size can be calculated with SpriteBatch.MeasureString

using Sharpex2D;
using Sharpex2D.Math;
using Sharpex2D.Rendering;
using Sharpex2D.Rendering.Scene;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SGLTest.Scenes
{
    class IntroScene :Scene
    {
        Font font;
        string greeting = "Hello, World!";
        public override void Update(Sharpex2D.GameTime gameTime)
        {

        }

        public override void Draw(Sharpex2D.Rendering.SpriteBatch spriteBatch, Sharpex2D.GameTime gameTime)
        {
            spriteBatch.GraphicsDevice.ClearColor = Color.Black;
            Vector2 screenCenter = new Vector2(spriteBatch.GraphicsDevice.BackBuffer.Width,
                spriteBatch.GraphicsDevice.BackBuffer.Height) / 2;
            Vector2 textPosition = screenCenter - (spriteBatch.MeasureString(greeting, font) / 2);

            spriteBatch.DrawString(greeting, font, textPosition, Color.White);
        }

        public override void Initialize()
        {

        }

        public override void LoadContent(Sharpex2D.Content.ContentManager content)
        {
            font = new Font("Arial", 20f, TypefaceStyle.Bold);
        }
    }
}

Calculating the size of the string within the Draw method makes it possible to change the string to whatever you want, it'll still be centered.

Changing scenes

As we said, we want this greeting to disappear after 3 seconds and head on to the menu. So first of all, we need a Menu Scene. Create an new class MenuScene in your Scenes directory and let it inherit from Scene. In this scene, set the background color back to cornflower blue. We'll also draw a heading.

using Sharpex2D.Math;
using Sharpex2D.Rendering;
using Sharpex2D.Rendering.Scene;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SGLTest.Scenes
{
    class MenuScene : Scene
    {
        Font font;
        public override void Update(Sharpex2D.GameTime gameTime)
        {
        }

        public override void Draw(Sharpex2D.Rendering.SpriteBatch spriteBatch, Sharpex2D.GameTime gameTime)
        {
            spriteBatch.GraphicsDevice.ClearColor = Color.CornflowerBlue;
            spriteBatch.DrawString("Menu", font, new Vector2(100, 100), Color.White);
        }

        public override void Initialize()
        {
        }

        public override void LoadContent(Sharpex2D.Content.ContentManager content)
        {
            font = new Font("Helvetica", 25f, TypefaceStyle.Bold);
        }
    }
}

Then, add it to the SceneManager like you did it with the IntroScene before.

public override void OnLoadContent()
{
    this.SceneManager.AddScene(new Scenes.IntroScene());
    this.SceneManager.AddScene(new Scenes.MenuScene());
    this.SceneManager.ActiveScene = this.SceneManager.Get<Scenes.IntroScene>();
}

Go back to your IntroScene and navigate to the Update function. In there, use the passed gameTime variable to determine if the game is already running for 3 seconds or longer. If so, get the SceneManager instance and set the active scene to MenuScene.

public override void Update(Sharpex2D.GameTime gameTime)
{
    if (gameTime.TotalGameTime.Seconds > 3)
    {
        SceneManager sceneManager = SGL.Components.Get<SceneManager>();
        sceneManager.ActiveScene = sceneManager.Get<MenuScene>();
    }
}

Test it. Your scene should change after 3 seconds.