I wrote my honors application essay for the University of Michigan a few weeks ago, and I really enjoyed writing it, to my surprise. There were a few prompts to choose from, but I chose one that I thought would be interesting to twist in my own way: “Take a complicated idea or object and make it simple.” In response to this prompt, I wrote a ~600 word essay on how to make water using cellular automata, in layman’s terms (for the most part). Without further ado, have a read:
One concept that I have found of continuous interest as a programmer has been that of water. It is a fluid and, as such, it has properties that would seem to make it very difficult to realistically simulate in a fast, simplistic way in a video game or program. Making water fall, splash, or spread outward due to celerity in waves, and still settle into available crevices neatly would appear to require a vast amount of calculation and rendering precision in executing it on even a basic level. In the real world, this liquid interacts on a molecular level, which results in these properties of which we are all familiar. But a program would not be able to run with per-molecule level precision at any kind of reasonable rate, if at all. In programming video games, there exists a constant dance of balancing the game experience with the speed at which it is able to run; in essence, finding elegant solutions to complicated concepts is the hallmark of a talented programmer, and simplicity correlates directly with its running speed and its overall quality. In order to solve these kinds of speed problems with water and still give it the capability to form waterfalls, lakes, and varying water levels, from deep to shallow, on entirely randomly-generated terrain where specific-case implementation is impossible, I use a simple technique called “cellular automata.” This technique divides the aquatic region into squares or rectangles to make a grid where each “cell” can hold a possible amount of water. Each cell has a set x/y position, width, height, and percentage of fill. Using only the last value, the fill of the cell, and rules governing these cellular interactions, we can develop a program in which water is able to act in a naturally fluid manner and behave according to all of the tendencies listed above.
In determining how these different cells interact, it simply comes down to deciding how water would act with the different cells around it in reality; if the current cell has more water than the cells to the left or right of it and at least one of them is not obstructed by an impediment of some sort, then this cell must empty water out into that cell to make both have an equivalent fill value. Also, if the cell below the current cell is not blocked by ground or another obstacle and is not completely filled with water, it must fill up with as much water as it can from the current, higher cell until it is completely full. Then, we simply have each cell draw a rectangle whose height is determined by its fill value, and we have a program where water can flow left and right, as well as by gravity. By using these simple, logical rules and executing them for each of the cells that contain water several times a second, a program can easily handle this method and give an effect that will allow for waterfalls, bodies of water with varying depths, and waves. Also, with a little tweaking, pressure calculations can be implemented to show when water is shallower or deeper. Thus, the daunting task of making water adapt in a predictable fashion to a randomly generated environment is quickly turned into a simple case of taking a step back, looking at how water works in the real world, developing rules that fit the natural manner of a liquid, and manipulating a single value, the percentage of fill, to represent that behavior in each cell of a grid.