This follows on from the previous articles "Emulating Biological Systems - 1 of 2" and "Developing Biological Emulation Using a Generic Turn-based Testbed", which defined the underlying components needed to model an aquarium and the development tools that would allow it to be developed and tuned. This final article carries this through to developing the AI.
The Limited Animation Model
From the previous articles it can be seen that the emulation of the Aquarium system has been factored down to a viable universal and limited system to represent it. In the real world the variation and complexity of motion and physical distortion of a fish is infinitely varied and complex. Trying to match the real world one-for-one was never going to be practical, so the previous article defined a limited system that would allow all fish to fit within a single restricted framework.
The reader is recommended to look at this in "Emulating Biological Systems - 1 of 2", which shows how all fish animation is mapped down to major animation types with interconnecting animations. The range of possible animation states is therefore very restricted, but enough to represent all the behaviours needed.
The other major restriction is collision detection. If collision detection
was based on the real shape of the fish, then modelling large numbers of fish,
or modelling on limited platforms, would be too costly in processor time.
The final model adopted used connected bounding spheres, which gives a good
Mapping One Model to all Fish
A key to this system's success is that a single fish emulation model must be shared by all species. This means that parts of this model need to be configurable so that different behaviours can be emulated with a single engine.
Now this may sound like it might be a science, but much of this requires trial and error and intuition. In practice each fish is controlled by 91 parameters that govern fish behaviour. In practice, while a fish is being developed, the configuration file can be tweaked and re-loaded, to see if the tuning is realistic. This is an attractive and flexible system, as it generally allows a new species to be added without needing any added game engine changes.
The Flexible Animation and Physics System is there, so now the AI Falls into Place?
A pity but not so! The next step is creating an artificial fish that behaves like a real fish. After trying to string behaviours together it is easy to see that it can decay into distinctly unfish-like behaviour. Until you impose fish characteristics, these objects are no more than fish-shaped ball bearings. When traversing open empty space it is not hard to randomly switch between animations and have something that looks plausible. It starts to fall apart when fish meet barriers and other fish.
When fish meet obstacles, such as the corner of the tank, or other fish, this can result in fish getting stuck. Two fish swimming into a corner may find that the first fish cannot easily move, but the fish behind may not give way. This problem can occur even with forgiving obstacles such as just the side of the tank! When you start to introduce complex objects and many fish, then the problems multiply. It is easy to create logjams where many fish get stuck in some awkward position.
The solution is having fish remove themselves from the stuck position. This highlights an immediate limitation that the fish can only do what a real fish would do. Shuffling them around to just re-arrange them is not an option. Fish cannot reasonably turn and swim vertically upwards, as fish do not generally do that. If there are a number of fish involved, it might also be tempting to have some cooperation, so that fish voluntarily remove themselves to allow other fish to get free. However this is a hacky and dangerous solution as you get sucked into the dynamics of what is an unrealistic system. Fish are generally probably selfish, and do what they want to do, not what helps the group.
Centring the AI on Single Fish
The practical basis for this to work is to treat each fish as an autonomous unit, with no understanding of what other fish are doing. This is a reasonable basis and focuses on creating behaviour that is linked to the information that a real fish is exposed to (i.e. they cannot mind-read).
Given this a fish needs to make decisions. Of course, these robot fish, by default, do not care what is happening, so if they all end up squashed in the corner unable to move, then this is as good as any other outcome. To avoid this, fish are generally given the aspiration to make progress. Each fish type will (by configuration) have inclinations to swim fast, slow or to turn in varying proportions. Once a fish is starting to get stuck it needs to notice this and try and change the situation.
Fish Self Awareness
The easiest thing a fish can do is notice where it is and compare this with where it was before. To do this it tracks recent and longer-term average positions. If a fish finds that it seems to have not changed its position for a while, it then starts to actively change this.
Now this leads to more complexity. A fish may try turning to swim in some new direction, but this may fail. It might fail because collision danger stops it even trying. Even if it can turn, it may still be stuck. The fish needs several techniques and needs to track the success of these. If turning fails, then try swimming upwards.
This leads to fish working though options until the fish position changes. However this can lead to further strange behaviour as a fish stuck in some region finds that it oscillates between two positions.
Here the fish, when in some moderately confined space (here limited by bounding spheres, but actually representing Aquarium objects), can be fooled into believing it is making progress, whereas it is simply getting stuck between two positions.
This requires longer term tracking, but also requires good solutions. The fish might try one of (say) 5 manoeuvres to try and get unstuck, but all these may fail, The fish needs more flexibility. To do this it needs to multiply up its options by combining them. If it has 5 basic manoeuvres, then this becomes 5x6 = 30 possible behaviours (allowing each pair and single manoeuvres as a distinct activity). A fish may then turn and drift upwards (lateral movement). If this is also randomised, a fish can eventually find its way out.
Of course, there are other inputs to this. One is the time that a fish allows for a manoeuvre to work. It might try turning a bit and give up, but should have tried harder. All this is down to tuning and allowing fish to try quick and longer solutions. This still has to be constrained: if a fish looks like it is trashing, trying all kinds of movement, this does not look good. A fish may try and then give up for a while, in case the situation later changes (a blocking fish may move away).
Tuning the System
This comment perhaps belongs in the previous article and "Developing Biological Emulation Using a Generic Turn-based Testbed", but is worth a mention here. To develop this behavior requires setting up test positions. In the image above we have a fairly complex environment with a difficult shape. You can set a fish in this, and watch it in accelerated time to see if it copes. We also set up much more challenging environments, wholly unrealistic with very little space, simply to test the fishes ability to avoid getting jammed. From this the AI was tuned until fish could cope with anything, and do this while still looking like they are fish.
Group Behaviour - Shoaling
We indicated above that fish are treated as autonomous entities, so it may sound like this cannot cope with group behaviour. Shoaling is such behaviour, and again this required no group control. Each fish does its own thing, but if inclined to shoaling, it can modify its behaviour to try and follow other fish.
This works very well. Fish only try and follow fish they can see and in each case chooses the nearest fish in front. Added to that the fish may choose to not shoal, or just get too far behind, so may break away. This results in quite attractive and plausible behaviour, and it is fairly captivating watching some 100 fish to see what happens. With a medium level of shoaling inclination you can easily find that you have several loose shoaling groups, which may at times either split up or join another shoal. It is not hard to start attributing this behaviour to being that of some real live entity, in which case you wonder "why did that fish do that?".
This has been a very interesting project, where success or failure can be measured by instinctive assessment. It comes down to "Does that look real?". Of course the article here picks up on just a limited number of specific details: the whole project has significant added complexities, but the elements above are core features of the system.
We are now planning to take this system on to the next level, with more lavish and complex systems. Watch this space!
Jeff Rollason: November 2007