class Ball {
PVector pos;
PVector vel;
float r;
float d;
color col;
float mass;
boolean isDead = false;
ArrayList<Ball> others;
Ball(float r, float x, float y, PVector vel, color col, ArrayList<Ball> others) {
this.r = r;
this.d = 2*r;
this.mass = 10*sqrt(r * r);//r*r//3.21
this.pos = new PVector(x, y);
this.vel = vel;
this.col = col;
this.others = others;
}
void move() {
vel.mult(reduction);
pos.add(vel);
vel.y += gravity;
}
void bound() {
if (pos.y + r > height) {
vel.y = -vel.y;
pos.y = height - r;
}
if (pos.y - r < 0) {
vel.y = -vel.y;
pos.y = r;
}
if (pos.x + r > width) {
vel.x = -vel.x;
pos.x = width - r;
}
if (pos.x - r < 0) {
vel.x = -vel.x;
pos.x = r;
}
}
float x() {
return pos.x;
}
float y() {
return pos.y;
}
float d() {
return d;
}
float r() {
return r;
}
void display() {
noStroke();
fill(col);
ellipse(x(), y(), d(), d());
}
void accelaration(PVector delta, float force) {
PVector accel = new PVector(delta.x, delta.y);
accel.mult(force/mass);
vel.add(accel);
}
void deadSmaller(Ball other) {
if (this.d() < other.d()) {
this.dead();
} else if (other.d() < this.d()) {
other.dead();
}
}
void collide() {
for (Ball other : others) {
if (other.isDead())continue;
if (this == other)continue;
PVector delta = new PVector(other.x()-x(), other.y()-y());
float rr = other.r() + r();
if (delta.mag() < rr) {
float force = spring * (rr - delta.mag());
delta.normalize();
this.accelaration(delta, -force);
other.accelaration(delta, force);
deadSmaller(other);
}
}
}
void dead() {
isDead = true;
}
boolean isDead() {
return isDead;
}
boolean isAlive() {
return !isDead();
}
}
int maxBall = 50;
ArrayList<Ball> balls;
float spring = 100;
float reduction = 0.9991;
float gravity = 0.01;
void setup() {
size(480, 640);
colorMode(HSB, 360, 100, 100, 100);
smooth();
frameRate(30);
balls = new ArrayList<Ball>();
for (int i = 0; i < maxBall; i++) {
addBall();
}
}
void addBall() {
float r = random(8, 12);////2, 4
float x = random(r, width-r);
float y = random(r, height-r);
PVector vel = new PVector(1, 0);
vel.mult(random(5, 10));
vel.rotate(random(TWO_PI));
color c = color(random(360), 100, 100);
balls.add(new Ball(r, x, y, vel, c, balls));
}
void draw() {
background(0, 0, 100);
//fill(0, 0, 100, 40);
//rect(0, 0, width, height);
for (Ball ball : balls) {
ball.display();
ball.move();
ball.bound();
ball.collide();
}
for (int i=balls.size()-1; i>=0; i--) {
if (balls.get(i).isDead()) {
balls.remove(i);
}
}
}
Y2xhc3MgQmFsbCB7CiAgUFZlY3RvciBwb3M7CiAgUFZlY3RvciB2ZWw7CiAgZmxvYXQgcjsKICBmbG9hdCBkOwogIGNvbG9yIGNvbDsKICBmbG9hdCBtYXNzOwogIGJvb2xlYW4gaXNEZWFkID0gZmFsc2U7CiAgQXJyYXlMaXN0PEJhbGw+IG90aGVyczsKCiAgQmFsbChmbG9hdCByLCBmbG9hdCB4LCBmbG9hdCB5LCBQVmVjdG9yIHZlbCwgY29sb3IgY29sLCBBcnJheUxpc3Q8QmFsbD4gb3RoZXJzKSB7CiAgICB0aGlzLnIgPSByOwogICAgdGhpcy5kID0gMipyOwogICAgdGhpcy5tYXNzID0gMTAqc3FydChyICogcik7Ly9yKnIvLzMuMjEKICAgIHRoaXMucG9zID0gbmV3IFBWZWN0b3IoeCwgeSk7CiAgICB0aGlzLnZlbCA9IHZlbDsKICAgIHRoaXMuY29sID0gY29sOwogICAgdGhpcy5vdGhlcnMgPSBvdGhlcnM7CiAgfQogIHZvaWQgbW92ZSgpIHsKICAgIHZlbC5tdWx0KHJlZHVjdGlvbik7CiAgICBwb3MuYWRkKHZlbCk7CiAgICB2ZWwueSArPSBncmF2aXR5OwogIH0KCiAgdm9pZCBib3VuZCgpIHsKICAgIGlmIChwb3MueSArIHIgPiBoZWlnaHQpIHsKICAgICAgdmVsLnkgPSAtdmVsLnk7CiAgICAgIHBvcy55ID0gaGVpZ2h0IC0gcjsKICAgIH0KICAgIGlmIChwb3MueSAtIHIgPCAwKSB7CiAgICAgIHZlbC55ID0gLXZlbC55OwogICAgICBwb3MueSA9IHI7CiAgICB9CiAgICBpZiAocG9zLnggKyByID4gd2lkdGgpIHsKICAgICAgdmVsLnggPSAtdmVsLng7CiAgICAgIHBvcy54ID0gd2lkdGggLSByOwogICAgfQogICAgaWYgKHBvcy54IC0gciA8IDApIHsKICAgICAgdmVsLnggPSAtdmVsLng7CiAgICAgIHBvcy54ID0gcjsKICAgIH0KICB9CiAgZmxvYXQgeCgpIHsKICAgIHJldHVybiBwb3MueDsKICB9CiAgZmxvYXQgeSgpIHsKICAgIHJldHVybiBwb3MueTsKICB9CiAgZmxvYXQgZCgpIHsKICAgIHJldHVybiBkOwogIH0KICBmbG9hdCByKCkgewogICAgcmV0dXJuIHI7CiAgfQogIHZvaWQgZGlzcGxheSgpIHsKICAgIG5vU3Ryb2tlKCk7CiAgICBmaWxsKGNvbCk7CiAgICBlbGxpcHNlKHgoKSwgeSgpLCBkKCksIGQoKSk7CiAgfQogIHZvaWQgYWNjZWxhcmF0aW9uKFBWZWN0b3IgZGVsdGEsIGZsb2F0IGZvcmNlKSB7CiAgICBQVmVjdG9yIGFjY2VsID0gbmV3IFBWZWN0b3IoZGVsdGEueCwgZGVsdGEueSk7CiAgICBhY2NlbC5tdWx0KGZvcmNlL21hc3MpOwogICAgdmVsLmFkZChhY2NlbCk7CiAgfQogIHZvaWQgZGVhZFNtYWxsZXIoQmFsbCBvdGhlcikgewogICAgaWYgKHRoaXMuZCgpIDwgb3RoZXIuZCgpKSB7CiAgICAgIHRoaXMuZGVhZCgpOwogICAgfSBlbHNlIGlmIChvdGhlci5kKCkgPCB0aGlzLmQoKSkgewogICAgICBvdGhlci5kZWFkKCk7CiAgICB9CiAgfQogIHZvaWQgY29sbGlkZSgpIHsKICAgIGZvciAoQmFsbCBvdGhlciA6IG90aGVycykgewogICAgICBpZiAob3RoZXIuaXNEZWFkKCkpY29udGludWU7CiAgICAgIGlmICh0aGlzID09IG90aGVyKWNvbnRpbnVlOwoKICAgICAgUFZlY3RvciBkZWx0YSA9IG5ldyBQVmVjdG9yKG90aGVyLngoKS14KCksIG90aGVyLnkoKS15KCkpOwogICAgICBmbG9hdCByciA9IG90aGVyLnIoKSArIHIoKTsKCiAgICAgIGlmIChkZWx0YS5tYWcoKSA8IHJyKSB7CiAgICAgICAgZmxvYXQgZm9yY2UgPSBzcHJpbmcgKiAocnIgLSBkZWx0YS5tYWcoKSk7CiAgICAgICAgZGVsdGEubm9ybWFsaXplKCk7CiAgICAgICAgdGhpcy5hY2NlbGFyYXRpb24oZGVsdGEsIC1mb3JjZSk7CiAgICAgICAgb3RoZXIuYWNjZWxhcmF0aW9uKGRlbHRhLCBmb3JjZSk7CiAgICAgICAgZGVhZFNtYWxsZXIob3RoZXIpOwogICAgICB9CiAgICB9CiAgfQogIHZvaWQgZGVhZCgpIHsKICAgIGlzRGVhZCA9IHRydWU7CiAgfQogIGJvb2xlYW4gaXNEZWFkKCkgewogICAgcmV0dXJuIGlzRGVhZDsKICB9CiAgYm9vbGVhbiBpc0FsaXZlKCkgewogICAgcmV0dXJuICFpc0RlYWQoKTsKICB9Cn0KCgoKaW50IG1heEJhbGwgPSA1MDsKQXJyYXlMaXN0PEJhbGw+IGJhbGxzOwoKZmxvYXQgc3ByaW5nID0gMTAwOyAKZmxvYXQgcmVkdWN0aW9uID0gMC45OTkxOyAKZmxvYXQgZ3Jhdml0eSA9IDAuMDE7IAoKdm9pZCBzZXR1cCgpIHsKICBzaXplKDQ4MCwgNjQwKTsKICBjb2xvck1vZGUoSFNCLCAzNjAsIDEwMCwgMTAwLCAxMDApOwogIHNtb290aCgpOwogIGZyYW1lUmF0ZSgzMCk7CgogIGJhbGxzID0gbmV3IEFycmF5TGlzdDxCYWxsPigpOwogIGZvciAoaW50IGkgPSAwOyBpIDwgbWF4QmFsbDsgaSsrKSB7CiAgICBhZGRCYWxsKCk7CiAgfQp9CnZvaWQgYWRkQmFsbCgpIHsKICBmbG9hdCByID0gcmFuZG9tKDgsIDEyKTsvLy8vMiwgNAogIGZsb2F0IHggPSByYW5kb20ociwgd2lkdGgtcik7CiAgZmxvYXQgeSA9IHJhbmRvbShyLCBoZWlnaHQtcik7CiAgUFZlY3RvciB2ZWwgPSBuZXcgUFZlY3RvcigxLCAwKTsKICB2ZWwubXVsdChyYW5kb20oNSwgMTApKTsKICB2ZWwucm90YXRlKHJhbmRvbShUV09fUEkpKTsKICBjb2xvciBjID0gY29sb3IocmFuZG9tKDM2MCksIDEwMCwgMTAwKTsKICBiYWxscy5hZGQobmV3IEJhbGwociwgeCwgeSwgdmVsLCBjLCBiYWxscykpOwp9CnZvaWQgZHJhdygpIHsKICBiYWNrZ3JvdW5kKDAsIDAsIDEwMCk7CgogIC8vZmlsbCgwLCAwLCAxMDAsIDQwKTsKICAvL3JlY3QoMCwgMCwgd2lkdGgsIGhlaWdodCk7CgogIGZvciAoQmFsbCBiYWxsIDogYmFsbHMpIHsKICAgIGJhbGwuZGlzcGxheSgpOwogICAgYmFsbC5tb3ZlKCk7CiAgICBiYWxsLmJvdW5kKCk7CiAgICBiYWxsLmNvbGxpZGUoKTsKICB9CgogIGZvciAoaW50IGk9YmFsbHMuc2l6ZSgpLTE7IGk+PTA7IGktLSkgewogICAgaWYgKGJhbGxzLmdldChpKS5pc0RlYWQoKSkgewogICAgICBiYWxscy5yZW1vdmUoaSk7CiAgICB9CiAgfQp9