Home Blog Index
Joseph Petitti —

Making a 2D game with no art assets

In my last blog post I wrote about the game I'm working on with two of my friends. It now officially has a name, Afterlight Caves, and we're going to be showing it off at the WPI booth at PAX East, February 27 through March 1 2020. In this post I'll talk about how three computer science majors with no artistic ability between them were able to make a decent looking game.

Screenshot of Afterlight Caves

The game's graphics system is powered by the JavaScript Canvas API, which allows you to draw simple lines, circles, and rectangles onto an HTML canvas. Though simple, this API is deceptively powerful, and combining its various features allowed us to make some cool-looking effects.

By combining these simple concepts we were able to make a surprisingly complex game world without any images, sprites, or textures. Every visual element is generated programmatically using only pure JavaScript.

Simple particles

Good looking particles add a lot of excitement and motion to a game, and they can be surprisingly simple to make. In our physics system, all entities have velocity, acceleration, and drag. Using these, we can create simple line-based particles very easily.

Screenshot of Afterlight Caves

Each particle has a lifetime, after which it is automatically removed from the world, an initially high velocity, and high drag. It's drawn as a line with length as a function of its velocity, so it naturally shortens as it slows down until it is removed. This creates a nice spark-like effect that is computationally cheap and snappy.

Glow effect

Cole came up with a cool way to give Afterlight Caves a glowing, neon look. The display manager maintains a separate canvas, called the blurCanvas that's half the dimensions of the main display canvas (so it's only a quarter of the pixels). The filter attribute of this canvas' is set to a string of filter functions:

const blurContext = blurCanvas.getContext("2d"); blurContext.filter = "blur(3px) brightness(200%)";

Each frame, the game world and all entities and particles are drawn onto the canvas. Then, the canvas is scaled to half its original dimensions and drawn onto the blurCanvas. The lower resolution and filter string create the bright, glowing effect we want.

Then, the blurCanvas is drawn onto the displayCanvas, the one that's actually visible to the user. Next, all UI elements (menus, health bars, etc.) are drawn onto the canvas. This prevents text elements from getting blurred. Finally, the canvas is drawn onto the displayCanvas, which has its globalCompositeOperation set to "lighter," placing the regular game world and UI elements on top of the glowing game world.

The front, display canvas
The regular display canvas
The blur canvas
The blur canvas

Splatter effect

When enemies die, they create a nice splatter effect on the floor that permanently sticks around in the game world. This provides satisfying visual feedback for each enemy killed, and leaves a way to tell which areas of the world you've been to before.

These splatters are also generated programmatically, using a separate canvas. The splatterCanvas has dimensions equal to one fourth of the display canvas, so it only has one sixteenth of the pixels. When an enemy dies, it draws several random rectangles at its location on the splatter canvas.

These rectangles are distributed according to the enemy's velocity before it died. If a shot (or bomb) deals more damage than the enemy has health, the extra damage is converted into velocity, creating a nice splatter effect.

Check out displaymanager.js and draw.js on GitHub to see how all these functions work, and try out the game online to see how it looks in motion.