Jump to content

View more

Image of the Day

#ld38 #screenshotsaturday Mimosa Fizz action gif #2 https://t.co/TUzdppvfUL
IOTD | Top Screenshots

The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.


Sign up now

2D Tile based water using cellular automata.

4: Adsense

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.


  • You cannot reply to this topic
1 reply to this topic

#1 Aaru   Members   

224
Like
0Likes
Like

Posted 04 November 2012 - 03:43 PM

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[Left].TileProp != TILE_GROUND)
   {
	//Equalize the amount of water in this block and it's neighbour
	Flow = (TileList[ID].Mass - TileList[Left].Mass)/4;
	if(Flow > MinFlow){Flow *= 0.05f;}
	Flow = Constrain(Flow, 0, remainingmass);
	TileList[ID].NewMass -= Flow;
	TileList[Left].NewMass += Flow;
	remainingmass -= Flow;
   }
   if(remainingmass <= 0)continue;
   //Right
   if(TileList[Right].TileProp != TILE_GROUND)
   {
	//Equalize the amount of water in this block and it's neighbour
	Flow =(TileList[ID].Mass - TileList[Right].Mass)/4;
	if(Flow > MinFlow){Flow *= 0.05f;}
	Flow = Constrain(Flow, 0, remainingmass);
	TileList[ID].NewMass -= Flow;
	TileList[Right].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?




http://www.youtube.com/watch?v=MpouMU62nK4&feature=youtu.be

Edited by Aaru, 04 November 2012 - 03:50 PM.


#2 Aaru   Members   

224
Like
0Likes
Like

Posted 20 November 2012 - 12:08 PM

I fixed the issues myself(took me a while) here is the final video of it working.





Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.