Dropping tiles

Hi,

You probably seen the game I’m developing and the million and one questions I keep asking and get some superb answers to (thanks all :wink: ), one more question to add to my
list is best way or a way of when player digs out a brick that has water below, allow water to fall down, basically blocks of water to fall, kind of move and replace.

W
WW
BBBBB
BBBBB

Moving out a B would give:

WW
BBWB
BBBB

If you get what I mean? Is this some sort of flood fill? I did use flood fill to fill my caves with water tiles in my game.

Thanks

I would scan from bottom to top. Is water above/adjacent to me? if yes move it to here. This then creates a space in the water that also will get filled by the time the scan reaches the empty tile. You can optimize it by only scanning tiles next to water, or by keeping a list of “toDo” tiles, and add newly created space tiles (from water you just moved). This also means however that water can at most travel just one tile per game tick. Or slower if you only do a water scan every 5 game ticks for example.

It also preserves volume.

http://buildanddefend.com/readnews_news_44

heres a good link about water with some more in depth links at the bottom.

I implemented this in a game a long time ago. As delt0r said, you basically update your liquid blocks bottom up. You can check if there is a valid spot to “flow” into on the bottom, or left and right sides of the block (in that order), and if there is the block should flow to either spot randomly, prioritizing bottom because of gravity. This is a bit sporadic and will make the block jitter a lot if it has open room but works in your case. Once a hole is made, the block directly above the hole will fall, and eventually the rest of the water will even out.

Thanks all,

Been thinking of what you have suggested, but still struggling to think how to implement, any advice on how to start with this? The water tiles are held in a 2d array along with all the other tiles in the game, do you have to check each frame if water block has a empty block at bottom/left/right of it? Guess this can’t be right as I’ve probably got around 800000 water blocks at any one time in the game map?
:persecutioncomplex: :persecutioncomplex:

Below shows what I’m thinking (a is air, b is brick - is water)

baaaaaab
baaaaaab
ba-----b
b------b
babbbbbb
bbbbbbbb

baaaaaab
baaaaaab
ba-----b
ba-----b
b-bbbbbb
bbbbbbbb

baaaaaab
baaaaaab
ba-----b
b-a----b
b-bbbbbb
bbbbbbbb

baaaaaab
baaaaaab
baa----b
b------b
b-bbbbbb
bbbbbbbb

You could use sub-blocks. Both Minecraft and Terraria have metadata on their blocks (in the case of Minecraft it’s a 4 bit number, not so sure for Terraria) indicating how tall the water is. Essentially it’s the same principle except you’re “moving” parts of the water.

Thought I’d bump this thread, still no joy with doing this water block falling as not sure when we check for this?

If I were you I would NOT be updating the lot of them at once. If you haven’t already, separate your world into chunks and perform logic only on tiles that are within some sort of distance from the camera, otherwise you’ll bog yourself down.

Hi,

The caves which have water in them are stored in an ArrayList so you could call them the chunks for the water. Checking if they are in view of the camera still requires a big loops to check all these chunks…Does this mean use some sort of binary tree, spatial partioning too?

My main concern is that I don’t know where to begin to move water blocks except checking block above water to see if it is water etc. Basically if player digs a hole out where water was above them, move that block of water down, then I’m stuck…

If I remove a block below some water and then scroll the screen so this is now not in the camera view, it should still update the water…

Thanks

Hi,

Got something working in simulation I’ve done in Swing - hope this helps somebody else, seems ok, of course cannot do real water simulation
as would take some much cpu time up and I’ve not got the math/physics brain for that! Code checked but still could have some bugs in it, anybody improve
it, please let me know!

Thanks


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.*;

public class MainAc extends JFrame {

	static final int WATER = 8;
	static final int AIR = 0;
	static final int ROCK = 1;
	static final int WIDTH = 12;
	static final int HEIGHT = 12;
	static final int FRAME = 1 * 400;

	static int[][] map = { 
		    { 1, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1 }, 
		    { 1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1 },
			{ 1, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 1 }, 
			{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
			{ 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 },
			{ 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
			{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
			};

	public static void main(String[] args) {
		new MainAc();
	}

	public MainAc() {
		super("Water fluid simulation attempt 1");
		setSize(800,800);
		setLayout(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);

		while (true) {
			try {
				Thread.sleep(FRAME);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			moveWater();
			repaint();
		}

	}

	public void paint(Graphics g) {
		super.paint(g);
		drawMap(g);
	}

	private  void moveWater() {

		for (int y = HEIGHT-1; y >= 0; y--) {
			for (int x = 0; x < WIDTH-1; x++) {
				if (map[y][x] == WATER) {
					if (map[y + 1][x] == AIR) {
						map[y][x] = AIR;
						map[y + 1][x] = WATER;
					}
					else if (map[y][x-1] == AIR) {
						map[y][x] = AIR;
						map[y][x-1] = WATER;
					}
					else if (map[y][x+1] == AIR) {
						map[y][x] = AIR;
						map[y][x+1] = WATER;
					}
				}
				else
				{   // air to the right and water left
					if( (map[y][x+1]==AIR) && (map[y][x]==WATER)) {
						map[y][x]=AIR;
						map[y][x+1]=WATER;
					}
					else if ( x > 0) {
						if( (map[y][x-1]==AIR) && (map[y][x]==WATER)) {
							map[y][x]=AIR;
							map[y][x-1]=WATER;
						}
					}
				}
			}
		}
	}

	private void drawMap(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		for (int y = 0; y < HEIGHT; y++)
			for (int x = 0; x < WIDTH; x++) {
				switch (map[y][x]) {
				case ROCK:
					g2d.setColor(Color.orange);
					g2d.fillRect(x * 50, 50 + y * 50, 49, 49);
					break;
				case WATER:
					g2d.setColor(Color.blue);
					g2d.fillRect(x * 50, 50 + y * 50, 49, 49);
					break;
				case AIR:
					g2d.setColor(Color.BLACK);
					g2d.fillRect(x * 50, 50 + y * 50, 49, 49);
					break;
				}
			}
	}
}


Hi,

The code isn’t fully correct, when water moving right, sometimes even though space to move right it doesn’t??

Can anyone see in the code why?

Thanks

New code:


private  void moveWater() {

		for (int y = HEIGHT-1; y >= 0; y--) {
			for (int x = 0; x < WIDTH-1; x++) {
				if (map[y][x] == WATER) {
					if (map[y + 1][x] == AIR) {
						map[y][x] = AIR;
						map[y + 1][x] = WATER;
					}
		
					else if (x>0 && map[y][x-1] == AIR) {  // water and air to the left
						map[y][x] = AIR;
						map[y][x-1] = WATER;  
						System.out.println("Going left");
						
					}
					
					else if (map[y][x+1] == AIR) {   // to the right air?
						map[y][x] = AIR;
						map[y][x + 1] = WATER;
						System.out.println("Going right");
					}
					
				}
			}
		}
	}
	

But right and left are fighting against each other if I have air to left and right of water…

You could make it so it doesn’t move if there’s air on both sides of the water block.

As for your actual game’s water, why aren’t you storing your tiles in a 2D array? That would solve the searching through a list by just choosing which indices to start iterating at.

Hi,

The tiles are stored in a 2d Array, don’t know what you mean here? My map is a big 2d array of tiles. Do you mean just have
a separate 2d array for the water?

As for not moving water if air on both sides, what if you have a water tile on top of another water who happens to have air both sides of it as shown below:

AAWAA
AAWAA <----- Air on both sides of water
BBBBB

How would we get it then to end up as:

AAAAA
AAWWA
BBBBB

Many thanks, appreciate your help with this.

That was what I was referring to for the 2D array (not your Swing example).

Yeah, I see why the not moving thing wouldn’t work now. You could do it so it randomly chooses left or right if there is a space on both sides. Besides, if you’re doing the multi-leveled water it would just try to flow to both sides at the same time, allowing the top block to flow into the bottom.

The water are stored in a cave object hence arraylist just holds caves but all tiles are still stored in my 2d array map.

I can just check and update what the camera sees just as I do when I draw the map.

Any chance you could run my code (swing example) and see how it isn’t fully correct?

I think to make it fully correct, you need to do it how cellular automate is done, basically, store the map into temp array when move water, then back to world map etc…

Thanks

Ran the example with the new moveWater code and it seems to work fine. The drop on the left will move into the hole, the drop in the middle always moves to the middle hole and the other long droplet falls right in.

One issue I noticed: the way the loop works causes the left droplet to immediately go diagonally into the hole since it’s getting updated, moving right, and immediately updated again. A way to fix this is with metadata if the block was updated already. If you were using something like bytes for metadata for your water levels, you could make the byte negative to tell the update loop to not update the block again, and at the end just re-negate the metadata.

Thanks for running this :slight_smile:

I will probably go with this for now, it’s not perfect but nothing is!

Thanks for the idea about metadata, seems plausible.

BTW - which 2d array did you use for demo map?

Thanks

I used this demo map:


static int[][] map = { 
          { 1, 8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1 }, 
          { 1, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 1 },
         { 1, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 1 }, 
         { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 
         { 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 },
         { 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 
         };

Hi,

Got this in my game now, looks pretty good, I run it every frame and still get 60 fps. Obviously the water the camera sees is only updated now the whole game world else the cpu would grind to a halt!

Need to do few fixes on when water passes torch, needs to light up, same with when blank/cave tiles are replaced, need to have their light level updated.

What is good for recording game that doesn’t take up 1Gig?! ??? Then could put a demo up of it running?

Thanks