Table of Contents

Setting up a project

This guide covers the parts of a game's project that the first game leaves out: which packages to add, how the project file should look, how the game is laid out in a solution, how logging is set up, and how to choose the render backend.

Packages

Start with BSGameLib.Game. Add the others when the game needs them:

dotnet add package BSGameLib.Game --prerelease
dotnet add package BSGameLib.UI --prerelease                  # menus and other views
dotnet add package BSGameLib.Networking --prerelease          # online play, the client side
dotnet add package BSGameLib.Game.ShaderCompiler --prerelease # shaders made at runtime

The server is a separate project. The host and its settings covers what it needs.

The packages target .NET 10, so the project's TargetFramework is net10.0. The native libraries come in with the packages and need no reference of their own. Publishing a game says which of them each platform gets.

The project file

A game's project file needs only its folders of content and views copied to the output, beyond the packages:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="Content\**\*" CopyToOutputDirectory="PreserveNewest" />
    <Content Include="Views\**\*" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

</Project>

Content holds the textures, atlases and fonts that ContentManager loads. Views holds the XML that BSGameLib.UI reads. Copy only the folders the game has.

Set AllowUnsafeBlocks only when the game's own code uses unsafe. The packages are compiled with it on for their own code, and it does not pass on to the projects that reference them.

Solution layout

A game with an online server usually has three projects in one solution:

  • The client, the game itself: references BSGameLib.Game, BSGameLib.UI and the shared project.
  • The shared project, for packets and anything else both sides use: references BSGameLib.Networking.
  • The server: references BSGameLib.Server and the shared project.

The client never references the server project, so the server's host and its dependencies stay out of the game. A game without online play needs only the client project.

Logging

The game logs through the ILoggerFactory in its service container. Without one, its logs go nowhere. Register one in Configure:

using BSGameLib.Game;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class MyGame : Game
{
  protected override void Configure(IServiceCollection services) =>
    services.AddLogging(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Debug));

  protected override void Initialize()
  {
    Logger.LogInformation("Started");
    base.Initialize();
  }
}

AddLogging comes from Microsoft.Extensions.Logging, which BSGameLib.UI brings in. The console provider is in the Microsoft.Extensions.Logging.Console package, so add it with dotnet add package Microsoft.Extensions.Logging.Console when the game has no UI package. Any other provider works the same way. Services, including your own, take ILogger<T> from the container.

The render backend

The renderer is Vulkan by default. The game can ask for OpenGL instead, by name:

Name Renderer
vulkan, vk Vulkan. The default.
opengl, open-gl, gl OpenGL.

Names are not case-sensitive. The choice comes from the first of these that is set:

  1. The BSGAMELIB_RENDER_BACKEND environment variable.
  2. The --render-backend argument on the command line, as --render-backend opengl or --render-backend=opengl.
  3. PreferredRenderBackend in the game's WindowOptions.
  4. Vulkan.

So a player or a tester can override the game's choice without rebuilding it:

using BSGameLib.Game;

public class MyGame : Game
{
  public MyGame() : base(new WindowOptions
  {
    Title = "My Game",
    Width = 1280,
    Height = 720,
    PreferredRenderBackend = "opengl",
  }) { }
}
dotnet run -- --render-backend vulkan

The -- separates the arguments for dotnet run from the arguments for the game. A name the game does not recognise falls back to Vulkan and logs a warning, which shows only when logging is set up.

If Vulkan is chosen and fails to start, the game starts on OpenGL instead, unless the fallback is turned off. See Falling back to OpenGL.

Next