Grid-based Particle Movement „Formula“ works incorrectly

I‘ve been having a bit of trouble with this for a while and finally found a solution (more or less).

What i‘m trying to achieve is basically something like a Grid-based Wave Simulation (only that waves would propagate in a curved way, while i try to achieve straight motion, like a particle/wall of particles [instead of ‚)‘ it should be ‚l‘… that‘s the best visual representation i can offer right now :sweat_smile: ]).

Now, the problem lies within a „Formula“ i came up with for this… it works in Desmos, and it should at the very least not behave the way it does for me…

Because, the way it moves a particle is fine when the vector‘s floats are either -1, 1 or 0, but not any other number (float or int)… in that case, the particle moves correctly for a while, until it splits into horizonal and vertical motion in the same direction, so if it started (0.8,0.2) it ends up in the middle right and bottom, with the brighter part being right (in a 4:1 (0.8:0.2) ratio, so at least it somehow kept this…).

What it is supposed to do, is to continue moving and reaching or passing (if started at 50, 50) the position (90,60) at some point, which is impossible if it splits up…

And i just can‘t find the reason for it…
If anyone could point me in the right direction, it‘d be very much appreciated :blush:

As a reference, here‘s the part of the code together with the parts that will display the grid :

Summary

Take Note, that this is written in the iCompiler (iOS) so things like casting, nullpointers in arrays and others are handeled more or less automatically (access on indexoutofbounds just creates new indexes) so there might be things that cause errors… but there shouldn‘t i hope :sweat_smile:

//the method that updates the grid
void update() {
      
      PVector[][] dir2 = new PVector[dir.length][dir[0].length];
      
      for (int x = 0; x < dir2.length; x++) {
         for (int y = 0; y < dir2[x].length; y++) {
            dir2[x][y] = new PVector(0,0);
         }
      }
      
      for (int x = 1; x < dir.length-1; x++) {
         
         for (int y = 1; y < dir[x].length-1; y++) {
            
            float a = dir[x][y].x;
            float b = dir[x][y].y;

            //my Formulae

            dir2[x][y+1].x += a*(b>0?b:0);
            dir2[x][y+1].y += (1-abs(a))*(b>0?b:0);
            
            dir2[x][y-1].x += -a*(b<0?b:0);
            dir2[x][y-1].y += (1-abs(a))*(b<0?b:0);
            
            dir2[x+1][y].x += (1-abs(b))*(a>0?a:0);
            dir2[x+1][y].y += b*(a>0?a:0);
            
            dir2[x-1][y].x += (1-abs(b))*(a<0?a:0);
            dir2[x-1][y].y += -b*(a<0?a:0);
            
         }
         
      }
      
      for (int x = 1; x < dir.length-1; x++) {
         for (int y = 1; y < dir[x].length-1; y++) {
            
            dir[x][y].set(dir2[x][y].x, dir2[x][y].y,0);
            
         }
      }
      
   }

The Grid (the update happens in an extended class, but that‘s just way too long, but doesn‘t do anything to this process, so i’ll just post the basic class)

class Grid {
   
   PVector pos;
   PVector[][] dir;
   
   Grid(float px, float py, int w, int h) {
      
      pos = new PVector(px, py);
      dir = new PVector[w][h];
      
      for (int x = 0; x < w; x++) {
         
         for (int y = 0; y < h; y++) {
            
            dir[x][y] = new PVector(0,0);
            
         }
         
      }
   }
   
   void update() {
      
   }
   
   void display() {
      
      for (int x = 0; x < dir.length; x++) {
         
         for (int y = 0; y < dir[x].length; y++) {
            
            stroke(dir[x][y].mag() * 180);
            
            point(pos.x+x, pos.y+y);
            
         }
         
      }
      
   }
}

And for the rest just use this :

Grid g;

void setup() {
g = new Grid(50,50,100,100);

g.dir[50][50].set(0.8,0.2,0);
}

void draw() {
   g.update();
   g.display();
}

what waveform are you trying to achieve?

@paulgoux While a normal Wave simulation would result in this (not what i want) :

(The part after the slit, not before)

I‘d like to get something like this :

Hope the Images show what i mean… it‘s the best i could find. (Also, i know the images are 3D and i have a 2D grid, but just imagine how it looks like in 2D :sweat_smile: )

Give me a few hours, ill post back later. Also do you have a precise equation you can post?

Not really a precise equation to solve it, else i could‘ve done it :sweat_smile: .

All i got after a lot of trial‘n‘error is this :

            //To set the vector on the bottom
            dir2[x][y+1].x += a*(b>0?b:0);
            dir2[x][y+1].y += (1-abs(a))*(b>0?b:0);
            
            //Top
            dir2[x][y-1].x += -a*(b<0?b:0);
            dir2[x][y-1].y += (1-abs(a))*(b<0?b:0);

            //Right
            dir2[x+1][y].x += (1-abs(b))*(a>0?a:0);
            dir2[x+1][y].y += b*(a>0?a:0);

            //Left
            dir2[x-1][y].x += (1-abs(b))*(a<0?a:0);
            dir2[x-1][y].y += -b*(a<0?a:0);

It‘s the best i was able to come up with…

And it works in Desmos for the respective directions. And it also works in Processing if the values are either -1, 1 or 0 and not other numbers (like -1,0 works, -1,0.5 doesn‘t), i just don‘t get why it doesn‘t also work for floats inbetween -1 and 1, since this works in Desmos…

can you screenshot the desmos graph?

as a starter here is a p3d version, it will allow you to view your graph in 2d and 3d.

int cols, rows;
int scl = 20; //scale
int w = 1200; //width, adjustable
int h = 900; //height, adjustable

int atX = 0;
int atY = 0;

float [][] z;
float [][] X;
float [][] Y;

float moveOffX = 0;
float moveOffY = 0;

void setup() {
  size(1100, 660, P3D);
  frameRate(60);


  cols = w / scl;
  rows = h / scl;
  z = new float[cols][rows];
  Y = new float[cols][rows];
  X = new float[cols][rows];
  float yoff = 0; //small float offset for smooth changes in value
  for (int y = 0; y < rows; y++) {
    float xoff = 0;
    for (int x = 0; x < cols; x++) {
      z[x][y] = map(noise(xoff, yoff), 0, 1, -100, 100); //output of map(last numbers) controlled for height of mountains.
      X[x][y] = x;
      Y[x][y] = y;
      xoff += 0.2;//change offsets to control smoothness.
    }
    yoff +=0.2;
  }
}

void draw() {
  background(0);
  stroke(255);
  fill(111, 222, 55);

  translate(width/2, height/2); //prepares to rotate everything relative to center of window
  rotateX(radians(45));


  translate(-w/2, -h/2); //offsets beginning of coordinates so that all of them appear in the screen.

  //TRIANGLE_STRIP: LAND
  for (int y = 0; y < rows-1; y++) {
    beginShape(QUAD_STRIP);
    for (int x = 0; x < cols; x++) {
      //vertex(x*scl, y*scl, z[x][y]*scl/10);
      //vertex(x*scl, (y+1)*scl, z[x][y+1]*scl/10);
      //text(X[x][y],X[x][y]*scl, Y[x][y]*scl);
      vertex(X[x][y]*scl, Y[x][y]*scl, 0);
      vertex(X[x][y]*scl, (Y[x][y+1])*scl, 0);
    }
    endShape();
  }

  for (int y = 0; y < rows-1; y++) {
    for (int x = 0; x < cols; x++) {

      if (x == atX && y == atY) {
        fill(255, 0, 0);
        pushMatrix();
        translate(x*scl, y*scl, 0); //the addition makes the ellipse not intersect the mountains for the most part.
        ellipse(0, 0, 19, 19);
        popMatrix();
      }
    }
  }

  //these are the coordinates now. I can control these to control the thing's movement.
  atX = int(map(mouseX, 0, width, 0, cols));
  atY = int(map(mouseY, 0, height, 0, rows));

}

Thanks, but i‘m doing it in 2D intentionally, so that i have a better time using it on touchscreen. Implementing a 3D version is pretty complicated to maneuver in with just touchscreen (if you want to have other functionality as well).

I have to admit that I’m not 100% certain what you’re going for, but hopefully this suggestion will help you come up with new ideas for your formula: Have you considered using sin or cos to calculate the height of the wave?

edit
Not sure it will work for a grid system, but I have faith in you :joy:

edit 2
Example of what i had in mind to create a ‘wave effect’:

float a = 0.0;
float inc = TWO_PI / 40.0;
float waveHeight = 120;

void setup() {
  size(800, 400);
  noLoop();
  strokeWeight(4);
}

void draw() {
  background(250);
  translate(100, height/2 - inc);
  for (int x = 0; x < 600; x += 2) {
    float y = sin(a) * waveHeight;
    point(x, y);
    a += inc;
    waveHeight -= .4;
  }
}
1 Like

What i‘m trying to achieve is a Gridbased „Fluid Simulation“ that doesn‘t spread out the forces. As an (pretty terrible but best i could do) example, i made these… things.

This is how a normal Fluid simulation spreads out the force and creates a wave :

image

While this is what i‘m trying to achieve :

image

I know the Images are pretty bad, and the first one starts from a point while the second from a line, but just imagine the first wave to have a line in between the 2 sides of the wave, that‘s how a fluid simulation spreads the force from a line…

And i just can‘t figure out how to get a straight motion… it seems incredibly easy, but whatever i do, it doesn‘t result in the motion being continued…

Imagine for example many points on a line from (65,15) to (35,85) with each point having the velocity of (0.7,0.3) (positive y being downwards like in Processing), then the point that is at (50,50) will have to move through the position (85,65) after 10 steps.

Here‘s an image of that :

Blue = Point A
Green = Point B
Red = (50,50)
Orange = Red‘s position after 10 steps
Black = Red‘s position during the 10 steps
Purple Lines = A/B‘s position during the 10 steps

I hope this explains what i‘m trying to achieve :wink:

Now, i just can’t get it to work, even though the concept should be relatively straight forward… i tried for maaany hours and nothing works… though i‘m not good at math/geometry anyway, so maybe i‘m just not using the correct technique to get the right answer…

This is a plane wave. This can be done in a different reference frame to start and then you can rotate your sketch to give the impression of a motion along a different angle. I will show you what I mean in the code below. If you still want to use trig functions, it is a bit more work but not too complicated.

Kf

//===========================================================================
// FINAL FIELDS:
final float HALF_LENGTH=50;

//===========================================================================
// GLOBAL VARIABLES:
ArrayList<PVector> points;
boolean isPaused=false;
float currentStep=0;
float deltaX=5;
float deltaY=0.5;

//===========================================================================
// PROCESSING DEFAULT FUNCTIONS:

void settings() {
  size(400, 600);
}

void setup() {

  textAlign(CENTER, CENTER);
  rectMode(CENTER);

  fill(255);
  strokeWeight(2);
  //noLoop();

  points = new ArrayList<PVector>();
  initLine();
}

void draw() {
  background(0);

  translate(width/2, height/2);
  rotate(map(mouseX, 0, width, -PI, PI));

  if (isPaused==false) {
    setLine();
  }

  //Show sketch's center (and pivot point)
  stroke(255);  //White
  strokeWeight(3);
  point(0, 0);

  showLine();
}

void mouseReleased() {
  isPaused=!isPaused; //Toggle
}


//===========================================================================
// OTHER FUNCTIONS:
void initLine() {
  currentStep=0;
  setLine();
}


void setLine() {

  float x = -HALF_LENGTH;
  float y=currentStep; 

  points.clear();
  while (x<=HALF_LENGTH) {
    x+=deltaX;    
    PVector vec = new PVector(x, y);
    points.add(vec);
  }

  // Increases ypos + deltaY and resets the value back to zero when it leaves the sketch
  currentStep=  (currentStep+deltaY)%(height/2);
}

void showLine() {

  //Show line's center
  stroke(255, 255, 0);  //Yellow  
  point(0, currentStep);

  stroke(255, 0, 0);  //Red 
  strokeWeight(1);

  for (int i=0; i<points.size(); i++) { 
    PVector v = points.get(i);
    point(v.x, v.y);
  }
}

That is very close to how it should look like, only that i can‘t just use rotation, because i want multiple such lines to interact (like in a wave simulation). That‘s why i‘d need to use the actual Math for it, but nothing i tried worked… the line either dissipates, or randomly splits into multiple lines, or just spreads out in all directions or doesn‘t do anything/vanishes instantly…

I‘ll try to find some equtions for plane Waves and try to implement them. Thanks for the help :wink: