ARC-8: devlog #2 - Blazor

Some years ago I coded a CHIP-8 emulator in C# just for fun, that emulator was hibernating in a private repository that I never released. Some days ago I started to working on it again with the idea to release it running on Blazor and as a Unity asset where any game developer could drag its prefabs as easter eggs directly to their games.

In this post, I will talk about how I implemented the graphics, sound, input, and log systems for Blazor.

You can read the other ARC-8’s devlog posts.

The source code is not yet published on GitHub, I will notify in this series of posts about ARC-8 devlog and on my Twitter too when this happens.

Introduction

Blazor is a feature of ASP.NET that extends the .NET developer platform with tools and libraries for building web apps.

Blazor can run your client-side C# code directly in the browser, using WebAssembly. Because it’s real .NET running on WebAssembly, you can re-use code and libraries from server-side parts of your application.

This is why we can use our ARC-8 Core, mentioned in the previous devlog, because it is a .NET Standard class library and can run directly on Blazor web assembly.

For some components, like menu, inputs, and buttons I use the Blazorise library.

Online demo

You can test and play the CHIP-8’s games directly on your browser with our online demo: ARC-8 Blazor Online Demo.

Systems interfaces implementations

post image

The system interfaces IGraphic, ISound, IInput, and ILog will be implemented as Blazor components.

A component is a self-contained chunk of user interface (UI), such as a page, dialog, or form. A component includes HTML markup and the processing logic required to inject data or respond to UI events. Components are flexible and lightweight. They can be nested, reused, and shared among projects.

post image


Chip8Graphic.razor component (IGraphic)

post image

This a simplified version of IGraphic implementation (without of color selector that you can see in the demo).

C# side

JS side

OnAfterRenderAsync method

In the method OnAfterRenderAsync we verify if it’s the component’s first render, then we call a JS method that will initialize a JS helper for Chip8Graphic.razor that will return the size of the canvas to C# code, then we use this information to scale our 64 x 32 CHIP-8’s display.

OnAfterRenderAsync and OnAfterRender are called after a component has finished rendering. Element and component references are populated at this point. Use this stage to perform additional initialization steps using the rendered content, such as activating third-party JavaScript libraries that operate on the rendered DOM elements.

Draw method

This is one of the two methods needed to be implemented of IGraphic interface. We received the array (64x32) of bytes representing the current state of CHIP-8 graphics and just update our local array variable _gfx.

RenderAsync method

The method RenderAsync will be called by the Chip8Loader component during the Game Loop.

This method is used to draw the state of CHIP-8 graphics (_gfx array) to the HTML page. We use a second array called _buffer to implement a Double Buffer and reduce the screen flickering.

A byte with value 1 should be drawn (foreground color) and a byte with value 0 should not be drawn (background color).

Invalidate method

This is the second of the two methods needed to be implemented of IGraphic interface, but as we implemented a Double Buffer, this method does not need to perform any operation.

Resize method

Called by the JS side every time that the user resizes the browser window.

ClearCanvasAsync method

We use this one to invalidate our _buffer and reset the canvas to the background color.

Chip8Sound.razor component (ISound)

post image

This a simplified version of ISound implementation.

C# side

JS side

OnInitialized method

We just use the information from NavigationManager to set the audio file we want to play.

Play method

This is the only method we need to implement of ISound interface and it just calls a JS method that will get the audio tag on the component, set the AudioSource, then load, and play it.

Chip8Input.razor component (IInput)

post image

This is the IInput implementation.

C# side

JS side

Key mapping

First we create the dictionary _map to map the real keyboard keys to CHIP-8 keypad keys. The second dictionary we create is _keyDown. It will be used to map what keys the player is pressing.

OnAfterRenderAsync method

We call the JS method chip8Input.init that will add two event listeners, one for keydown and the other for keyup that will call the C# methods HandleKeyDown and HandleKeyUp.

UpdateKeys method

The only method we need to implement for IInput interface. In this method, we set to 1 the CHIP-8’s keypad keys that were pressed by the player.

HandleKeyDown and HandleKeyUp methods

This method is responsible to set the _keyDown dictionary by the keyboard keys that the player pressed.

Chip8Log.razor component (ILog)

post image

This is a simplified version of the ILog implementation.

C# side

Debug and Error methods

The two methods implemented for ILog interface use the Microsoft.Extensions.Logging.ILogger<T> to send log messages to the browser console.

Chip8Loader.razor

post image

This is a simplified version of the component responsible to load all systems (IGraphic, ISound, IInput, and ILog), initialize the Chip8 class emulator, load the ROM and perform the game loop.

C# side

JS side

OnAfterRenderAsync method

Initializes the emulator with the systems, then calls the JS chip8Loader.init function that will use the browser window.requestAnimationFrame to call the C# method RunCycle.

The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint.

RunCycle method

This method is called by the JS (window.requestAnimationFrame). We implement a Game Loop and in the end, call the Chip8Graphic.RenderAsync.

Next step

post image

In the next ARC-8 devlog I will talk about the ARC-8’s implementation on Unity3D.

If you have any doubts about what I talk about above or any tip about the CHIP-8 emulator (or Blazor) and you like to share it, please let me know in the comments section below.

Further reading

post image




Icons made by Freepik, Vignesh Oviyan and Eucalyp from www.flaticon.com is licensed by Creative Commons BY 3.0

Loading comments...
Tutorials

Articles

Labs