We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I want to make a pixel water physics simulation, and I want to add gravity to the water pixels. This is my code so far:
int[][] map;
int mapWidth = 100;
int mapHeight = 100;
int drawScale = 4;
int tick = 0;
int tickRate = 2;
void settings() {
size(mapWidth*drawScale, mapHeight*drawScale);
}
void setup() {
frameRate(240);
surface.setTitle("Pixel Fluid");
map = new int[mapWidth][mapHeight];
for (int i = 0; i < mapWidth; i++) {
for (int j = 0; j < mapHeight; j++) {
setMap(i, j, 0);
}
}
thread("physics");
}
void draw() {
tick++;
surface.setTitle("Pixel Fluid | " + frameRate + " " + tick % tickRate);
for (int i = 0; i < mapWidth-1; i++) {
for (int j = 0; j < mapHeight-1; j++) {
fill(mapTileColor(i, j));
noStroke();
rect(i*drawScale, j*drawScale, drawScale, drawScale);
}
}
thread("physics");
if (mousePressed) {
switch (mouseButton) {
case RIGHT:
setMap(mouseX/drawScale, mouseY/drawScale, 1);
break;
case LEFT:
setMap(mouseX/drawScale, mouseY/drawScale, 2);
break;
}
}
}
void physics() {
for (int i = 0; i < mapWidth-1; i++) {
for (int j = 0; j < mapHeight-1; j++) {
if (getMap(i, j) == 2 && getMap(i, j+1) == 0 && tick % tickRate == 0) {
setMap(i, j+1, 2);
setMap(i, j, 0);
}
}
}
}
void setMap(int x, int y, int tile) {
map[x][y] = tile;
}
int getMap(int x, int y) {
return map[x][y];
}
color mapTileColor(int x, int y) {
switch(getMap(x, y)) {
case 1:
return #000000;
case 2:
return #0000FF;
default:
return #FFFFFF;
}
}
I want to make the gravity work on a water particle every 2 ticks, so it looks like it's falling. Instead, when you left click to place the water it falls instantly. How can I have a "fixed update" function, where the gravity would only occur every a certain amount of frames?
Answers
in physics() you are copying the top row to the next row down. then you are copying the (new) next row down to the row below that. and then that row to the row below that... do you see the problem?
start from the bottom, move upwards...
@theliquu69 -- @koogs' suggestion
is a simple fix that works really well -- assuming things move down, and never up.
As soon as things start moving in all directions, have two maps -- an old and new. Copy the new to the old, read the old map, write to the new map. Because you never write to the old map you are never updating changes based on cascades of current changes. Separating old and new is how Conway Game of Life implementations work, for example.
@jeremydouglass I solved my problem by splitting the map into 4*4 chunks and breaking the loop, but that results in "tearing" (visible horizontal lines) so I will be switching to your method anyways. I am trying to implement pipes now, on the same type of loop (left>right, top>bottom) but the problem is that when the fluid moves to the right or to the bottom it is basically "zipping" through the pipe with no delay between steps. I tried implementing the separated old and new map, but that still doesn't fix my issue. Is there any solution? If I have to I will post an example.
again this is probably due to 'overlapping copies'
You should post a minimal runnable piece of code that illustrates the problem
@koogs using your method i've fixed the problem by using two separate loops, one for moving up and left, another for moving down and right. Actually using my split-to-chunks it doesn't affect the performance too much.