Category Archives: Blazor

Creating a Game in Blazor – Part 4 – Platform and Collision

I’ve recently been creating a JetSet Willy clone in Blazor. I use the term clone loosely – I’m actually not creating a clone or anything like it – I’m simply replicating some aspects of the game (moving, jumping, platforms, collision, etc.).

This is the fourth post in the series that started here. In this post, I’m going to add a platform – so far we’ve been walking on the air.

As with previous posts, the code for this can be found here on GitHub.

In order to do this, we’ll need to do a bit of refactoring, and to introduce a crude collision concept. Let’s start with the refactoring and platform display:

We’re introducing the concept of a base GameObject, from which, Platform, Player, and NPC inherit. We’re dispensibg of IPlayer, and instead, adapting World to manage the elements in the world:

    public class World : IWorld
    {
        private readonly IEnumerable<GameObject> _gameObjects;

        public World(IEnumerable<GameObject> gameObjects)
        {
            _gameObjects = gameObjects;
        }

        public Player Player
        {
            get => (Player)_gameObjects.First(a => a.GameObjectType == GameObjectType.Player);
        }

        public IEnumerable<GameObject> Platforms 
        {  
            get => _gameObjects.Where(a => a.
                GameObjectType == GameObjectType.Platform);
        }

        public void ApplyPhysics()
        {   
            foreach (var gameObject in _gameObjects)
            {
                gameObject.Update();
            }            

        }
        
    }

We’re not dealing with NPCs in this post, but we are dealing with platforms. The new Platform class currently looks like this:

    public class Platform : GameObject
    {
        public Platform(int width, int height, int left, int top)
        {
            Width = width;
            Height = height;
            Left = left;
            Top = top;
            GameObjectType = GameObjectType.Platform;
        }

        public override void Update()
        {
            //throw new System.NotImplementedException();
        }
    }

We’ll no doubt come back to this, but essentially, all we’re doing is maintaining a collection of GameObjects with a specific type.

For now, we’ll inject the properties of the World in through Program.cs:

    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("#app");

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddSingleton<IWorld, World>(srv =>
            {
                var platform = new Platform(
                    50, 10, 0, WorldSettings.FLOOR);

                var player = new Player(17, 21, new[] { platform })
                {
                    GameObjectType = GameObjectType.Player,
                };

                var world = new World(new GameObject[] { player, platform });                
                return world;
            });            
            builder.Services.AddSingleton<IControls, Controls>();
            builder.Services.AddSingleton<IGraphics, Graphics>();

            await builder.Build().RunAsync();
        }
    }

As you can see, we build the Platform and Player and then build the world. Finally, we adapt Game.razor to display the platforms:

@page "/"
@using System.Timers
@using BlazorGame.GameLogic
@inject IEnumerable<GameObject> GameObjects
@inject IControls Controls
@inject IWorld World
@inject IGraphics Graphics

<div @onkeydown="HandleKeyDown" @onkeyup="HandleKeyUp" @onkeydown:preventDefault 
    style="background-color: #000000; width: 80vw; height: 80vh; margin: auto"
    tabindex="0" @ref="mainDiv">
    <div style="color: white; top: @(World.Player.Top)px; left: @(World.Player.Left)px; width: @(World.Player.Width)px; height: @(World.Player.Height)px; overflow: hidden; position: relative">
        <img 
            src="/images/Willy-Sprite-Sheet.png" 
            style="margin: 0 @(Graphics.PlayerOffset)px; transform: scaleX(@(Graphics.PlayerDirection))" />
    </div>

    @foreach (var platform in World.Platforms)
    {
        <div style="position: relative; top:@(platform.Top)px; left:@(platform.Left)px; width:@(platform.Width)px; height:@(platform.Height)px; border: 1px solid #FFFFFF; background-color: #FFFFFF"></div>
    }
</div>

Finally, we need to ensure that our player lands on the platform (and doesn’t simply drop through). For now, we’ll pass the World into Player and perform the logic there:

        public override void Update()
        {
            _forceUp -= WorldSettings.GRAVITY;

            Top -= _forceUp;

            Console.WriteLine($"Top: {Top}, Left: {Left}, Width: {Width}");

            var platform = _gameObjects.FirstOrDefault(a =>
                a.Top <= Top &&
                a.Left <= Left + Width &&
                a.Left + a.Width >= Left + Width &&
                a.GameObjectType == GameObjectType.Platform);
            
            if (platform != null)
            {
                Top = platform.Top;
                _forceUp = 0;
            }
            
            if (Left <= 0 && _forceRight < 0) 
                _forceRight = 0;
            else if (_forceRight != 0)
                _direction = _forceRight;            

            Left += _forceRight;
            
        }

It’s not quite finished yet, but we now have a platform that we can walk on, and fall off:

What’s Next?

In the next post, I’ll try to introduce an NPC (not quite sure where I can get the graphics from yet, so it might just be a rectangle or something).

Creating a Game in Blazor – Part 3 – Graphics

In this post I started writing a game in Blazor. In this last post, I covered how we could use the keyboard to move an object around, and how we could apply gravity.

In this post, we’re going to refactor, and we’re going to replace the word test with something approximating Willy.

Refactor

Just because we’re writing a game in Blazor is no reason not to use the IoC container in order to better structure the code. I’m not going to cover all of the refactoring here; however, the changes are here.

We’ve added a sub-directory called GameLogic which contains all the relevant classes:

At some point in the future, we may separate this directory into its own project; but for now, we have four classes:

Controls – this handles the user input.

Graphics – this will handle the manipulation of the graphics.

Player – this handles behaviour of the player.

World – this deals with the things such as collisions, gravity, etc.

WorldSettings – these are just a list of variables that control how things move. In the original game, there was a POKE that meant you could jump so high that you went into the next room.

I won’t cover what’s actually in these classes – it’s essentially what was in the main Razor file. I will cover the change to the razor file itself:

@page "/"
@using System.Timers
@using BlazorGame.GameLogic
@inject IPlayer Player
@inject IControls Controls
@inject IWorld World

<div @onkeydown="HandleKeyDown" @onkeyup="HandleKeyUp" @onkeydown:preventDefault 
    style="background-color: #000000; width: 80vw; height: 80vh; margin: auto"
    tabindex="0" @ref="mainDiv">
    <div style="color: white; top: @(Player.Top)px; left: @(Player.Left)px; width: 20px; position: relative">test</div>
</div>

@code {

    private ElementReference mainDiv;    
    private Timer _timer;

    private void HandleKeyUp(KeyboardEventArgs e) =>
        Controls.KeyUp(e.Code);    

    private void HandleKeyDown(KeyboardEventArgs e) =>    
        Controls.KeyDown(e.Code);    

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await mainDiv.FocusAsync();
        }
    }

    protected override Task OnInitializedAsync()
    {
        _timer = new Timer();
        _timer.Interval = 16;
        _timer.Elapsed += TimerElapsed;
        _timer.AutoReset = true;
        _timer.Enabled = true;        

        return base.OnInitializedAsync();
    }

    private void TimerElapsed(Object source, System.Timers.ElapsedEventArgs e)
    {
        Update();
        Draw();
    }

    private void Update()
    {
        World.ApplyPhysics();
    }

    private void Draw() => 
        this.StateHasChanged();    

}

This is much more terse than before, and delegates most of its functionality to the classes that we described above. You’ll see at the top that we @inject those classes into the page.

Finally, the classes are registered in Program.cs:

        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("#app");

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.Services.AddSingleton<IWorld, World>();
            builder.Services.AddSingleton<IPlayer, Player>();
            builder.Services.AddSingleton<IControls, Controls>();

            await builder.Build().RunAsync();
        }

This is by no means the last refactoring that we’ll do, but it’s perhaps the last one that will make it into its own section of a post.

Graphics

For the graphics, I spent a while trying to get various graphics libraries to work cross platform. I finally realised that, not only did I not need a graphics library, but that I’d solved this issue before – well, more or less. The answer was to use CSS to animate the image. The very first step was to add a sprite sheet; which I got from here, and since Jet Set Willy is the same character as manic miner (with just one pixel difference in the hat), I managed to add a sprite sheet:

The next change was to alter the HTML in Game.razor slightly:

<div @onkeydown="HandleKeyDown" @onkeyup="HandleKeyUp" @onkeydown:preventDefault 
    style="background-color: #000000; width: 80vw; height: 80vh; margin: auto"
    tabindex="0" @ref="mainDiv">
    <div style="color: white; top: @(Player.Top)px; left: @(Player.Left)px; width: 16px; height: 17px; overflow: hidden; position: relative">
        <img 
            src="/images/Willy-Sprite-Sheet.png" 
            style="margin: 0 @(Graphics.PlayerOffset)px; transform: scaleX(@(Graphics.PlayerDirection))" />
    </div>
</div>

There’s a few things to unpick here. Let’s start with the interaction between the div and the img. Essentially, we’re using the div as a window into the image; similar to this:

Both the margin and transform are set to bound properties of a new Graphics class, which we’ll come to in a second; but first, let’s see the other change to this file:

    private void Update()
    {
        World.ApplyPhysics();
        if (Player.IsWalking)
        {
            Graphics.CyclePlayer();
        }
    }

This allows us to change the bound variables that we mentioned earlier.

Now that we’ve seen the changes to the main razor file, let’s see the new Graphics class:

    public class Graphics : IGraphics
    {
        private readonly IPlayer _player;
        private int _playerOffset = 0;
        private DateTime _lastUpdate = DateTime.MinValue;

        public Graphics(IPlayer player)
        {
            _player = player;
        }

        public int PlayerOffset => _playerOffset;

        public int PlayerDirection =>
            _player switch
            {
                { IsWalkingLeft: true } => -1,
                { IsWalkingRight: true } => 1,
                _ => 0
            };
        
        public void CyclePlayer()
        {
            if (_lastUpdate.AddMilliseconds(100) > DateTime.Now) return;

            if (_playerOffset > -48)
                _playerOffset -= 16;
            else
                _playerOffset = 0;

            _lastUpdate = DateTime.Now;
        }
    }

This is essentially a utility, or helper class. It encapsulates details about the graphics that are displayed, and uses the Player class to do so. Most of it is relatively self-explanatory, with the possible exception of CyclePlayer which moves the offset that we mentioned earlier no more frequently that every 100ms.

That’s pretty much it; we now have a walking Willy:

What’s Next?

In the next post, we’ll try to add a platform, and some collision logic.

References

https://www.spriters-resource.com/fullview/113060/

https://gunnarpeipman.com/csharp-reading-embedded-files/

https://www.hanselman.com/blog/how-do-you-use-systemdrawing-in-net-core

https://www.davidguida.net/blazor-gamedev-part-11-improved-assets-loading/

https://stackoverflow.com/questions/493296/css-display-an-image-resized-and-cropped

Creating a Game in Blazor – Part 2 – Gravity, and Controls

In this post I started the process of writing a very vague approximation of Jet Set Willy, in an effort to regain my youth.

Here, we’re going to take those very vague foundations, and allow left and right controls, along with a jump function. As a caveat, I’m going to state here that I expect quite large swathes of this code to change significantly before I declare it complete; and, as another caveat, there were 60 rooms in the original Jet Set Willy. I’ll be surprised if this series of posts manages to replicate the bathroom (which is the first room).

From the first post, we have a Game.razor, and all the code for this post will go into there. You can simply view that code here.

I’ve introduced a game loop here, which calls an update and then a draw method. Currently, the game loop is just a crude timer:

    private void TimerElapsed(Object source, System.Timers.ElapsedEventArgs e)
    {
        Update();
        Draw();
    }

This gets registered in the OnInitializedAsync method:

    protected override Task OnInitializedAsync()
    {
        _timer = new Timer();
        _timer.Interval = 16;
        _timer.Elapsed += TimerElapsed;
        _timer.AutoReset = true;
        _timer.Enabled = true;        

        return base.OnInitializedAsync();
    }

The Draw method is, in fact, just a single line:

private void Draw() => this.StateHasChanged();  

The reason for this is that Blazor doesn’t always automatically refresh state – updating bound objects on a timer is one of the times when it doesn’t. The Update method has a little more to it:

    private void Update()
    {
        ApplyGravity();
        _top -= _forceUp;

        if (_top > FLOOR)
        {
            _top = FLOOR;
            _forceUp = 0;
        }

        if (_left <= 0 && _forceRight < 0) _forceRight = 0;

        _left += _forceRight;
    }

Anything in caps is just a constant. The rest of the code basically takes care of the left, right, and jump.

Next, we’ll need to modify the HandleKeyDown method:

    private void HandleKeyDown(KeyboardEventArgs e)
    {
        switch (e.Code)
        {
            case "ArrowLeft": // Left
                if (_forceUp == 0)
                {
                    Walk(-SPEED);
                }
                break;
            case "ArrowUp": // Up
                Jump();
                break;
            case "ArrowRight": // Right
                if (_forceUp == 0)
                {
                    Walk(SPEED);
                }
                break;
            default:
                break;
        }
    }

As you can see, we’ve added Jump and Walk methods. All the logic has moved into those methods:

    private void Walk(int amt) => _forceRight = amt;

    private void Jump()
    {
        if (_forceUp == 0)
        {
            _forceUp += JUMP_FORCE;
        }
    }

Since Walk needs to be immediate, we just set the _forceRight to whatever value it’s passed; similarly with the jump, although we can’t allow a double jump, so we determine if a jump is in progress first.

Finally, we’ve added a HandleKeyUp: this stop walking when the key is released.

    private void HandleKeyUp(KeyboardEventArgs e)
    {
        switch (e.Code)
        {
            case "ArrowLeft": // Left
                Walk(0);
                break;

            case "ArrowRight": // Right
                Walk(0);
                break;

            default:
                break;
        }
    }

If you run this, you should now be able to walk “test” around the screen, and cause him to jump.

What’s Next?

For the next steps, I’m going to add a platform, and try to use some graphics. I’ll also try to refactor a little, as the main form is becoming a little large.

References

https://docs.microsoft.com/en-us/aspnet/core/blazor/components/event-handling?view=aspnetcore-5.0

https://www.pmichaels.net/2019/06/03/creating-a-car-game-in-react-part-1-drawing-and-moving/

https://stackoverflow.com/questions/58920461/how-to-detect-key-press-without-using-an-input-tag-in-blazor

Creating a Game in Blazor – Part 1 – Moving Objects

By now, writing games in frameworks that were clearly not designed for such things is becoming something of a habit for me. Here I created a poor-man’s version of Trans-Am (the hugely popular Spectrum game) in React, and here I attempted something along the lines of Daley Thompson’s Decathlon in Vue. I even created a catch game and a snake game in a .Net console app.

In this post, I’m going to attempt to create a game in Blazor. I’m hoping I can get a vague approximation of a platform game, such as Jet Set Willy. Obviously, this will not be as advanced (nor will I be able to offer a helicopter ride as a prize for finishing, as the creators originally did), but I can hopefully get some semblance of something moving across the screen, and the ability to jump over obstacles.

For part one, we’ll just explore how we would move an object. To start, let’s create a default Blazor client side application.

If you’d like to see the finished product from this post, you’ll find it here.

We’ll start in the Counter.razor file. We’ll simply replace the existing code with the following:

@page "/counter"

<h1>Counter</h1>

<button class="btn btn-primary" @onclick="IncrementLeft">Across</button>
<button class="btn btn-primary" @onclick="IncrementTop">Down</button>

<div style="top: @(top)px; left: @(left)px; position: absolute">test</div>

@code {
private int top = 0;
private int left = 0;

private void IncrementLeft()
{
left += 10;
}

private void IncrementTop()
{
top += 10;
}

}

All we’re really doing here is binding the position of the div to the variables left and top and then changing them on the button presses. Each time they are updated, they trigger a refresh of the screen.

You should now see the word test (very vaguely) in the top left hand corner of the screen. Pressing the Across and Down buttons move the text – if you move it far enough, you should be able to see it clearly against the white background.

Tidy Up

Now that this is working, let’s remove some of the cruft – our game doesn’t need a menu, or a FetchData screen; the following files can be removed:

Index.razor
NavMenu.razor
FetchData.razor

In Counter.razor we can change the routing:

@page "/"

Finally, change the code in MainLayout.razor to the following:

@inherits LayoutComponentBase

<div class="page">
<div class="main">
<div class="content px-4">
@Body
</div>
</div>
</div>

What’s left is just the counter screen: which can now be renamed to something more appropriate – I’ve changed mine to Game.razor.

What’s Next

We now have something moving around the screen – the next step will be to make this work using key presses, and add an actual platform for our game.

Simple binding in Blazor

A while back, I asked on Dev about moving my blog from WordPress to … well, not WordPress anymore. My main critera was to Markdown instead of whatever the WordPress format is called. The main issue being that you need to replace the code tags.

I resolved to create a tool to do it for me. I’m doing so in Blazor.

The first task was to create a very simple data binding scenario, so I could handle all the view logic in the View Model. I’ve previously written about using view models. This post covers the scenario where you want to bind text boxes and a button.

Let’s see the View Model first:

    public class MainViewModel
    {
        public string WpText { get; set; }
        public string MdText { get; set; }

        public void ConvertText()
        {
            MdText = $"Converted {WpText}";
        }
    }

Okay, so we have two strings, and a method that populates the second string with the first. As per the linked post, the plumbing for the view model is very simple; first, it’s registered in ConfigureServices:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MainViewModel, MainViewModel>();
        }

Then it’s injected into the Razor view:

@page "/"
@inject ViewModels.MainViewModel MainViewModel

In fact, the next part is much simpler than I thought it would be. To bind a view model property to the view, you just use the syntax bind:

<div class="container">
    <div class="row">
        <div class="form-group col-md-6">
            <label for="WpText">Wordpress Text</label>
            <input type="text" @[email protected] class="form-control" id="WpText" name="WpText"/>
        </div>

        <div class="form-group col-md-6">
            <label for="MdText">Markdown</label>
            <input type="text" @[email protected] class="form-control" id="MdText" name="MdText"/>
        </div>
    </div>
    <div class="row">
        <div class="form-group col-md-12">
            <input type="button" value="Convert" @[email protected](() => MainViewModel.ConvertText()) class="form-control" id="Submit" />
        </div>
    </div>
</div>

Just to point out one thing that tripped me up before I leave this: the event handlers that relate to Blazor must be prefixed with an at symbol (@).

References

https://www.nativoplus.studio/blog/blazor-data-binding-2/

Using Blazor Components

Imagine that you’re writing a Blazor application – maybe it’s similar to this one. Now, imagine that you have a large chunk of HTML in your main view. You might think: I wish I was using React, then I could separate this into its own component.

You can also do this in Blazor. Here’s how.

Components in Blazor

Let’s start with moving your code. The first step is to cut your HTML and paste it into a new Razor Component:

The format of your new component, from scratch, will be:

&lt;h3&gt;Component Name&lt;/h3&gt;

@code {

}

Your existing code should go beneath, or instead of:

&lt;h3&gt;Component Name&lt;h3&gt;

Parameters

The @code section allows you to put all kinds of crazy C# code in a code behind type model – so you probably don’t want to use that, except for passing parameters; for example:

@code {
    [Parameter]
    private string MyParameter { get; set; }
}

This allows you to pass a string into your component; for example (in your main view):

&lt;MyComponent MyParameter=&quot;test&quot; /&gt;

Complex Parameters

So far so good. But what if you need a complex type? You could, for example, pass a View Model into your component:

[Parameter]
private MyViewModel MyViewModel { get; set; }

You can pass this into the component as though it were a primitive type:

&lt;MyComponent MyViewModel=&quot;@MyViewModel&quot; /&gt;

This means that you can lift and shift the code with no changes.

Using External Namespaces

As with standard C#, you can access anything within the current namespace. Should you need any classes that are not in your current namespace, you can declare them at the top of the file, like this:

@using MVVMShirt

&lt;h3&gt;My Component&lt;/h3&gt;

Summary

Blazor is still in its infancy, but hopefully, adding actual code to these @code sections will become as frowned upon as code-behind.

Adding Logging to Client Side Blazor

Whilst there are some pre-built libraries for this, I seemed to be getting Mono linking errors. What finally worked for me was to install the pre-release versions of:

Install-Package Microsoft.Extensions.Logging -Version 3.0.0-preview6.19304.6
Install-Package Microsoft.Extensions.Logging.Console -Version 3.0.0-preview6.19304.6

Now, in your View Model, accept the Logger:

public MyViewModel(ILogger<MyViewModel> logger)

Then you can log as normal:

_logger.LogInformation("Hello, here's a log message");

You should now see the debug message in the F12 console.

You might be wondering why you don’t need to explicitly inject the logging capability; the reason is that:

BlazorWebAssemblyHost.CreateDefaultBuilder()            

Does that for you.

Using View Models in Blazor

Being new to Blazor (and Razor), the first thing that tripped me up was that the view seemed divorced from the rest of the application. In fact, this is actually quite a nice design, as it forces the use of DI.

For example, say you wanted to create a View Model for your view, you could register that ViewModel in the Startup:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<MyViewModel, MyViewModel>();
        }

Note here that you don’t need an interface. If you’re only creating an interface for the purpose of this then that abstraction provides no benefit. That isn’t to say there may not be a reason for having an interface, but if you have one and this is the only place it’s used, you probably should reconsider.

The views in Razor / Blazor (at the time of writing) are *.razor files. In order to resolve the dependency inside the view, you would use the following syntax:

@page "/"
@inject ViewModels.MyViewModel MyViewModel

(Note that @page “/” is only in this snippet to orientate the code.)

You can call initialisation in the view model using something like:

@code {

    protected override async Task OnInitAsync()
    {
        await MyViewModel.Init();
    }    
}

And, within your HTML, you can reference the view model like this:

<div>@MyViewModel.MyData</div>

Magic. Hopefully more to come on Blazor soon.