Skip to content
Justin Skiles edited this page Apr 17, 2020 · 1 revision

Introduction

Version 3.0 rearchitected the structure of the engine to favor composition over inheritance. As such, it will help to understand the fundamentals of dependency injection. Don't worry, you don't need to be an expert to use the framework.

While this approach introduces more boilerplate to the bootstrapping process, it also allows for more flexibility in how the engine is implemented. In fact, you can even inject your own implementations of dependencies to change the behavior of your game.

SharpDL has helper extensions which make wiring up all of its inner dependencies easy (examples below) but requires the use of the Microsoft.Extensions.DependencyInjection framework. You can use a different dependency injection container, but you'll need to wire up the game engine dependencies on your own.

The Game Loop

Calling the Start method on the IGameEngine interface will result in the following:

  1. Initialize will initialize SDL with SDL_INIT_EVERYTHING flag, initialize SDL_ttf, and initialize SDL_image.
  2. LoadContent will perform a no-op.
  3. Until the End method is called on the IGame interface, the game loop will call Update to update the game state and Draw to draw the game state. Note that the game loop uses a Fixed Time Step approach
  4. UnloadContent will dispose the Window, Renderer, SDL_ttf, SDL_image, and SDL.

Creating a Blank Window

  1. First create a console application.

    dotnet new console -o MyFirstSharpDL

  2. Create a MainGame class which implements the IGame interface and takes an injected dependency on IGameEngine.

    public class MainGame : IGame
    {
        private readonly IGameEngine engine;
        
        public MainGame(IGameEngine engine)
        {
            this.engine = engine;
        }
        
        // Must be implemented as part of IGame interface. 
        // Usually just used to start the engine.
        public void Run()
        {
            engine.Start(GameEngineInitializeType.Everything);
        }
    }
  3. Update Program.cs to create your dependency injection container, add the game engine to it, and run your MainGame class. See comments below.

    class Program
    {
        static void Main(string[] args)
        {
            // Create dependency injection container with configured services.
            ServiceProvider serviceProvider = GetServiceProvider();
            
            // Get instance of your implemented game and then run it.
            var game = serviceProvider.GetService<IGame>();
            game.Run();
        }
    
        // Creates the dependency injection container, registers services with the container,
        // and returns the built container.
        private static ServiceProvider GetServiceProvider()
        {
            var services = new ServiceCollection();
            ConfigureServices(services);
            var serviceProvider = services.BuildServiceProvider();
            return serviceProvider;
        }
    
        private static void ConfigureServices(ServiceCollection services)
        {
            // Add the game engine components and your game to the dependency injection container.
            services.AddSharpGame<MainGame>();
        }
    }
  4. Add an Initialize method to your MainGame class. Update the MainGame constructor to set the engine's Initialize action to your method. This will inject your implementation into the game loop.

    private IWindow window;
    private IRenderer renderer;
    
    public MainGame(IGameEngine engine)
    {
    	this.engine = engine;
    	engine.Initialize = () => Initialize();
    }
    
    // Create a window from the engine's window factory.
    // Create a renderer using that window from the engine's renderer factory.
    private void Initialize()
    {
    	window = engine.WindowFactory.CreateWindow("Example 0 - Sandbox");
    	renderer = engine.RendererFactory.CreateRenderer(window);
    }
  5. Build and run to see a blank window.

    dotnet build

    dotnet run

Clone this wiki locally