In mid-2018 I set out to make a a game; simple in concept and simple technically. While it was simple, it still has taken me a long while to actually complete it, as I love to tinker. Below is an attempt to capture, at a high-level, some of the more interesting bits of the project so far.
Concept - July 2018
While sitting in my office, and staring out my window into the nature in my backyard, my mind wandered into game development, as it does from time to time. I wanted to make something and hopefully come up with an idea that was not only simple for me to build, but also enjoyable to build and play. As I watched the weeds in my yard sway with the wind, the idea, or, part of the idea, popped in my head, “What if I built a game based around a plant?”
I grabbed my notebook and began jotting down some word-associations:
plant, weed, grow, flower, rabbit, squirrel, …
When I looked back over the list of words, the one that stood out the most was “grow”. As soon as I focused in on that, the idea came to me:
I will build a game based on a plant growing. The player will have to help the plant grow as high as they can. The player will control the root as it grows down into the ground, and have to avoid obstacles along the way.
Then I began to sketch.
I love pixel art for a few reasons. First, I am incredibly nostalgic for my younger days where I’d play 8-bit and 16-bit games basically every day. Second, because it’s something I feel mildly competent in drawing. The first idea I had was that the entirety of the game’s viewable space would be 64x64. It may stretch in other directions, but the player would only see a screen of 64 by 64 pixels at most. This meant all art generated would be 64x64 pixels, or smaller, to fit within the game’s view space. That also meant I’d have to technically draw less, because of that restriction. Things could not be hyper-detailed due to only having so many pixels to work with.
I began to sketch out a few things that I knew I’d need:
- a stem sprite that was 2 pixels wide, 1 pixel tall
- a “root” sprite that was 2 pixels wide, but 2 pixels tall at its max height
- a “dirt” texture for the background
- a few 8x8 pixel rocks that would be obstacles underground
I wanted the game to be about navigating the plant’s root down through the earth, avoiding obstacles along the way. I also wanted the ground to go on infinitely, allowing the player to rack up high scores as they went deeper and deeper. To add a challenge, I wanted to add multiple types of obstacles that were randomly placed in the path of the root: rocks, bones, moles, etc. I started with rocks, as they were the easiest for me to draw and experiment with.
The player would only have two buttons to worry about: left and right. The way you could control the plant’s root was by moving it slowly to the right, or slowly to the left. That’s it! If you ran into an obstacle, that was a game over.
Code Example: Obstacle Randomness
I wanted the ground that the player was navigating through to have a feel of randomness, but with some kind of defined behavior. It was here that I took an example from Spelunky’s level generation, where a single level was broken up into “chunks” or “rooms” and each chunk had to have at least one exit or entrance to it. Within a chunk, there was randomness added to the position of dirt/enemies.
I devised a system similar to this. I created a bitmap image with tiles in it, of 8x8 pixels each, and if there was a black pixel, put a rock, if there was no color for a given pixel, that was empty. In the future I added red pixels for “bonus pickups” like water.
Why is each tile 8x8 pixels? At the time of building the bitmap images, a rock was the largest obstacle, and they are 8x8 pixels. If the game world is 64x64 pixels, a rock takes up 1/8th of the width, so I only needed to keep track of 8 position (horizontally and vertically) to place a single rock within that 64x64 game world. So if a black dot was at pixel position (0,0), the top left, we’d center a rock at the game-world position of (8,8) to be centered within that top-most grid position. Similarly, if a black dot in the chunk bitmap was at pixel-position (2,3), that would translate to a game-world position of (24,32), and we’d place a rock there, centered vertically and horizontally over that point.
The code responsible for picking a “chunk” tile from the tiles above, and adding the objects to the game world is below:
Pretty simple. You’ll notice that
_buildChunks is capable of building multiple chunks at once, if necessary. I will cover that next as I go over how I built the never-ending underground.
Code Example: Endless Growth
As the player’s root moves down every frame, we need to make sure there is “dirt” and obstacles waiting for them. To do this, we need to dynamically grow and populate the dirt with a random set of obstacles before the player even knows that the world is about to end outside of the game view.
It’s actually quite simple now that I’ve shown how I generate one or more “chunks” to be built from a pre-selected layout of obstacles.
Here’s the code:
On each frame, the
update(rootPosition) method is called, and we’ve passed in the current location of the player (e.g. the “root” position). We then determine if we are about to run out of dirt below the player, and if so, we add a few more “chunks” onto the game world, and populate it with obstacles via the
_buildChunks method shown previously.
It’s not much more complicated than that. There’s still a handful of features and game elements that are presently a work in progress, and I hope to get to them in the near term.
You can play the game right now, if you head over here:
Some things I still need to code, and refine:
- Expand game window to fill mobile screens. Be more responsive.
- Add some game-over animations/graphics.
- General code cleanup/refactoring now that the core mechanics are clearly defined.
- Performance improvements / Reduce the number of draw calls I’m making to the canvas
- Release as a Facebook game using Phaser’s “Instant Game” api