Building Progressive Web Games Part 3

This is the hardcore part where we’ll take a stage and start creating the game. Lights, camera, shapes, textures, animations and everything begin with this part 👇. Let’s quickly take a deep dive on getting a 60fps game working in super simple javascript code.

Prateek Bhatnagar
6 min readAug 31, 2017
starting to stitch all our parts together

For recap’s sake, this is a game where you swipe to keep a jumping ball on the platforms while the ball moves forward. In order to achieve this, we’ll begin with a simple canvas stretching to the entire screen. This canvas will then be handed over to BabylonJs which will do the rest of sorcery.

Setup:

In order to get started I have installed BabylonJs and CannonJs like 👇. Also I’ll be using separate imports from Babylon in order to help it get tree shaken.

Here are the first few basic steps:

1.) 1st thing we do here is to initiate the game engine and construct a scene. Now imagine this scene to be standing inside a dark black box with nothing besides.

2.) Next, we put lights in this scene so we can see the objects whatever we are putting in this scene. I chose a hemispheric light, which acts up like a lamp in a room and lights up the entire space.

3.) After this ,we’ll need to stand somewhere on the room from where we will watch the game. This is where cameras come in. I am choosing a fixed camera as this game does not allow you to change your viewport but there are other cameras like ArcRotate, FreeCamera etc.

4.) Before we go any further we need to start calling `scene.render` in render loop. This is a BabylonJs scene is refreshed. Also, think of this as a hook where you can implement something like a “pause” functionality.

5.) We are now good to put a simple object in this empty space, so we begin by putting a sphere in here, which will act like our ball.

6.) And after this let’s try creating a simple box under our ball and a put it in simple for loop + a randomized function to layout the initial stage.

This is how our scene looks right now

The scene is set with a sphere and boxes and nothing fancy

Note: in order for a cleaner code I have broken my game logic into 3 classes. A. The Game scene, B.The Ball, C. The Platform. While all the logic described is the real code, but you just might have to look into one of the three class files.

Let there be animations

If there’s a game there has to be animation.

Now there are two type of animations we will do for this game

  1. Simple key based animations for our objects.
  2. A tad complex manual frame by frame animation for user input.

Keyframe based animations: For a keyframe based animation you just tell the set of keys, which are basically just milestones between 0 to N keyframes and the property which will be affected by these keys. E.g. A bounce animation of the ball will have 2 set of keys, one will control `position.y` and other `position.z` like 👇

simple bounce animation for our ball

Box’s drop and appear animation is a combination of two set of keys controlling position.y and opacity.

we will start the box animation in a loop to give consecutive falling effect

Render cycle animation: In this method, we put our code in a callback function after which we call the render function of BabylonJs. I’ll come back at this later when we’ll start handling user input.

We’ll use simple animation for our box’s drop and appear animation and our ball’s bounce animation.

Note: I have placed all the animation keys in a separate animations.js file.

Physics OMG 😵:

If you would’ve ever thought of creating a game, one of the many horrors that would’ve come to your mind would have been the gigantic amount of work needed to replicate real world physics. E.g. Gravity, Angle of collision, Restitution, Elasticity of collision and so one. Luckily some genius developers already got us covered(I mean we’re still writing jS, do you really think someone wouldn’t have made a library for this already). Enter CannonJs, a physics engine which covers multiple shape physics, collision mechanisms, gravity, physics imposters and some more alien tech.

We’ll use the collision and physics imposter part of this sweet library at our disposal.

You can think of “physics imposters” to be like invisible objects around your shape which help detect collisions or apply forces on your shapes and objects. And they are super simple to use.

We’re keeping mass as zero for all our objects to avoid gravity acting upon them.

Here’s what it means, now we’re able to bounce the ball and detect its collision if it lands on the next platform. Once we detect the collision we just need to restart the ball’s animations and increase our score by one. And if no collision is detected the ball will drop down and we’ll add an event to detect this and tell the user he/she has lost.

User Inputs:

As described in the animations section, for user inputs we’ll manually do some animations in our render loop, just before calling this._scene.render(). Our aim here is to make the ball respond to user’s swipe left or right.

Now BabylonJs follows different dimensions and viewport sizing factor and your pixels won’t really map 1:1 points on the canvas. Hence I decided to take a reference point in the beginning and then factor down the swipeDistance on mouseMove by a certain factor which felt fit for the game.

touch based factoring for swipe control

After this one thing that you can do is that just update the x position of the ball instantly, but this will make the game super duper easy. So rather I made a small piece of code that will add or subtract a small value from the ball’s “x position” and hence maintaining a mid level difficulty.

👆with this in place being called in our render loop, we’re good to go with the whole thing.

Upon intersection I fire a callback to preact code which displays the score on the DOM and upon the lost event fired I fire another callback, to display the re-play fab button.

final game play video(excuse the frame-rate plz)

Trial run:

So now I decided to try my game. I landed on the home page and opened the dialog for Guest login, and being a perf freak I started the performance recording in dev tool. When I went to the play route, stood for some time in front of a white screen and then my game stopped. And to my horror, the gigantic loads of BabylonJs & CanonJs did this to my timeline

a gigantic wait for 6s in the time when everyone wants everything super quick!!! One word: Unacceptable.

But not to worry, a super small fix known as prefetch will balance out things for us. so in our head section, I added a <link rel=prefetch.../> which started my download on a low priority and by the time my user checks out the home screen, enters the name or authenticate with Google our bundle would’ve been downloaded. And this would make our timeline happy again 😄

After you have added a prefetch expect some delta in your initial render time but that’s to balance the overall UX.

Note to Service Worker:

I am using preact-cli-sw-precache to add runtime caching configuration to preact-cli. With my service worker my aim is to have a minimal pre-cache resources, so that it quickly takes control of the page. Later on whatever resources are requested from the controlled page, our service worker will cache them on runtime with cacheFirst strategy.

Conclusion:

So we have our game’s start screen up and running ~3.5s and the stage setup(start of web-gl loader) with a delta ~2s. And if the browser has Service Worker all of this drops by several notches from consecutive visits. Also, the user will be able to play this irrespective of network availability.

We have reached a point where its a full fledged working game with a perfect Lighthouse score.

If words like analytics and ads do not excite you, this is all the series had it for you. Because there’ll be one last round of changes adding open collective based ads and some analytics.

Github code: https://github.com/prateekbh/hopon/tree/part3

🍻Hope you had good time reading the series.

--

--

Prateek Bhatnagar

Web-dev @ Google/ PreactJS! Trying to build a better mobile web