Bipp, A Music Game Engine


So a funny thing happened: I forgot I made this blog. Not that there has been a ton to report on. My explorations into platform games and pixel art were certainly fun, and I'd love to return to them someday, but I didn't really have much of a game idea, so I kinda stopped working on Blorp.

Now I'm working on another weirdly-named game, Bipp, though this one at least is named after something. Bipp is a music game engine that runs in a web browser. It has pretty standard “rhythm-action” gameplay as seen in DDR, Beatmania, Guitar Hero, etc. It also includes a song editor, with an interface inspired by the StepMania editor, that makes it easy to create note charts for songs.

Demo

If you've played other music games before, you can probably figure this demo out. Use the SDF[space]JKL keys to play the notes from left-to-right.

Design Details

I've been wanting to make a music game engine for a really long time, since I love music games. I have a few different ideas of what could be done with an engine like this - a music game in the vein of DDR or StepMania is the most obvious, and what I've been working on at the moment, but there are some other ideas I've been toying with (like creating a drum tutor, inspired by Rock Band's surprisingly-realistic drumming).

Rather than just build a generic engine, I do really want to build a game with this. Ideally, I'd find some music with a unified theme and build a game around that. I wanted to make a PC Music game at one point, but now all those artists are on real record labels like XL and Sony that would probably not be happy with me serving a bunch of MP3s of their music, and I don't exactly want to go licensing music for my goofy free video game.

Right now, I've just been using Undertale music, which hits the sweet spot of “sounds great, fun to chart, fun to play, and I have MP3s of it.” But it's a commercial soundtrack, and while I've been serving up one song for the demo of the engine, I still don't exactly have the rights to distribute it. I'd love to make an Undertale music game, but I'd either have to find a way to license the music, or license some of the remixes/remakes the community has made of the music (some of which would actually work better in a music game, and some of which is even Creative Commons-licensed!).

One idea I've had is to use some sort of streaming service as the source of the music, so that I don't have to host MP3s. It's reaaaallly hard to time music playback from an embedded widget like Soundcloud or Youtube provides such that it syncs with game playback, though.

Technical Details

When I started the project, I had considered making it in Coquette like I had my previous games, using canvas for all rendering. However, I realized it would be significantly faster and easier to create the editor interface (the first piece I built) in React, using SVG to render the core chart. Since then, I've replaced the SVG-rendered chart with a Canvas-rendered chart for significantly better performance, but around the Canvas-rendered chart is a lot of plain ol' DOM elements.

React components are used for all rendering. Even Web Audio playback is handled through a React component (since audio playback can sort of be thought of rendering, in a weird way!).

Components receive state as you'd expect, through Redux. The core “run loop” of the game is implemented as a class that dispatches a Redux action on every tick. This causes the playback reducer to calculate how much to scroll the chart, check if you've missed any notes, etc. Gameplay actions like playing a note are also Redux actions.

There is one funny quirk to re-rendering that's a bit different from most React/Redux apps. Originally, all components were connected to Redux using the traditional react-redux decorator, which causes a component to re-render the Redux store state it depends on changes. However, I realized that this meant that the chart would be re-rendered for both the “runloop tick” actions and for other Redux actions like playing notes, which is unnecessary - with the runloop being 60fps, re-rendering any faster than that is pointless. It was also detrimental to performance, since re-rendering the chart is relatively expensive.

So, I just added a little sub/pub system to the runloop so that the chart component just re-renders on runloop ticks. Again, I only did this change for the chart, since the chart is always re-rendering on tick anyways - enabling it for other components would cause them to unnecessarily re-render (since not all the components depend on the state that changes every frame).

Unfortunately, I still have yet to reach perfect performance on all devices - it seems “jittery” in Chrome on the Macbook Air I've been developing it on. It does run at 60fps in Firefox and on other devices, and for the few people I've enlisted to playtest it, and when I add an internal FPS counter, it reports 60fps. I suspect I might be encountering a Chrome rendering bug - I've seen some issues around VSync in particular - that are causing it to seem jittery even if it is technically hitting 60fps. Still investigating that.

Code

Right, so, here's the code: https://github.com/thomasboyt/bipp

If you're particularly adventurous, you can make your own song by copy-pasting the demo song. You'll want to change the title/artist/MP3 in index.js, as well as the bpm field in the chart files. Then you can navigate to localhost:8080 and click the “edit” link next to the chart you want to edit. There's an editor manual in the README that should get you started.

As I start to build an actual game out of this, I'm going to be working on finding a way to split the “game data” from the “engine data,” so the engine bits will stay generic. Not sure what that will look like yet. I've already got a separate repo for the Undertale songs I'm working on that's included as a submodule under songs/, but I need to add a similar setup for the game's interface and graphics.