Aiming marbles away from a central point

I have a sketch that simulates marbles bumping into each other. Each marble has one PVector for ‘location’ and another one for ‘velocity’. location.add(velocity) moves the marble to it’s next location, slowly for small velocities, quickly for larger ones.

I’d like to create a small group of marbles clustering around some random point, with random initial velocities but all pointing straight out/away from the middle of the cluster.

Below are the main pieces pulled out of the rest of the sketch. It just places the marbles but doesn’t move them around, decrease their velocities, etc…

Any help setting the velocities to point outward from ‘r’ would be huge!!

class MovingPoint {
  PVector location, velocity;
  MovingPoint(float x, float y, float xv, float yv) {
    location = new PVector(x, y);
    velocity = new PVector(xv, yv);
  }
}

MovingPoint [] points;

void setup() {
  size(800, 600);
  ellipseMode(CENTER);
  points = new MovingPoint[10];
  for (int i=0; i<10; i++)
    points[i] =  new MovingPoint(0, 0, 0, 0);
  initializePoints();
}

void initializePoints() {
  // pick a semi-random point as the center
  PVector r = new PVector(random(200, 600), random(200, 400));
  for (int i=0; i<10; i++) {
    points[i].location.x = r.x + random(-50, 50);
    points[i].location.y = r.y + random(-50, 50);
    // how to set the velocities pointing out/away from 'r'?  
  }
}

void draw() {
  background(225);
  stroke(0);
  fill(0);
  for (int i=0; i<10; i++)
    ellipse(points[i].location.x, points[i].location.y, 10, 10);
}

void mouseClicked() {
  initializePoints();
}

Hi! If you have no idea what to start with, I recommend you to read Dan’s book or watch his videos to get familiarized with vectors
https://natureofcode.com/book/chapter-1-vectors/

tip: how you initialize the point will end up with points forming a square (you will find it if you increase the number of points). If you want a circular distribution, check out random2D, which returns a vector with a random angle and a unit length. Then you can scale the vector with a random value.

Thanks a ton micuat!

I ended up using polar coordinates to aim the marbles straight out from the center. Here’s the rework in case it helps anyone else-

class MovingPoint {
  PVector location, velocity;
  MovingPoint(float x, float y, float xv, float yv) {
    location = new PVector(x, y);
    velocity = new PVector(xv, yv);
  }
}

final int NUM_POINTS = 10;
MovingPoint [] points;
PVector center;

void setup() {  
  size(800, 600);
  ellipseMode(CENTER);
  points = new MovingPoint[NUM_POINTS];
  center = new PVector();
  for (int i=0; i<NUM_POINTS; i++)
    points[i] =  new MovingPoint(0, 0, 0, 0);
  initializePoints();
}

void initializePoints() {
  float radius = 50; // radius from center to marbles
  float degrees = 270; // top
  float dx = 360.0 / NUM_POINTS;
  // pick a semi-random point as the center
  center = new PVector(random(200, 600), random(200, 400));
  for (int i=0; i< NUM_POINTS; i++, degrees+=dx) {
    float x = center.x + radius * cos(radians(degrees));
    float y = center.y + radius * sin(radians(degrees));
    points[i].location.x = x; 
    points[i].location.y = y;   
    // calculate the point twice as far out as this one (going straight out)
    // ... and set the velocity equal to the difference
    // (so one "location.add(velocity)" moves this marble twice as far out)
    points[i].velocity.x = (center.x + radius * 2 * cos(radians(degrees))) - x;
    points[i].velocity.y = (center.y + radius * 2 * sin(radians(degrees))) - y;
  }
}

void draw() {
  if (millis() < 1000)
    ((java.awt.Canvas) surface.getNative()).requestFocus();
  background(225);
  stroke(255, 0, 50);
  fill(255, 0, 50);
  ellipse(center.x, center.y, 5, 5);
  stroke(0);
  fill(0);
  for (int i=0; i<NUM_POINTS; i++) {
    MovingPoint p = points[i];
    ellipse(p.location.x, p.location.y, 10, 10);
    // add one pass at the velocity to see where the marble is headed
    line(p.location.x, p.location.y, p.location.x + p.velocity.x, p.location.y + p.velocity.y);
  }
}

void mouseClicked() {
  initializePoints();
}

yay! This is the way that is similar to random2D and makes a nice distribution too. You can also randomize the radius or you don’t have to.

By the way, if you do a bit more of math, you notice that the velocity is actually

points[i].velocity.x = radius * cos(radians(degrees));
points[i].velocity.y = radius * sin(radians(degrees));

but either way works :slight_smile: The repulsion force (this case velocity) is a difference between the two points (where the force is applied - where the center is) so actually the position of PVector center doesn’t affect the velocity and only the offset (this case cos/sin * radius or in the previous case random(-50,50)) matters.

1 Like