On the physics of flying snowballs

As living legend Chris Crawford points out in his book The Art of Computer Game Design, any game must revolve around a central concept. So when I started thinking of a new one, the first step was to figure out what the game was going to be about. I had already decided to make a first-person shooting game, simply because they're so immersive, and it's an uncommon perspective in 2D, so it wasn't going to seem too unoriginal. For the same reason, it was also an easy decision to have projectiles with ballistic trajectories. And since martial games where you go around shooting stuff with guns are oh so common, why not simulate a snowball fight for a change?

But in order to do that, we first need to make those snowballs fly.

ballistic snowballz screen

I won't show you the whole code here; it's over 300 lines as of this writing, and going up. Just look at the tech demo for details. Luckily, the physics simulation part is trivial; all we want is to approximate the motion of a body under uniform acceleration. We don't care about the way it rotates (it's a ball...), or its mass (we'll just fudge the forces involved). All we need to know is where it is, and where it's going. We don't even care about its size!

var Physics = {};
Physics.Vector3D = function (x, y, z) {
	this.x = x;
	this.y = y;
	this.z = z;

Physics.Ball3D = function () {
	this.position = new Physics.Vector3D(0, 0, 0);
	this.speed = new Physics.Vector3D(0, 0, 0);
	this.forces = [];
	this.update = function (time) {
		for (var i = 0; i < this.forces.length; i++)
		this.position.x += this.speed.x * time;
		this.position.y += this.speed.y * time;
		this.position.z += this.speed.z * time;

So far, so good. With only 20 lines of code, we can track an object's position and speed. Note the time parameter; our little simulation should be independent of the framerate, so we'll express speed in meters per second and update the position depending on how much time has passed since last frame (it will be a small value, say 1/60). But what about those forces?

Physics.Acceleration3D = function (object, vector, timeout) {
	this.object = object;
	this.vector = vector;

	this.timeout = timeout;
	this.delta_t = 0;
	this.apply_for = function (time) {
		if (this.timeout > 0 && this.delta_t >= this.timeout) return;
		this.delta_t += time;
		this.object.speed.x += this.vector.x * time;
		this.object.speed.y += this.vector.y * time;
		this.object.speed.z += this.vector.z * time;

For the sake of simplicity, I decided to ignore drag and focus on the accelerations. We have two of those: the initial impulse and good old gravity. And as you can see, calculating how speed changes over time under acceleration is trivial. The timeout is simply a convenience feature, so the force will stop influencing our object after a time. Total code required: 35 lines!

(Here I must confess a mistake: for the longest time, I was using the formula for displacement instead of the one for speed, having misunderstood a friend's explanations; you can see the wrong one in the source code of Square Shooter. But you can end up in the same place by tweaking the parameters a little. Such is the beauty of natural laws: they all fit together.)

Not that the calculations are particularly precise. Rounding errors, or perhaps some detail I'm missing, makes it so that changing the framerate results in the snowballs landing closer or further, but the differences are small and easy to compensate for. Besides, for the game I have in mind, little precision is required in the first place. Oh, and speaking of imprecision, the snowball in the tech demo is indeed 20cm across, twice what it should be; that's so you can still see it well at the far end of the playing field.

The rest is just busywork: keeping track of several balls at once, making sure you can throw them just often enough to see two at once in flight, moving around and throwing with each hand in turn. Now, to start working on the actual game for a change...