Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Simulating Water

Credits go to Billybob, CGamesPlay, and Matt Smith for helping out!
This thread is locked; no one can reply to it. rss feed Print
Simulating Water
Onewing
Member #6,152
August 2005
avatar

This is a lot like my Generating a Wind Model thread. I'm still building up to that stage. Right now, I'm working on adding flowing water to the game.

Basically, you have your terrain and one of the functions you can do is add water at any given point of the graph (currently, each graph is made of nodes that each have a height and the amount of water on that node). The water needs to flow appropriately.

My current algorithm works decently, but becomes a problem after a while. Here's what I'm doing, in semi-pseudo-code. :)

add_water:
Calls raise_water (by a defined amount of water) at node(mouse_x, mouse_y). lSegment is set to this node and the update_water function is then called.

update_water:
Moves through linked list of all nodes that have water on them. To keep from tieing down the program, only a segment of the list is allowed during each game loop. lSegment defines where the list needs to update. Each node that does get updated in this function calls balance_water.

balance_water:
Calls moveable_water to find the locations where water can move to. Add 1 to this value to account for current position. Divide the amount of water at the node being balanced by the amount of moveable locations (with the added one). Lower the node to this amount (using lower_water) and add (using raise_water) this amount to each node the water can move to.

moveable_water:
Takes the height plus the amount of water on the current node and sees if it can move to the adjacent nodes' height + water. Calculates which adjacent nodes it can move to.

raise_water:
If the node we are adding water to does not have any water on it, add this node to the list of water (so it can be updated in update_water). Next, add the given amount of water to this node.

lower_water:
Take away the amount of water given. If the amount of water at this node is below 0.01, then set this node to have 0 water and remove the node from the list of water (so we don't have to worry about updating it again).

Like I said, the above works, but has a few problems. One thing that I should mention is the nodes are 1024 X 768 (each pixel is a node). Fortunately, this can be easily changed to 640 X 480 or even 200 X 200 the way I've set up my code. However, I want to try and have as many nodes as possible and the program still function. The algorithm works fine until you've added too much water. Then, via the segmented list, sometimes it takes a long time for some water to be updated, and appears frozen (which is uncharacteristic of real water). Note: the update_water function calls draw(node.x, node.y) for the nodes it updates. This function calculates what the pixel should look like based on how much water is on it and putpixel's it to the bitmap that eventually is output to the buffer and then to the screen.

I've never done any particle work before and all the above was completely experimental. If any one has any advice or if I need to supply more, I would greatly appreciate it. As I was writing this post, I got a few more optimizations that I'm going to try now.

Thanks in advance!

------------
Solo-Games.org | My Tech Blog: The Digital Helm

CGamesPlay
Member #2,559
July 2002
avatar

Instead of each pixel being a node, find the largest convex polygon that can fit in the area and make that a single node. This will work file for areas that already have water, but will be unrealistic as water enters (it will immediately spread the entire area of the polygon). To cope with this, you can enforce a maximum polygon size...

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

piccolo
Member #3,163
January 2003
avatar

i cant picture it is this for 2d or 3d?

wow
-------------------------------
i am who you are not am i

Onewing
Member #6,152
August 2005
avatar

Quote:

i cant picture it is this for 2d or 3d?

Here's a picture to give you an idea of what it looks like (however, this water isn't simulated):

http://comp.uark.edu/~spsilve/terrain.JPG

I believe CGamesPlay has the right idea. I need to find a way to not think of so many nodes, because there's simply too much. Having an efficient way to group will most likely produce the best results and (hopefully) still work under the same algorithm as above. Also, I could add it to the config file how many polygons for the game, which will allow users to set a better settings for their computer.

This is all easier said then done. I'm going to try and figure out how I want to convert this from evenly aligned x,y nodes to convex polygons. I've got some ideas and should be interesting and fun to implement. I'll post here if I make any progress.

------------
Solo-Games.org | My Tech Blog: The Digital Helm

CGamesPlay
Member #2,559
July 2002
avatar

Yes! The fist of knowledge delivers the punch of advice into the face of problems!

I only make these posts so you can post when you make progress, you know.

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Sirocco
Member #88
April 2000
avatar

I'd really like to make some sort of 'flow' setup for my current game, but I'm already pushing a lot of crap on the CPU, so it probably won't ever happen. Right now water flows in the same direction no matter what.

Maybe next game :)

-->
Graphic file formats used to fascinate me, but now I find them rather satanic.

Onewing
Member #6,152
August 2005
avatar

Quote:

I'd really like to make some sort of 'flow' setup for my current game

I love the way water ripples in FB. It's such a nice little feature that's not a necessasity, which makes FB all the more brilliant.

Anyway, I let my current program run on a 100 X 100 graph with a few hills and added some water at different locations. I then went and took a shower, watched some TV, conquered a small country, followed by reading a gardening book while making an ice sculpture of a gnome. When I came back, the water had spread out across the 100 X 100 graph and was continually expanding and contracting across the graph. I was happy to see a few waves form as well. However, 100 X 100 is way too blocky and it still took forever, but it's good to know the algorithm is doing what it is suppose to, so when I switch to polygon nodes it will hopefully be what I want. One problem I did find was the count of nodes. I had a debug message relay to me how many nodes with water were being worked on. It said over 20,000! Now, with a 100 X 100, the max should've been 10,000. I've got some kind of anomaly producing unwanted nodes.

On the topic of polygons, I had a few minutes to write some code. I made a mistake in my recursion that caused each polygon to be too long, but that can be easily fixed. Wish I could work on it, but I'm doing a double shift at work today (and tonight).

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Billybob
Member #3,136
January 2003

Is it possible to reduce your calculations to bitwise operations? If you can do some tricky bitwise operations that work on all the surrounding nodes at once you'll gain an immense performance boost I'm sure.

Onewing
Member #6,152
August 2005
avatar

Quote:

Is it possible to reduce your calculations to bitwise operations?

It might be a lot of redesigning, but I'm sure it's possible. If the current solution doesn't provide the necessary results, I'll definitely look into it.

Here's an update on the polygon status. I've got the polygons, but the algorithm is currently not implemented for using it. Here's a test I did to make sure the polygon's were setting up correctly.

This is a picture of the terrain (with only red as the color, instead of green and blue above...)
http://comp.uark.edu/~spsilve/planet2.bmp

Here's what the polygon creating algorithm produced after translating the pixel by pixel setup to groups of pixels (aka polygon). I dyed each pixel a random color to differentiate the polygons. The random spot of dark blue was me adding water to the mix (and like I said, that is not working on the polygon setup yet). And of course, a few debug messages.
http://comp.uark.edu/~spsilve/planet2a.bmp

Lastly, I thought I'd mention that 51,000 polygons of max area 10 were produced (they are produced by grouping nodes that are relatively close in height). This is a 640 X 480 graph, so originally there'd be 307,000 nodes. Thus, this reduces my work size by about 600%. One foreseeable problem would be as CGames mentioned, in moving from one polygon to the next (especially the ones that turned out long and stringy).

If I get a chance before I head out for vacation, I'll see if I can get the water to work with the polygons instead of at the pixel level. Any comments are always welcome.

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Billybob
Member #3,136
January 2003

Quote:

It might be a lot of redesigning, but I'm sure it's possible. If the current solution doesn't provide the necessary results, I'll definitely look into it.

Bitwise division is crazy fast. If you were to store the water level as possibly a 16-bit integer, and reduce the division to a bitwise division, you'd be running much faster than a floating point division.

I've done water flow before, but I can't remember the exact calculations. Anyway, I think everything is a division by eight, since there is always 8 nodes surrounding each node. This requires a buffer border of nodes that aren't processed, of course. 8 is a bitwise division >> 3
Or you may have to divide by less, for a dampening effect. If so it's a simple matter of choosing a dampening effect that continues the powers of 2. If you want it to take 1 second to balance, at 32 fps, it'd be something like >> 8.
With that you could divide and add all the nodes back into a single 16-bit int, since the max value after >> 8 times 8 nodes is less than a 16-bit int.

Onewing
Member #6,152
August 2005
avatar

Quote:

Anyway, I think everything is a division by eight, since there is always 8 nodes surrounding each node.

Actually, I'm only looking at 4 nodes with the non-polygon algorithm (above, below, left and right). Also, it doesn't always move to the 4 nodes, particularly when a node is higher than the node being balanced.

Nonetheless, I might be able to incorporate a bitwise operation somehow to optimize it. Hopefully I'll have at least some time to work on it tonight.

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Billybob
Member #3,136
January 2003

Quote:

Actually, I'm only looking at 4 nodes with the non-polygon algorithm (above, below, left and right). Also, it doesn't always move to the 4 nodes, particularly when a node is higher than the node being balanced.

I believe with the right calculation it's always 4. I'll have to crack out my research into the topic to be sure.

Onewing
Member #6,152
August 2005
avatar

Alright then, time for a little update. I've got the water acting with polygons now, although there is plenty for me to optimize in the polygon setup. Even with the unperfected setup, it is quite an improvement from the original. One method I hope to implement is the rectfill hack for polygons, somewhat mentioned here.

However, I'm not satisified with the current results. I will probably try to do the shift bits method this weekend as well to compare and contrast. Here's a picture of the reddish world with some water added on. Here, I've made the polygons very small (can only hold about 5-10 pixels in a polygon). You can see on the bottom left there are over 4000 polygons that have water. And yes, the color of the water is still kind of odd, bear with me.

http://comp.uark.edu/~spsilve/terrain3.bmp

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Billybob
Member #3,136
January 2003

Yay! Simulated blood.
Redrum, Redrum.

Matt Smith
Member #783
November 2000

I'm doing something similar in a 3d game. I'm only having nodes at the vertices between the tiles, which vastly reduces the number. The water height is stored as absolute height above sea level, and so the zbuffer is used to decide how far up the slopes (in pixels) the water is drawn.

You could do something similar on your 2d terrain by having nodes every 4x4 pixels or so.

Onewing
Member #6,152
August 2005
avatar

Matt: Sounds cool (and probably a lot more complicated than mine). :) Show us some pics!

Anyway, I've decided to stamp the water simulation process as done. Any optimizations at this point is really just juggling of other features. Thus, I need to move on to the next step of the game, because if I spent all my time trying to make the perfect water simulator (something that has most likely already been done to some degree), I'd never get to the game itself!

I'm not 100% satisified with the results, but considering the scope of the planet, I think it does its job and is reasonably understandable to the user. In the end, I used several methods suggested above. I did end up switching my water heights to integers, but never used shifting-bit methods.

Here's a final pic of a randomly generated planet, followed by a planet that I added some water too. It doesn't ripple, but it does kind of sparkle during gameplay. :)

http://comp.uark.edu/~spsilve/terrain4.JPG
http://comp.uark.edu/~spsilve/terrain4a.JPG

Thanks to all! Get ready for my next thread.....

[EDIT] Okay, I lied. I added some sparkles to rushing water. Here's a planet covered in water.

http://comp.uark.edu/~spsilve/terrain5.JPG

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Go to: