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.
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.
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.
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.