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.
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.
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
The system interfaces
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.
Chip8Graphic.razor component (IGraphic)
This a simplified version of
IGraphic implementation (without of color selector that you can see in the demo).
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.
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
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
A byte with value 1 should be drawn (foreground color) and a byte with value 0 should not be drawn (background color).
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.
Called by the JS side every time that the user resizes the browser window.
We use this one to invalidate our
_buffer and reset the canvas to the background color.
Chip8Sound.razor component (ISound)
This a simplified version of
We just use the information from
NavigationManager to set the audio file we want to play.
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)
This is the
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.
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
The only method we need to implement for
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)
This is a simplified version of the
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.
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.
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
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.
This method is called by the JS (
We implement a Game Loop and in the end, call the
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.
- Blazor Tutorial - Build your first Blazor app
- Blazorise quick-start
- Create and use ASP.NET Core Razor components
- ASP.NET Core Blazor lifecycle
- ASP.NET Core Blazor logging
- Double Buffer
- Game Loop