Original Photo by Ajeet Mestry on Unsplash, edited by me.

I wrote a videogame in Javascript and this is what I learnt.

Ignacio Segura
CloudBoost

--

I just wrote a videogame in ES6, React and MobX during a parental leave to up my Javascript game. Long story short, I did.

This is the game:

Android version: https://play.google.com/store/apps/details?id=es.niknak.bouncerback

Play in browser: http://bouncerback.niknak.es/

If you want to up your Javascript game, there are plenty of quality resources out there. There are all kind of free tutorials and affordable courses. I went thru some of these sites and I found top class material, well thought-out lessons and clear examples on how to do things such as a simple to-do list.

Booooooring.

So I decided to write a videogame because “why not”. I had a good concept. It was simple, doable, and it would give me the opportunity / obligation to do my best. And boy, what a journey it was.

Planning

I like many different types of videogames, but when we’re talking about creating, I’m the minimalism itself. All I want is the most solid concept I can think of, completely skinned down to the bone and expressed in its purest form. With the best sound I can make. At 60 fps.

With such an idea, I planned the execution and checked the technologies I wanted to use before putting them into my project. For any library/framework/whatever to be added to the project, it had to fulfill two requirements: 1 — it had to be helpful, letting me do more with less. 2 — It had to be worth learning for the future, so they had to be key players in top projects, or expected to be top players quite soon.

Those were the things I needed

A system to transition from initial screen to gameplay, game over screen, etc. Enter React.

A system to automatically render the scoreboard, timer and such. In a declarative way if possible, I should not need to tell the scoreboard “hey, dude, time to render yourself again, numbers have changed”. Again, React: a React component with a couple props did the job.

A way to keep the information accessible for any component that needed it, but protected. An application store that is also able to notify components that data has changed and they should render the changes again. Miss popularity Redux was dropped for the more simple, thinner and more straightforward MobX, which was able to work with and without React equally well, and it did a hell of a job here.

A graphical system. Three possibilities were considered: Canvas, SVG or plain HTML elements. While HTML was enough, there was nothing to learn there, so I went for SVG and for sure I learnt. A few cool things, and a couple crappy browser quirks too. More on this later.

Audio. Oh, a lot of fun here. While I discovered the new Web Audio interface during the work on the game, I considered it overkill for my purposes. Good old core Audio class was enough.

ES6

If you’re like me (read: old), the transition to ES6 was uphill. Yes, the changes are so big that it doesn’t even look like the same language. Yes, you will have to trash a lot of stuff. Yes, Javascript advocates are a pain in the ass with their endless enthusiasm for the “JS flavour of the month” or for JS finally being able to do awesome things that C++ has been doing, no sweat, for fifteen years.

But, in spite to this bunch of overenthusiastic dicks (dudes, seriously, get a life), the transition is actually for the good. You can do more with less verbose stuff and your code will look tidier, more simple and more readable on the long run. I just find ES5 to be ugly now. Just ugly.

And for the record, the transition is not that complicated. It’s just that many tutorials out there are written for people who doesn’t need these tutorials. You know what I’m talking about, right?

React.js

React has the ability of making difficult things easy, and some easy things quite difficult. The key here was to remember that React was built to make user interfaces. In other words, draw interactive stuff on screen. Everything else is extra fanciness and if you try to go there, you’re trying to go outside React’s reach, which is always a bad thing. While React is the biggest pain in the ass you’ve ever seen at first, with sooooo many things that make you bang your head against the table, with the many articles out there that make you understand less after reading them… it’s extremely productive once you understand it and you use it JUST FOR ITS ORIGINAL PURPOSE. In my case, once I had a structure, building every new game screen took minutes. The Game Over screen, the level selection one… I could even “improvise”, implementing new ideas on the fly. As soon as I realized I needed a new screen, scoreboard, menu or button, I built it in minutes using React.

Anything inside the circle was vanilla JS. Anything outside the circle, React.

It takes weeks to be able to make things in React in minutes, but this moment eventually arrives. Simply don’t struggle against it. Consider React a graphical rendering engine and nothing else. Don’t try to use it for anything that is not rendering stuff and your life will be much less miserable. If you need logic, move it somewhere else. Vanilla JS or whatever. In my case, I created services, lots of them. Background, soundtrack, mouse control, touch control, clock, game events, text overlays… everything was its own service. A vanilla JS class with its own methods. That approach proved to be both productive and easy to extend / debug.

MobX

I love this one, for several reasons. One of them is because it’s the underdog against Redux, and I love underdogs. Another reason is that MobX is not Redux, and I hate Redux.

But what does MobX do, in plain english? MobX solves this problem: suppose I need a way to store the information about the current state of my application (example: I have 5 bananas) in such a way that when something changes (ex: I now have 6 bananas), whatever it needs to be recalculated is automatically recalculated, whatever component needs to be notified about the changes is automatically notified, and whatever has to be rendered again, is rendered again immediately, like magic.

MobX does that, and it solves that problem in a very elegant way. If you have something that needs to be watched for changes, you label it as “observable”. If you need something to be computed every time an observable changes, you label it “computed”. And if you need something to happen automatically when one of those “labeled things" change, you put those changes inside a function named “autorun”. That’s it. MobX does more things, but this basic stuff covers most of the scenarios.

One of my game’s stores, the one controlling scores, lives and other stuff. Score is recalculated whenever “bounces” or “captured” changes, and the scoreboard is re-rendered automatically. React’s diff mechanism does the rest.

For my game, MobX controlled the game clock, the score, the remaining lives and other essential data for the game. Highly recommended.

SVG

Let’s use vector graphics, the support has to be good, it’s 2018, for God’s sake.

Man, I was so wrong.

The thing is, I didn’t need SVG graphics. My game is so simple that Divs and CSS was all I needed. I just used SVG for the sake of using SVG and learn something along the way. And I learned, man, that being 2018 is not enough.

The hard way.

I learned that an SVG object has its own coordinates system, and its zero point is locate top left of the <svg> container. So any element inside this SVG will use this point of origin for any transformation, including rotation. This is not what I needed, so I looked out a bit and I learned that you can set an object as the coordinates origin using the CSS property transform-origin … but Firefox will simply ignore you.

Firefox. Not IE9. No. Latest Firefox. Hello 2018.

The solution, actually, is to put an <svg> inside another, and the browser will use the inner one’s top left point as coordinates origin. So if you ever see an <svg> tag inside another, that’s why.

Another thing I learned is that you can set or alter some SVG attributes such as width, height, fill, strike and such using CSS properties. Veeeeery convenient. But not all of them. Not radius. OK, my game is all circles and lines and I can set all attributes for my elements using CSS… All them but the radius of a circle. In 2018. Because Firefox. Again.

That’s when things become funny. As I couldn’t modify an SVG circle’s radius using CSS, i used a CSS 2D transform, which did the work as expected. But then, for the purpose of the game, I needed to know the final size of the element after transform. Easy peasy, I can use JS native method getBoundingClientRect() for that. Only that Firefox AGAIN doesn’t report the right size. To be precise, it gives you the size of an element on screen before applying a CSS scaling transformation. What’s the point of that?

No worries, I can read CSS tranform matrix and do some math. BOth Chrome and Firefox report the right data here. All good.

Enter Safari.

Safari does NOT report the right data for the CSS transform matrix. None. Empty. Void. Zero. But, adding humiliation to pain, it does draw the object as expected. Pixel perfect. So you apply a CSS transform to an object, Safari does good. Then you ask Safari via JS, “hey, what’s the CSS transform you just applied to that element?” and Safari responds “what transform, I didn’t do such thing” and you say “what? I see the element, transformed, perfect sized, right on my screen” and Safari says “I don’t know what are you talking about.

True story. But thankfully, in Safari getBoundingClientRect() works as expected, so I ended up doing a very hacky thing I hate: using different logic depending on the platform. I used getBoundingClientRect() first, and if the output didn’t make any sense, then I read the transformation matrix.

In 2018.

Oh, and the icing of the cake: adding a glow effect to the balls in the game killed my CPU. Five circles with a very simple CSS box-shadow glow effect was enough to start losing frames. In my computer. Five tiny circles. In 2018. In a computer capable to run the latest Doom at full swing.

Phonegap

My first objective was for the game to be playable with only mouse or trackpad in a browser. Once I got there, I wanted to make an Android version.

Phonegap happened to be a really fine tool for that, if you have experience using the command line. I’m not saying you’re not gonna find problems, you’re going to find LOTS OF THEM. But all of them are documented. And, at least when you’re targeting Android, debug is a breeze. You don’t even need to install your app in your phone to run it, you can install Phonegap Developer in your phone, run Phonegap emulate in your computer, and if both devices are in the same Wi-Fi network, your phone will be able to get the app from your computer. Awesome.

More awesome: if you connect the device to your computer with a cable, you will be able to use Chrome debug console, exactly the same way you use it to debug a website.

Just remember that if you try PhoneGap, you will see the word “Cordova” everywhere. What is that? Cordova is Phonegap’s engine, that is: Phonegap makes Cordova make things. Consider Phonegap the command center for Cordova. This also means that if you want to do something with your app that requires access to some of your phone’s functions, you will need to install a Cordova plugin, not a Phonegap plugin.

Audio

Audio is fun because making electronic music means staring at blinking lights. This is my setup, BTW.

It all can be summarized by quoting my friend Daniel:

Awesome! Although I know you did all this just to have an excuse to make the music.

And yes I did. I will say no more about the subject.

Now, back to business:

Showing the creature to the world

Premiere day! I put my game on my phone and my laptop and attended a local games developer event where people were showing their latest creations. Here it was, my little minimalistic humble creature, sharing space and attention span with other people’s creations, written in serious engines like Unity, Unreal Engine and Godot. My little Javascript thingy was simple, but it run smooth and flawless. It wasn’t native, but it felt native, and that’s what mattered.

The guy with the best summer shirt in the event was testing my game next to me.

Takeaways

Quite often, the problem with some of these technologies is usually not the technology itself, but how it is explained. MobX happened to be a fine piece of software, but the examples and the wording could be more simple. Besides that, most of the examples I found said “you can use MobX with vanilla JS or any framework you like, let’s show you with an example… using React”. Always, always React. If MobX had better, more simple and direct to the point examples, I’m positive it could be much more popular.

Also, Phonegap, which by the way scared me at first, happened to be a powerful ally. If you make your app work fine in Chrome, it will work fine as an app, at least on Android. I don’t trust Safari enough to say anything about iOS.

Finally I knew graphical performance in JS is poor, but I didn’t know how poor it was. If you’re looking for smooth animations at 60fps, SVG stuff inside an absolutely positioned DIV, despite sounding like the most simple solution, performs poorly as soon as you add a little bit of eyecandy. I suggest people who needs real performance to research Canvas and WebGL first before taking a decision. Even for very simple stuff, plain SVG in a DIV won’t cut it.

Besides that, I have come to love ES6 to the point that I look at old Javascript and I find it disgusting. ES6 is cleaner, leaner and less cumbersome. It just makes more sense to me now. The only missing bit is the Elvis operator. I don’t really need it, but don’t you want something named “Elvis operator” in your preferred programming language, just because?

--

--

Graphic design nerd focused on all things visual and interactive. Currently working as consultant for World Bank.