The Fish Are Too Smart - a js13k retrospective
Looking back, I'm not particularly proud of how I did in previous years' competitions. My first year, I entered a very rough prototype that didn't even attempt to meet the theme. Last year I didn't even submit my entry at all (in fairness I was battling against acute clinical depression, but I still regret not submitting something). This year has been a good one though - not that my game is the best thing I could have made, nor is it likely to do particularly well in judging, but it is complete, it follows the theme, and I've had a lot of fun doing it.
Adrift is a game about the loneliness of being lost at sea. You have to struggle against the elements and even against your own boat to get it to go the way you want to go. There's little to find out on the ocean - other than somewhere out there, the key to returning home.
One of my favourite stories about this year's entry comes near the end, at the stage that no-one likes to subject their projects to - editing. Some people like to code up to the file size limit, but I prefer to build the thing I want to build and then pare it back. I end up doing a little more work that way, but it does stop me from making poor structural decisions early on that stop me from adding things later. This is the story of the fish.
The fish in Adrift don't actually do anything, or at least don't do anything meaningful in terms of gameplay. In a way they're almost illusory objects, scenery with a basic AI that exist mostly to give the player a sense of place and something to look at that isn't the monotony of the ocean.
I sort of went down a rabbit hole for a while with the fish. After discovering a very neat little method to get them to swim in a sufficiently fishlike fashion (effectively using 1-D noise), I thought about how I could make their behaviour more realistic. The obvious candidate was to add some sort of flocking (or, in this case, shoaling) behaviour. Flocking is a simple behaviour that is governed by small number of rules that apply to each member of the flock, governing their alignment, their cohesion, and their separation. This makes it a fantastic candidate for AI as it's quite lightweight but produces powerful visual results.
Then of course there was making them interact with the boat in some way, perhaps avoiding it where possible, and even changing their behaviour based on both the time of day and the weather. There were lots of aspects I fiddled with, trying to get the fish to behave in an interesting and aesthetically pleasing fashion.
All of which was fine, except then I turned my eye to my file size. I was over the limit.
What to cut? I had some sprites I could make smaller, I could probably turn to more efficient zip compression, maybe there was some cruft in my code I could cut. But then it struck me - for all the time that had been sunk into these damn fish, they were objects that the player never interacted with in a meaningful way and ultimately didn't *need* to be smart. They're not exactly notorious for it.
In writing they call it killing your babies. In this case, lobotomising your fish. Out went the influences of the weather and time of day. Out went the interaction with the boat. And out went the flocking. The fish were dumb.
But the fish were still fish, and they still looked like fish, and they still (for the most part) acted like fish. They swam randomly in a fishlike fashion, and sometimes by chance they even looked like they were still interacting with each other and the boat. Perhaps this was good enough? Even in the highest-budget AAA games, designers and AI programmers ask a lot of the player when we give other objects in the game world some kind of AI. We need them to overlook any of a million sins, ranging from picking routes to walk that are either very inefficient or almost prescient, to AI opponents who can't deal with the player taking an unusual strategy, to enemies getting stuck in infinite loops or who never seem to do the thing they're supposed to. In the grand scheme of things, people don't expect fish to be very smart.
In fact it is this expectation of "stupid" behaviour that drove some design decisions in one of my earlier games, Labyrinth. In Labyrinth all of the enemies are undead, ranging from zombies to skeletons to ghosts and wraiths. Each of these is a response to the fact that I'm not the most skilled AI programmer in the world. No-one cares if a zombie walks into a wall sometimes; in fact it sometimes helps to reinforce their mindless nature. Ghosts don't even need to bother pathfinding around obstacles at all!
Ultimately I don't think people will notice the fish. After all, there are far more glaring flaws in my game's design to point at. But it was a decent illustration that sometimes in game development, you can't let the perfect be the enemy of the good, and it's better to ship something that's less-than-ideal than to leave the best game ever made languishing in a folder on your PC somewhere.