Creating a game loop

When you look at Blazor and webassembly specifically you see that the performance is getting better and better. With this is mind building games in Blazor opens some possibilities. If you want to develop games that run in the webbrowser and you are an experienced .NET developer it is very handy that you can use the programming skills you already have to build that game.

The fundament of every game is a game loop. This is a loop that runs a lot of times every second (preferable 60 times or more) in which you can update your game logic, handle input and draw the new state of the game to the screen. So my first challenge was how to implement this game loop. After doing some research I found it was fairly easy to do this using the window.requestAnimationFrame (https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) method. This is a method that is implemented by all modern browsers. You can pass in a method of your own and the browser will call that method before the first repaint of the screen. In most browsers this is 60 times per second. But browsers do optimize this to their environment. So when possible (for example because a higher refresh rate of your monitor) it will do a repaint at an even higher frequency. What is important to know is that the browser will call your method only once. So if you want that it calls it continuously you have to call window.requestAnimationFrame again in the method that was called. Let me give you some example code:

1
2
3
4
5
6
7
8
<script>
		function gameLoop(timeStamp)
		{
			console.log('hello');
			window.requestAnimationFrame(gameLoop);
		}
		window.requestAnimationFrame(gameLoop);
</script>

When the browser runs this script you will see a new log in the console stating ‘hello’ about 60 times per second. If we can call our Bazor code from here we have the basis for our game loop.

To do this we have to register the instance of our Blazor component somewhere in javascript so we can call it from the gameLoop method. To make this possible I make use of the OnAfterRender (https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-5.0#after-component-render-onafterrenderasync) method of an ASP.NET core razor component. When this method is called I will call a javascript method using JSInterop to register the instance of my Blazor component in javascript. The following code shows this:

1
2
3
4
5
6
 protected override async Task OnAfterRenderAsync(bool firstRender)
 {
    if (!firstRender)
		return;
    await JsRuntime.InvokeAsync<object>("initGame", DotNetObjectReference.Create(this));
 }

Using the JsRuntime.InvokeAsync I call the initGame method in javascript. As a parameter I pass the result of DotNetObjectReference.Create(this). The result is a reference to my .NET object instance. Looking at the javascript side I added the following initGame method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
 <script>
    // the main gameloop. Will be called 60 times per second by requestAnimationFrame
    function gameLoop(timeStamp) {
        window.requestAnimationFrame(gameLoop);
        game.instance.invokeMethodAsync('GameLoop', timeStamp, game.canvases[0].width, game.canvases[0].height);
    }

    // will be called by blazor to initialize the game and register the game instance.
    window.initGame = (instance) => {
        var canvasContainer = document.getElementById('canvasContainer'),
            canvases = canvasContainer.getElementsByTagName('canvas') || [];

        window.game = {
            instance: instance,
            canvases: canvases
        };
        window.requestAnimationFrame(gameLoop);
    };
</script>

Here you see that I create a game object on the window object with a reference to the .NET instance. Next to that you see that I use the game object in my gameLoop method to call a gameLoop method on the instance of my .NET Blazor component. With this in place I have realized the basic game loop and we can start implementing our game logic in the GameLoop method in our Blazor component. This method will now be called 60 times (or more) per second.

Drawing on the screen

To draw on the screen I decided to use the NuGet package Blazor.Extensions.Canvas. This is in essence a wrapper around the HTML5 canvas. Using this wrapper you can just call all the HTML5 canvas functions from your C# code. To realize this we need a reference to our canvas inside our C# code. This can easily be done by declaring our canvas and setting a reference to it using the following code:

1
2
3
4
5
<BECanvas @ref="_canvasReference"></BECanvas>
@code
{
    BECanvasComponent _canvasReference = null;
}

Now we have a reference to our canvas we can start drawing on it from our earlier made GameLoop method. There is a whole list of methods you can call. You can for example draw lines, circles, squares, etc. You can even draw images to the screen. The following code shows how this can be done:

1
await _canvasContext.RectAsync(10, 10, 100, 100);

The example above will draw a rectangle at x position 10, y position 10 with a width of 100 and a height of 100.

Because the GameLoop method is called about 60 times per second you can make things move on the screen by making the X and Y position variable. I have worked out some examples showing this. Those examples can be found at:
https://github.com/henthoven/BlazorFunExamples

The things described above can be found in the projects Example1 & Example 2.

In my next blog I will continue on this subject and we will talk about handling input.