Jump to content

  • Log In with Google      Sign In   
  • Create Account

#ActualAaru

Posted 04 November 2012 - 03:50 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

#7Aaru

Posted 04 November 2012 - 03:47 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.c...bed/MpouMU62nK4

#6Aaru

Posted 04 November 2012 - 03:47 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?




[media] http://www.youtube.c...bed/MpouMU62nK4[media]

#5Aaru

Posted 04 November 2012 - 03:46 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/embed/MpouMU62nK4

#4Aaru

Posted 04 November 2012 - 03:45 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?




<iframe width="560" height="315" src="http://www.youtube.com/embed/MpouMU62nK4" frameborder="0" allowfullscreen></iframe>

#3Aaru

Posted 04 November 2012 - 03:45 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?




<iframe width="560" height="315" src="http://www.youtube.com/embed/MpouMU62nK4" frameborder="0" allowfullscreen></iframe>

PARTNERS