I have been working from the following example provided by the user Andrew Thompson -> Collision detection with complex shapes
I have attempted to implement this in my program (code below) in the method 'draw' but for some reason the statement to change the colour of the square to "Red" will never evaluate as true and I can't fathom why; I have tried almost everything at this point but lacking further help from Andrew I don't seem to be able to progress in correctly implementing this code so that when the flock of triangles come into contact with the square, the square changes colour to Red.
Any and all help is greatly appreciated (code below):
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.*;
import static java.lang.Math.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.Timer;
public class Boids extends JPanel {
Flock flock;
Flock flock2;
final int w, h;
public Boids() {
w = 1200;
h = 600;
setPreferredSize(new Dimension(w, h));
setBackground(Color.black);
spawnFlock();
new Timer(17, (ActionEvent e) -> {
if (flock.hasLeftTheBuilding(w))
spawnFlock();
repaint();
}).start();
}
public void spawnFlock() {
Random rand = new Random();
int n = rand.nextInt(599) + 1;
flock = Flock.spawn(100, h - n, 20);
}
@Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
flock.run(g, w, h);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Simulator v0.6");
f.setResizable(false);
f.add(new Boids(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class Boid {
static final Random r = new Random();
static final Vec migrate = new Vec(0.02, 0);
static final int size = 3;
final double maxForce, maxSpeed;
Vec location, velocity, acceleration;
private boolean included = true;
Boid(double x, double y) {
acceleration = new Vec();
velocity = new Vec(r.nextInt(3) + 1, r.nextInt(3) - 1);
location = new Vec(x, y);
maxSpeed = 3.0;
maxForce = 0.05;
}
void update() {
velocity.add(acceleration);
velocity.limit(maxSpeed);
location.add(velocity);
acceleration.mult(0);
}
void applyForce(Vec force) {
acceleration.add(force);
}
Vec seek(Vec target) {
Vec steer = Vec.sub(target, location);
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
return steer;
}
void flock(Graphics2D g, List<Boid> boids) {
view(g, boids);
Vec rule1 = separation(boids);
Vec rule2 = alignment(boids);
Vec rule3 = cohesion(boids);
rule1.mult(2.5);
rule2.mult(1.5);
rule3.mult(1.3);
applyForce(rule1);
applyForce(rule2);
applyForce(rule3);
applyForce(migrate);
}
public boolean doAreasCollide(Area area1, Area area2) {
boolean collide = false;
Area collide1 = new Area(area1);
collide1.subtract(area2);
if (!collide1.equals(area1)) {
collide = true;
}
Area collide2 = new Area(area2);
collide2.subtract(area1);
if (!collide2.equals(area2)) {
collide = true;
}
return collide;
}
void view(Graphics2D g, List<Boid> boids) {
double sightDistance = 100;
double peripheryAngle = PI * 0.85;
for (Boid b : boids) {
b.included = false;
if (b == this)
continue;
double d = Vec.dist(location, b.location);
if (d <= 0 || d > sightDistance)
continue;
Vec lineOfSight = Vec.sub(b.location, location);
double angle = Vec.angleBetween(lineOfSight, velocity);
if (angle < peripheryAngle)
b.included = true;
}
}
Vec separation(List<Boid> boids) {
double desiredSeparation = 25;
Vec steer = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < desiredSeparation)) {
Vec diff = Vec.sub(location, b.location);
diff.normalize();
diff.div(d); // weight by distance
steer.add(diff);
count++;
}
}
if (count > 0) {
steer.div(count);
}
if (steer.mag() > 0) {
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
return steer;
}
return new Vec(0, 0);
}
Vec alignment(List<Boid> boids) {
double preferredDist = 50;
Vec steer = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < preferredDist)) {
steer.add(b.velocity);
count++;
}
}
if (count > 0) {
steer.div(count);
steer.normalize();
steer.mult(maxSpeed);
steer.sub(velocity);
steer.limit(maxForce);
}
return steer;
}
Vec cohesion(List<Boid> boids) {
double preferredDist = 50;
Vec target = new Vec(0, 0);
int count = 0;
for (Boid b : boids) {
if (!b.included)
continue;
double d = Vec.dist(location, b.location);
if ((d > 0) && (d < preferredDist)) {
target.add(b.location);
count++;
}
}
if (count > 0) {
target.div(count);
return seek(target);
}
return target;
}
void draw(Graphics2D g) {
AffineTransform save = g.getTransform();
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
g.translate(location.x, location.y);
g.rotate(velocity.heading() + PI / 2);
g.setColor(Color.green);
// g.fill(shape);
g.setColor(Color.green);
g.draw(triangle);
g.fill(triangle);
g.setTransform(save);
Area square = new Area(new Rectangle(600,250,200,200));
g.draw(square);
if (doAreasCollide(square, triangle)) {
g.setColor(Color.RED);
System.out.println("Collision");
} else {
g.setColor(Color.GREEN);
System.out.println("noCollision");
}
g.fill(square);
}
public void run(Graphics2D g, List<Boid> boids, int w, int h) {
flock(g, boids);
update();
draw(g);
}
}
class Flock {
List<Boid> boids;
Flock() {
boids = new ArrayList<>();
}
void run(Graphics2D g, int w, int h) {
for (Boid b : boids) {
b.run(g, boids, w, h);
}
}
boolean hasLeftTheBuilding(int w) {
int count = 0;
for (Boid b : boids) {
if (b.location.x + Boid.size > w)
count++;
}
return boids.size() == count;
}
void addBoid(Boid b) {
boids.add(b);
}
static Flock spawn(double w, double h, int numBoids) {
Flock flock = new Flock();
for (int i = 0; i < numBoids; i++)
flock.addBoid(new Boid(w, h));
return flock;
}
}
class Vec {
double x, y;
Vec() {
}
Vec(double x, double y) {
this.x = x;
this.y = y;
}
void add(Vec v) {
x += v.x;
y += v.y;
}
void sub(Vec v) {
x -= v.x;
y -= v.y;
}
void div(double val) {
x /= val;
y /= val;
}
void mult(double val) {
x *= val;
y *= val;
}
double mag() {
return sqrt(pow(x, 2) + pow(y, 2));
}
double dot(Vec v) {
return x * v.x + y * v.y;
}
void normalize() {
double mag = mag();
if (mag != 0) {
x /= mag;
y /= mag;
}
}
void limit(double lim) {
double mag = mag();
if (mag != 0 && mag > lim) {
x *= lim / mag;
y *= lim / mag;
}
}
double heading() {
return atan2(y, x);
}
static Vec sub(Vec v, Vec v2) {
return new Vec(v.x - v2.x, v.y - v2.y);
}
static double dist(Vec v, Vec v2) {
return sqrt(pow(v.x - v2.x, 2) + pow(v.y - v2.y, 2));
}
static double angleBetween(Vec v, Vec v2) {
return acos(v.dot(v2) / (v.mag() * v2.mag()));
}
}