Need some help in creating a simulation

Hey people! I’m really new to processing and programming as a whole and I’m trying to do a simulation of a terrain with pseudo-realistic river flow logic. Its a 2D array with perlin noise that does the trick for the terrain which is colour coded (every x and y has a random colour attributed to its rectangle in the grid that shows its height/altitude). I would want to know how can I make so that the program knows how to only place “river tiles” when a tile has almost the same colour but higher (in this case, darker) than the next one so the river is in constant downfall. So there would only be rivers where there are inclinations and not just to generate them based in “from this height to this height its river”. The code is as it follows:

int cols,rows;
int scale =25;
int w = 1800;
int h = 950;

float[][] terrain;


void setup(){
  size(1800,950);
  cols = w/scale;
  rows = h/scale;

  terrain = new float[cols][rows];
    float yoff=0;
  for (int y = 0; y < rows; y++) {
    float xoff=0;
  for(int x = 0; x < cols; x++) {
    terrain[x][y] = map(noise(xoff,yoff),0,1,0,255);
     xoff+=0.2;
 }
     yoff+=0.2;
}
}
void draw(){
  noStroke();
for (int y = 0; y < rows; y++) {
  for(int x = 0; x < cols; x++) {
    fill(139,terrain[x][y],19);
    rect(x*scale, y*scale, scale, scale);
}
}

}

Hi @Toninuin,

I guess a naive approach would consist in picking “starting” cells (rectangles) at a specific height or with a specific noise value and, for each of them, find the neighboring cell with the closest height/noise value (either higher or lower than current one). Once found, these neighboring cells would become the new “starting” cells in turn and the previous starting cells would be marked as visited.

This routine can be repeated until either:

  • all neighboring cells are marked as visited
  • no higher (or lower, if going downhill) noise values are found in the neighborhood

Example sketch with annotations in Python mode:

M = 15.0                                  # Magnification
W, H = 1800, 900                          # Dimensions of canvas
w, h = W/M, H/M                           # Dimensions of grid (number of cols & rows)
S = H/h                                   # Step/Cell size
N = w*h                                   # Number of cells
F = .05                                   # Factor of noise
U, L = .9, .15                            # Upper and Lower bounds
K = (-w-1, -w, -w+1, -1, 1, w-1, w, w+1)  # Kernel

visited = set()

def setup():
    size(W, H)
    noiseSeed(54561)
    
    global n_vals
    
    n_vals = [noise((i%w)*F, (i//w)*F) - .05 for i in xrange(N)]
    
    for i, n in enumerate(n_vals):
        if n<L and random(1)>.95:
            descend(i)
    
    for i, v in enumerate(n_vals):
        c = color(v*255, v*255, 255) if i in visited else v*255
        fill(c)
        rect((i%w)*S, (i//w)*S, S, S)
        
        
        
def descend(id):
        
    n_val = n_vals[id] # get noise value of currently examined cell
    
    if n_val > U: return # if that noise value is too high -> return/stop the function
    
    visited.add(id) # else -> mark it as visited
    
    # Find neighboring cells with higher noise values (convolution)
    nbhood = []
    for k in K:
        nid = int(id+k) # neighboring id
        if 0 < nid < w*h and nid not in visited: # if neighboring cell inside canvas and hasn't been visited yet
            nn_val = n_vals[nid] # corresponding noise value
            if nn_val > n_val: # if noise value of neighboring cell is higher -> append to 'nbhood' array list
                nbhood.append((nid, nn_val - n_val))
       
    # If available neighbors, pick the one with closest noise value and explore it in turn   
    if nbhood:
        nxt_id = sorted(nbhood, key=lambda x: x[1]).pop()[0] # pick neighbor with lowest noise difference (just slightly higher)
        descend(nxt_id)

Thanks Solub! I cant express how grateful I am. Could I just ask you something? Can you write it in processing form? (Java). I dont know a thing about Python, I am starting to learn it but Im at the very beggining, sorry for the trouble and extra work but I just couldn’t grasp what you did fully. Thanks a lot, whole heartdly.

really, it’s almost like java

good practice to translate it yourself

I selfishly posted Python code to a Processing Java question so I should be the one apologizing. I would have posted in Java if I was comfortable with it but unfortunately it is still not the case and I don’t have much time on my hands to make the translation from Python.

All I can do is briefly explain the code and break it down into small steps:

  • 1/ compute 2D noise value for each cell in a grid (you did it already)
  • 2/ select one or several cells above a certain noise threshold ( >0.85 for example)
  • 3/ mark it/them as “visited”
  • 4/ get the noise value of its/their surrounding (Moore neighborhood) unvisited cells
  • 5/ filter out neighboring cells with higher noise values (keep only the ones with lower noise values)
  • 6/ pick the one with the closest noise value (just slightly below)
  • 7/ repeat step 3 to 6 recursively
  • 8/ display visited cells (path of river) in a different color

Feel free to post your attempts and ask for help if necessary. Sorry I couldn`t be of more help.