The program spawns a flock of triangles that 'fly' through an environment. In this environment, there is a rectangle and sometimes the flock will fly through the rectangle. The flock itself is comprised of 20 triangles - what I want to know is how many of these triangles pass through the rectangle each time the flock flys through the environment (once the flock disappears outside of the environment it respawns).
At the moment, my attempt at implementing this is the "hasFoundFood" method where I attempt to detect whether, for each of the boids, they have come into contact with the bounds of the rectangle but the value for noSuccessful is always 20.
Is there a way to detect whether any or all of the triangles have come into contact with the boundaries of rectangle and then count how many times this has occurred?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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;
import java.util.Random;
import javax.swing.JButton;
public class Boids extends JPanel {
Flock flock;
Flock flock2;
final int w, h;
int noSuccessful;
public Area food = new Area(new Rectangle(600,250,200,200));
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
public Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
public Boids() {
w = 1200;
h = 600;
setPreferredSize(new Dimension(w, h));
setBackground(Color.black);
spawnFlock();
flock.hasFoundFood(noSuccessful);
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);
flock2 = Flock.spawn(100, h - n, 1);
}
@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);
g.draw(food);
}
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;
/* static final Path2D shape = new Path2D.Double();
static {
shape.moveTo(0, -size * 2);
shape.lineTo(-size, size * 2);
shape.lineTo(size, size * 2);
shape.closePath();
}
*/
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);
}
public void run(Graphics2D g, List<Boid> boids, int w, int h) { //similair method to run leader
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) //will also be used to calculate votes based on whether boids is near food
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;
}
int hasFoundFood(int noSuccessful) {
Area food = new Area(new Rectangle(600,250,200,200));
int[] xTriangle = {33,36,34};
int[] yTriangle = {30,30,20};
Area triangle = new Area(new Polygon(xTriangle, yTriangle, 3));
noSuccessful = 0;
for (Boid b : boids) {
if(b.doAreasCollide(food, triangle)); {
noSuccessful++;
}
}
System.out.println(noSuccessful);
return noSuccessful;
}
}
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()));
}
}
Update: I have altered the code in line with Andrews code about collisions detection using Area's and it still wont work?! when I call hasFoundFood it still produces the value 20 which is incorrect as, at this point, it should be 0. I am pulling my hair out at this point and cannot for the life of me figure out what is wrong here?!