“If you’re going to build it in the browser, you better have a good reason for doing it.” — me, who has never built a browser game, to anyone who will listen
I’ve always been fascinated with how games are built specifically for their medium. Things like Mario Galaxy, the PS1 Final Fantasy games, and even the original Halo were clearly built for the platforms they were released on. That kind of appreciation for your medium can separate a good game from a great game. This is also true for browser games.
Inspired by the classic browser game ‘You Only Live Once’, I set out to build a game specifically for the browser. My idea was to find a way to load assets into the browser window so it looked like the player was actually building out the playable area in the browser depending on where they went. The problem was, I had no idea how to build a browser game. The few days I allowed myself to build this game became only enough to explore one interesting idea, but now it’s one I am hellbent on continuing to explore.
A fellow Javascript developer recommended the much heralded open-source HTML5 game framework Phaser to try out my idea. I picked up Phaser and started playing around for a day before deciding to begin in earnest. Here’s how I taught myself how to do load assets in the browser based on the player’s movement, and one way you can start playing around with Phaser’s super robust, super flexible engine.
Note: Before reading this, I recommend you go through the excellent Making your First Phaser 3 Game tutorial, which will help you get a bit more familiar with how Phaser functions. That being said, I will do my best to explain some of Phaser 3’s key components throughout this piece.
A Rough Start
I loaded up Phaser 3’s examples game library where I was able to experiment with different types of games they’ve built. I really liked that the Breakout game had a loss condition for the ball going off screen, so I tried playing around with that to see what I could do with the way the configuration (config) for a scene worked in Phaser.
This was a mistake.
What I tried to do here is reset the Y-coordinate the ball needs to reach to trigger the loss condition. That doesn’t change the visible image size, rather, the loss condition would just be met a few moments after the ball went past the visible canvas. After doing that, I attempted to render the entire scene when the ball goes past the original canvas size, but before it reaches the new loss condition. That meant each moment the ball met its loss condition it would load up an entire scene. After this failed experiment, I dived into the documentation and caught up on how Phaser 3’s scenes worked.
Assessing the Situation
Scenes in Phaser 3 are essentially decentralized game worlds that can be run in parallel within the same instance of a game, but they have their own logic and conditions, allowing them to function as a single game by themselves. Scenes in Phaser 3 are a lot more powerful and decentralized when compared with scenes in Phaser 2, where they had to adhere to the concept of a ‘Game World’. Instead, scenes can be managed by a global ‘Scene Manager’, which allows for super dynamic development options by handing the power of state management to these individual scene nodes rather than the entire ‘Game World’. Structurally, where Phaser 2 is more of a centralized system of financial ledgers, Phaser 3 operates more like blockchain.
Scene configs in Phaser 3 have a load, create, and update stage. The first two happen only once, and the update function has its own more complicated loop that it follows afterwards. What’s important about the update stage is that it is where the game runs. The endless ‘re-render’ that allows games to function is that update stage.
With all that said (and documentation read), I now understood that it was the assets within a scene that I’d need to load, not the scene itself. I switched from the breakout game to the tutorial game I made since I had more knowledge of the code, its win conditions, and the player sprite’s access to the world bounds. I started to mess with the bounds collisions and made it so that an asset would load on the rest of the canvas once the player’s position was past the visible bounds.
Finishing the Hat
I set the size of the canvas from 800 X 600 to 1200 X 600, then I dropped a couple of things into a conditional statement in the update function:
And I let it rip:
So what just happened? I created a loading effect by generating different assets based on player position. Because I expanded the canvas size, certain areas in the browser window appear blank, when in reality they just have no assets loaded in them. This creates that world building effect based on the player’s movements.
However, there’s still one problem remaining that is fundamental to the effect I am trying to create: I don’t want the extra worlds to be navigable until the player, and only the player, navigates there. That means I want all enemies and collectables to not only remain within the bounds of the visible canvas but behave as if the visible canvas is all there is until the player suspects there might be more world worth exploring. If anything gives away that there’s more to this browser window without the player discovering it for themselves (barring a gentle hint), then the magic will be lost.
Right now, the image of the sky and the platforms will only render visible when the player walks near the edge, but there are no collisions at that edge, so the enemy bombs that populate the game can bounce back and forth between the visible and invisible canvas. I had an admittedly hacky solution ready for this: Create objects with collision physics that border the edge of the canvas, and have those objects (and their collision physics) vanish when the player touches them, then render the appropriate scenery and platforms with their own corresponding collision effects.
Here’s the code that created the borders I needed:
The above was written within the create stage of the Phaser scene. Using the platforms object I built in the tutorial guarantees collision physics with the player, and I set its visibility to false so there’s no danger of the player seeing this artificial border. Theoretically, I could load in my own border objects that have their own collision effects going forward, and allow them to be malleable enough that I can use the setScale property to create really specific borders that make the game’s world (aka the scene) more dynamic in how it renders.
Here is how I set the update function so that the border both disappears and no longer has collision physics:
The moment the player reaches the 780 mark (by the way, I had to set it to 780 even though the asset loads at 800 due to the size of the player sprite’s collision box), that Border1 constant will no longer have a functioning ‘body’, so no collision effects.
Now let’s see how this plays out when we introduce objects other than the player:
Woo! The bombs can only go past the edge when the player decides to explore that area, otherwise, they are bound to the visible game world.
These are seeds of what I hope to one day be a game that lets the player build out their browser window through exploration. It shouldn’t be too hard from here for other users to start exploring the way Phaser allows you to easily load, create, and then manipulate assets to their advantage.