# 2D Tile based water using cellular automata.

This topic is 1891 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I've been trying to implement tile based water similar to terraria. I'm using C++ and SDL.
Here is my code for the simulation aspect of the water tiles.
My code is based off this java tutorial (http://w-shadow.com/...uid-simulation/)
 void App::SimulateCompression() { float Flow = 0; float remainingmass = 0; //Calculate and apply flow for each block for (int X = 0; X < MAP_WIDTH; X++) { for(int Y = 0; Y < MAP_HEIGHT; Y++) { int ID = Rect2Lin(TILE_SIZE,X,Y); int Up = Rect2Lin(TILE_SIZE,X,(Y-1)); int Down = Rect2Lin(TILE_SIZE,X,(Y+1)); int Left = Rect2Lin(TILE_SIZE,(X-1),Y); int Right = Rect2Lin(TILE_SIZE,(X+1),Y); //Skip inert ground blocks if(TileList[ID].TileProp == TILE_GROUND) continue; //Custom push-only flow Flow = 0; remainingmass = TileList[ID].Mass; if(remainingmass <= 0)continue; //The block below this one if(TileList[Down].TileProp != TILE_GROUND) { Flow = GetStableWaterState(remainingmass + TileList[Down].Mass) - TileList[Down].Mass; if(Flow > MinFlow){Flow *= 0.05f;} Flow = Constrain(Flow, 0, Min(MaxSpeed, remainingmass)); TileList[ID].NewMass -= Flow; TileList[Down].NewMass += Flow; remainingmass -= Flow; } if(remainingmass <= 0)continue; //Left if(TileList.TileProp != TILE_GROUND) { //Equalize the amount of water in this block and it's neighbour Flow = (TileList[ID].Mass - TileList.Mass)/4; if(Flow > MinFlow){Flow *= 0.05f;} Flow = Constrain(Flow, 0, remainingmass); TileList[ID].NewMass -= Flow; TileList.NewMass += Flow; remainingmass -= Flow; } if(remainingmass <= 0)continue; //Right if(TileList.TileProp != TILE_GROUND) { //Equalize the amount of water in this block and it's neighbour Flow =(TileList[ID].Mass - TileList.Mass)/4; if(Flow > MinFlow){Flow *= 0.05f;} Flow = Constrain(Flow, 0, remainingmass); TileList[ID].NewMass -= Flow; TileList

.NewMass += Flow; remainingmass -= Flow; } if(remainingmass <= 0)continue; //Up. Only compressed water flows upwards. if(TileList[Up].TileProp != TILE_GROUND) { Flow = remainingmass - GetStableWaterState(remainingmass + TileList[Up].Mass); if (Flow > MinFlow){Flow *= 0.05f;} Flow = Constrain(Flow, 0, Min(MaxSpeed, remainingmass)); TileList[ID].NewMass -= Flow; TileList[Up].NewMass += Flow; remainingmass -= Flow; } } } //Copy the new mass values for (int X = 0; X < MAP_WIDTH; X++) { for (int Y = 0; Y < MAP_HEIGHT; Y++) { int ID = Rect2Lin(TILE_SIZE,X,Y); TileList[ID].Mass = TileList[ID].NewMass; } } for(int X = 0; X < MAP_WIDTH; X++) { for(int Y = 0; Y < MAP_HEIGHT; Y++) { int ID = Rect2Lin(TILE_SIZE,X,Y); //Skip ground blocks if(TileList[ID].TileProp == TILE_GROUND) continue; //Flag/unflag water blocks if(TileList[ID].Mass > MinMass) { TileList[ID].TileProp = TILE_WATER; }else { TileList[ID].TileProp = TILE_AIR; } } } //Remove any water that has left the map for(int X = 0; X < MAP_WIDTH; X++) { TileList[Rect2Lin(TILE_SIZE,X,0)].Mass = 0; TileList[Rect2Lin(TILE_SIZE,X,0)].TileProp = 0; TileList[Rect2Lin(TILE_SIZE,X,MAP_HEIGHT - 1)].Mass = 0; TileList[Rect2Lin(TILE_SIZE,X,MAP_HEIGHT - 1)].TileProp = 0; //mass[x][0] = 0; //mass[x][map_height+1] = 0; } for(int Y = 0; Y < MAP_HEIGHT; Y++) { TileList[Rect2Lin(TILE_SIZE,0,Y)].Mass = 0; TileList[Rect2Lin(TILE_SIZE,0,Y)].TileProp = 0; TileList[Rect2Lin(TILE_SIZE,(MAP_WIDTH - 1),Y)].Mass = 0; TileList[Rect2Lin(TILE_SIZE,(MAP_WIDTH - 1),Y)].TileProp = 0; //mass[0][y] = 0; //mass[map_width+1][y] = 0; } } 

The embeded video shows what happens when using this function. I really need help understanding why I'm not getting the same effects as the tutorial. Maybe, guide me on what I could do to fix these issues. I discovered that it has to do with the "flow" and how the masses are not being distributed among the other tiles. Any Ideas?

[Media]

[/Media] Edited by Aaru

##### Share on other sites
I fixed the issues myself(took me a while) here is the final video of it working.
[Media]
[/Media]