IN THIS ARTICLE
Subscribe to Our Newsletter
Hunter Loftis is responsible for the Node.js platform at Heroku. When he’s not working at Heroku, he runs PlayfulJS, a website of cool JavaScript code snippets.
One of the better well-known demos on PlayfulJS is a re-creation of the Doom rendering engine in JavaScript. After building this, Hunter was contacted by Warp records about building a first-person shooter in JavaScript.
One of the issues with this request was the timeframe — three weeks to build the game to coincide with an album release, and with a tiny budget. On top of that, the game had to work on desktop, Android, and iOS.
So, Hunter rationalized and decided to accept the project.
“Optimism is an occupational hazard of programming”
-Kent Beck
After accepting the project for what he thought would be a small, indie release, Hunter realized that the artist (Rustie) was huge in the UK and overseas, and this release would be a huge deal.
”That’s when I realized that it wasn’t me helping out this no-name artist… *I* was the no-name artist, and he was giving me an opportunity.”
First Person JavaScript Demo
Hunter built a custom rendering engine for the game that renders about four million rays per second in canvas.
Check out the demo. You wander around a large, procedurally-generated world, and you find golden stones which allow you access to certain songs. There are lots of hidden challenges. In the maze, if you get lost, it plays a song called “Lost.”
“I’m really bad at my own game. I’m not going to solve the maze… because I can’t.”
One month later, Apple introduced WebGL for iPhone and iPad. In addition to learning a lot about trigonometry, Hunter had his game featured in Kotaku.
Application Interfaces Are Becoming More Like Games
3D immersive simulation is not where JavaScript is strong right now, and as a community we need to get better at that. This isn’t just for future applications: animations should be simulations of the real world, not pre-scripted.
Google’s Material UI is great for modern Android apps, whereas JavaScript may appear to be limited to what we can do with existing CSS animations. If you ever try to spend a weekend building a game, you’ll discover that it’s the hardest thing you’ve done in a long time.
“Building a simple game is harder than building most complex web applications.”
We’re going to focus on three areas where JavaScript devs can learn from the game development community.
1. Minimize and isolate state
It’s so easy to attach properties to everything in JavaScript — it’s a very prevalent practice.
Game developers don’t have that luxury.
Rockets are firing, people are shooting at each other, things may be on fire. A game will update its state every 16 milliseconds. Contrast this to JavaScript, where we have arguments over which MVC will update my 1,000 item list faster. Game developers have developed techniques to deal with state that changes frequently.
Originally we had a huge state object that would keep track of speed, direction, and current animation frame. Instead, we used pure functions, which are super powerful.
Pure Functions
The idea behind a pure function is that it has no side effects; it changes nothing. It takes some input and returns some type of output. Instead of creating a huge state object, we created a few pure functions:
var velocity = this.getVelocity(state.x, state.y, state.interval);
var direction = this.getDirection(velocity);
var pose = this.getPose(state.distance);
var frame = this.getFrame(direction, pose);
There are no variables set in these pure functions. We can learn from game developers to use pure functions to remove as much state as you can.
2. Enforce deterministic rendering
If you have state, you should be able to send it to your renderer, and it should be able to render everything based off that data. This is important because it makes sure that you’re encapsulating all your state in your state objects. If you have stage distributed through your application, it makes it difficult to undo and redo, and also save the current state of the application.
In gaming, this is especially important for multi-player games. If your state can’t be transformed into JSON, it will make multiplayer game development more difficult.
3. Separate rendering and simulation
Let’s understand that simulation is what leads to good animation. Modern interfaces require simulation: scrolling with momentum and bounce, or draggable icons with weight, mass and friction
. You have to run a simulation to do these things, but we don’t do that very often in JavaScript. You can decouple rendering and simulation using multiple approaches, including a time accumulator. It sounds complicated, but it’s really not.
Hunter ends the presentation by discussing his favorite bug ever.
Thanks to NewCircle for filming and editing this video. NewCircle provides excellent JavaScript training.