This little prototype began as an idea for a twin-stick shooter in the vein of Super Stardust HD. But while the action in Super Stardust HD takes place on a sphere, I wanted to see if similar gameplay was possible on implicit surfaces.
The idea was that the movement of the surfaces would supply a constantly changing play field. The way the primitives that compose the surface break apart and rejoin supplies a new mechanic to aid in attacking or escaping from enemies. Jumping could also be implemented as a means of getting from one primitive to another.
I already had an old implicit surface library that I made years ago. That took care of drawing the surfaces. On top of that I added some basic navigation and shooting of projectiles.
A great looking enemy for this sort of twin-stick shooter would be a snake or worm, reminiscent of Centipede. And, when prototyping, it’s good to try to implement the most difficult parts first. Such an enemy was the trickiest thing I could think of programming in this environment, so I got to work.
It wasn’t long before I decided this implicit surfaces environment would be a good platform for a collection of mini-games, not just a twin-stick shooter. One obvious possibility is a snake game where you eat food, grow, and try to not run into your ever-lengthening body.
As expected, making a snake move the way I wanted was hard. This video shows one of my first attempts. Notice that the body slides around a lot.
Sliding randomly across the surface, the snake would be too unpredictable. To make such a game playable, and to make the snake look alive, it needed to slide along one unchanging path. Of course, the path would change a little because the surface is changing, always stretching or compressing underneath the snake.
I had programmed the necessary basics for my twin-stick shooter idea. For example, I could already differentiate between an entity’s velocity and the velocity of the surface on which it resided. So I set about solving the problem with a slew of vector math tricks to try to preserve the snake’s curves. I kept making so many corrections to the movement that the code became overcomplicated and hard to think about. I even considered laying unmoving points on the surface that could be used as control points for some type of spline and having the beads of the snake body follow the spline, but this failed too many thought experiments.
The final solution is a two-step process. First, create a polynomial curve between each pair of beads. This curve is defined by the positions of each bead in the pair and a center point. The center point is a weighted average of points indicated by various beads’ positions. The weighting is carefully tuned so that the snake will hold its shape.
Second, a target position is found for each bead somewhere along its polynomial curve. Then its velocity is modified to bring it toward that position. It isn’t brought all the way to that position so the snake will feel more flexible and alive (this is an art project, after all (we don’t need cold, mathematical precision)).
Notice in the video how the path of the snake holds its shape. If you adjust the polynomial weighting one way, curves in the path collapse into straight lines. Adjust it the other way and curves expand.
The next video shows the addition of food. When the snake eats, it gets longer. There is also collision detection, so if the head runs into the body the game resets. The collisions also keep parts of the body from passing through one another. When the surface changes enough to cause different strands to intersect, the collision detection causes one strand to rise off the surface a little and pass over the other. The camera has been modified to face the same direction as the snake’s head and tilted back a little to help the player see what dangers lie ahead.
At this point, it’s actually a playable game. Of course, there is no interface in the video, but you can see the length of your snake printed in the console where you executed the game. This is only a prototype of the difficult programming issues. To make it better you could add fancy graphics, levels, power-ups, multi-player, and anything else you can dream up.
Math is hard.