PostsAboutGames
All posts tagged with gamedev

"Some Tank Game" in the browser!

August 05, 2021 - Søren Alsbjerg Hørup

After getting Bevy to run in the browser I started the process of porting Some Tank Game to the browser.

First step was to refactor my main.rs into a lib.rs such that I could use bindgen to generate Javascript bindings for my entrypoint and use the bevy_webgl2 plugin to render in the browser.

Next step was to get my levels to properly load. For Some Tank Game I use the Tiled editor to create and edit levels. The library I use also works in the browser, BUT! apparently not with external tile sets.

Reason for the lack of external tile sets support seems to be due to the async nature of Ajax requests. First, the .tsx map file is loaded. Next, the referenced external tile sets are loaded. In a native environment this will happen sequentially with blocking I/O and the tiled struct will be returned after all data and dependencies have been loaded. In the browser, only the .tsx file is loaded, subsequent external tile sets are not loaded as part of the .tsx file load due to the async nature of the browser. The open issue on the subject can be found here.

To fix this issue, I opted for the simplest strategy ever - just imbed the tile sets into the .tsx files. Not pretty, but working. A proper fix would be to somehow pre-load the tilesets before loading the maps, such that these are available from the start.

After less than two hours of working, I got my game to successfully run in the browser and made a pipeline in github which builds and deploys the game to Github pages !!!

some tank game 2021 08 05 112614

Next step was to improve the experience by adding a spinner when loading the WASM module, preloading of assets when the WASM module was loaded and adding explicit touch support for Tablet support.

An issue I hit regarding Tablet support was that I could not get my game to reliable load on Android Chrome. Only if I attached the Chrome debugger could I get the game to run - huh?!?!. Firefox on mobile was OK.

After a lot of searching I found that Chrome 91 had a bug related to WASM loading. The Blazor guys were also affected by this bug which were discussed here.

Apparently, the Google guys fixed the issue in Chrome 92, which I successfully verified, but without really know the underlying issue and thus why the bug manifests in Chrome 91 - scary!!!

For the touch support, I had to be somewhat creative since winit, the windowing library bevy use, does not support touch events on mobile browsers. The solution I concocted was to implement touch events in JavaScript, collect the touch data and let Rust ‘pop’ the touch events - and then map these events to my input system.

For the touch support, I opted for a simple single-touch experience where one can drag a path for the tank to follow and then let an ‘autopilot AI’ handle the driving of the tank. Shooting is handled by simply tapping. Seems to work OK.

some tank game 2021 08 05 112834

Anyways - took me about 10 hours to port my game to the browser including touch support.

The game can be played here.

Rust is awesome!!!

Bevy in the Browser!

July 08, 2021 - Søren Alsbjerg Hørup

After finishing “Some Tank Game” and posting about it I wanted to see how, if possible, I could port this to the web without replacing Bevy.

To get started, I spun up a fresh Bevy project to see if I could get rendering, kira audio, window management and Bevy UI to work in the browser.

It turns out I actually could!

hello bevy web

Source can be found here.

Firstly, not all of the features of Bevy is compatibile with the web, hence first step is to disable the default plugins when targeting web assembly.

This can be done through the Cargo.toml:

[target.'cfg(target_arch = "wasm32")'.dependencies] bevy = {version = "0.5", default-features = false, features = []}

Here we simply disable all optional features.

Secondly, Bevys default rendering backend does not support the Web, hence we need a ‘web specific’ plugin. Luckiliy, I found bevy_webgl2 which provides a webgl2 backend for bevy.

bevy_webgl2 = "0.5.2"

This dependency will pull in bevy_winit and thus allow for Window creation using a Canvas element, bevy_render for rendering and Bevy png support for png loading and displaying.

Thirdly, wasm-bindgen is used to generate the bindings for JavaScript and wasm-pack is used to compile a bundle targeting web using:

wasm-pack build --target web

My index.html simply loads the module as such:

<script type="module"> import init from './pkg/bevy_web_test.js'; var res = await init(); res.start(); </script>

One issue that a struggle with were the fact that my Canvas was fixed sized and unable to resize with the Window. I inserted some JavaScript to force the Canvas to a certain size, but this had no effect of the internals of Bevy - hence my stuff was not rendered properly.

winit apparently does not support this out of the box, so I implemented a web_canvas_resizer system that polls the dimensions of the window and ensures that the Bevy renderer has the correct size.

Lastly, I added a dependency to bevy_kira_audio and saw that kira more or less works out of the box in the browser. Only issue I had were the fact that Chrome will not play sound unless the Window has had some kind of interaction. I found this JavaScript snippet that works around the issue by tracking AudioContexts and ensuring they play when allowed to.

That’s is! Bevy is now running in the browser!

Next step for me is to merge these changes into some-tank-game-rs and see if I can get my game to run in the browser.

"Some Tank Game" - A game implemented in Rust using the Bevy engine

July 05, 2021 - Søren Alsbjerg Hørup

I Finished my first Rust Game - called “Some Tank Game”!

Source can be found here: https://github.com/horup/some-tank-game-rs

The aim of the project was to implement a full game (albeit a simple one) using Rust and using the Bevy game engine.

Why? More or less to prove my gut feeling that Rust is a great programming language to make computer games and that Bevy is an awesome engine with a lot of potential.

The game I implemented is nothing fancy, just a simple top down shooter. The game features four levels, pixel-art graphics, random collected sfx and music by Zander Noriega.

For fun, I tracked every hour I spent implementing the game, including play-testing, debugging, asset drawing, sfx searching, etc.

I started development the 27. of march and finished version 1.0 in the 2. of July. About 3 months of calendar development time. In this interval, I spent 65 hours in total or about 1 hour a day implementing the game.

I quickly got Bevy up and running and was able to draw some sprites. Bevy did not have tilemap support, so I implemented my own tilemap plugin which can render a tilemap consisting of many sprites batched into a mesh.

Bevys plugin system is really easy to work with. Simply define a struct and implement the Plugin trait and one can insert new resources, systems, etc. into Bevy.

The Entity Component System of Bevy is very non-verbose and easy to work with. Any struct (as far as I know) can be made into a component. Systems are implemented as plain functions and can be ‘wrapped’ as a system type for bevy to consume simply by calling <function name>.system(). This operation will fail at compile time if the function cannot be used as a system in Bevy, e.g. if it’s signature does not match the signature of supported functions. Systems run in concurrently and locking of resources are automatically handled. Great!

For the game I needed a collision detection and handling system. Bevy does not provide this out of the box, but due to the plugin friendly nature of Bevy, I quickly found a crate, bevy_rapier2d, that provides collision detection and response directly into the engine using rapier specific components and resources. Integration of this was a breeze! especially compared to implementing my own custom collision detection and handling systems.

For level editing, I used the excellent Tiled editor to construct my levels. Bevy does not support Tiled out of the box, but I found the tiled crate which provides generic Tiled support in Rust. I wrapped tiled in my own asset loader and ‘bam!’ I had Tiled support in Bevy. I later learned that bevy_tiled exists, which more or less does what I implemented - but hey, one less dependency :-)

Another awesome feature with Bevy is the build speed. By default, Bevy and the application compiles into a single ‘fat’ executable. This takes several seconds. However, Bevy also provides the ability to dynamically link to Bevy which reduces the compile times significantly.

I spent a lot of time getting Bevy UI to do want I wanted, specifically to render text in the correct positions and with the correct ordering. For a future projects I think I will opt-out of Bevy UI and instead use an immediate mode API such as egui through the use of the bevy_egui crate.

For sound and music playback I initially went with what was readily available in Bevy, which is more or less a single audio channel and the ability to schedule a wave, mp3 or ogg file to be played. However, I quickly realized that I needed the ability to loop music and also stop and restart a music track whenever a level ended either through a win or a loss. I found the bevy_kira_audio plugin which more or less replaces audio part of Bevy with the kira crate.

Lastly, I created a simple installer using Inno Setup which bundles my assets and executable into a self-extracting installer.

All in all, a fun project with the following post-project reflections:

  • Rust is an awesome programming language for Gamedev.
  • Bevy is an awesome engine for Gamedev currently only lacking in web support and maturity.

Next steps is to see if I can port the game to HTML5, which is one of the goals of the Bevy engine (although still in progress and not yet realized as far as I can see).

some tank game screenshot 1

some tank game screenshot 2

some tank game screenshot 3

Bevy - A Rust Game Engine

March 29, 2021 - Søren Alsbjerg Hørup

In the past months I have been focusing on using the Rust programming language in relation to game development.

I wanted a setup where I could implement a game that could build for both native, such as Microsoft Windows, and WASM, targeting modern browsers such as Chrome.

To achieve this I have been working on a pet project called Blueprint. Intention with Blueprint was to create a Rust template that could be quickly generated using cargo-generate and that provided several features out of the box. Features included:

  • 2d and 3d rendering.
  • many thousands of sprites using VBO batching.
  • entity component setup using Hecs.
  • pre-defined systems such as movement system, physics systems.
  • multiple template games such as platformer, shooter, etc.

My primary motivation was a template where I could quickly prototype game ideas using Rust. Previously I have been using Typescript + PIXI.js or THREE.js. But since I am a huge Rust fanatic, I wanted to see if I could conjure up a similar setup using Rust + libraries such as winit, wasm-bindgen, glow, etc.

Recently however, I stumbled upon Bevy, a data driven game engine written in Rust. Bevy more or less ticks all the boxes above, except for WASM support. I want to build my games such that they can be quickly shared in the browser for other to see, thus WASM is a non-optional thing.

However, it seems that WASM support is a focus area of Bevy and it seems it is currently possible to run Bevy in the browser using webgl plugins, atleast if one uses the master branch of github and not version 0.4 currently published on crates.io.

In any case. I have decided to put my own Blueprint project on hold and fiddle a bit with Bevy before continuing down a path which seems to be well underway by the community!

If all goes well, I can ditch my efforts on my own brewed Blueprint and make a Bevy template!

Laser Defence

February 23, 2018 - Søren Alsbjerg Hørup

I implemented my first ever (finished) HTML5 game called Laser Defence.

I used PIXI.JS v4 and TypeScript for the implementation. Visual Studio Code was used as the IDE.

For fun, I wrapped the project into Cordova and published it to the Google Play Store:

https://play.google.com/store/apps/details?id=dk.hrup.laserdefence

I had some issues with consistent frame-rates using Cordova on my Galaxy S5 phone. The fix was to use the Crosswalk Cordova plugin. This plugin comes with its own Chromium instance, which is far superior to the default webview provided by Android 6.0.

The con is a fatter APK, about 20MB - but the pro is a much more consistent experience.

Screenshot of laser defence!

Over- and under-clocking Refresh Rate

January 25, 2018 - Søren Alsbjerg Hørup

Recently I have been working on a HTML5 game using Pixi.js. One issue I have come across when doing web game programming is that it is not possible to disable vsync to test my game with higher and lower FPS.

The window.requestAnimationFrame() fires before the next repaint and is therefore tied to the refresh-rate of the monitor in use. For a 60hz monitor, the function fires every 16.66ms.

One could create a custom interval timer to simulate different refresh rates. This works fairly well, although the update will for obvious reasons be out of sync with the monitor.

Another method is to change the refresh-rate of the monitor using INI patching on Windows or using GPU tools such as NVIDIA Control Panel. A monitor is designed for a specific refresh-rate, where 60hz is the most widely PC monitor refresh rate.

Depending on the monitor, it is sometimes possible to over-clock the monitor yielding higher refresh rate. Similarly, under-clocking can be use to reduce the refresh-rate. For my 60hz DELL 2515h monitor I can increase the refresh-rate to 80hz before the monitor goes blank.

This allows me to test different frame rates, while preserving vsync, when developing HTML5 games. Similarly, I can reduce the frame-rate by under-clocking the monitor to e.g. 50hz or 30hz.

For NVIDIA GPUs, changing refresh-rates can easily be done through the NVIDIA Control Panel:

refreshrate.png

The Test button will test the refresh rate before adding it to the list. When added, you can select the custom refresh rates from the drop-down menu to the right.

This can be done even when the game is loaded in the browser. A site such as https://www.vsynctester.com/ can be used to verify that the refresh rate of monitor is in effect in the browser.

Photoshop Mockup

October 25, 2017 - Søren Alsbjerg Hørup

I ditched the idea of doing mockups using scripting from Photoshop. The primary reason was that Photoshops scripting capabilities are not great for doing WYSIWYG, i.e. every time a code change is made one has to reopen and reload the script. I had personally hoped for the ability to do F5 refresh of the script without any hassle.

Alas this is not possible. In any case, I actually did manage to produce a Mockup of a Red Alert inspired game using both real-time and turn based mechanics. This mockup was made using Photoshop and conventional tools.

mockup_1

I got heavily inspired by the graphics of the Cmd & Kill game made by renderhjs. Primary inspiration thread can be found at: http://polycount.com/discussion/120427/pixel-art/p10

I got the idea of combining RTS and Turned-based strategy. The concept uses two phases: planning & execution. In the planning phase, one plans troop movements, production etc. In the execution phase, troops move and attack. I made a GIF showcasing the concept.

lvl1

I haven’t really decided yet if I want to pursue this any further - but I believe it can be made to work. Frozen Synapse uses something similar, although this is on a more tactical level compared to what I was thinking.