summaryrefslogtreecommitdiff
path: root/resources/js/boid.js
diff options
context:
space:
mode:
Diffstat (limited to 'resources/js/boid.js')
-rw-r--r--resources/js/boid.js202
1 files changed, 202 insertions, 0 deletions
diff --git a/resources/js/boid.js b/resources/js/boid.js
new file mode 100644
index 0000000..6075cc2
--- /dev/null
+++ b/resources/js/boid.js
@@ -0,0 +1,202 @@
+class Boid {
+
+ constructor(context, radius, color, x, y, direction, id) {
+ this.rayLength = 40;
+ this.turnStepAmount = 20;
+ this.stepAmount = 4;
+ this.radius = radius;
+ this.x = x;
+ this.y = y;
+ this.direction = direction;
+ this.color = color;
+ this.fieldOfView = 270;
+ this.id = id;
+ this.boidBuffer = 20;
+
+ this.update(context);
+ }
+
+ move(context, boids) {
+ // this.direction += Math.random() * (2 * this.turnStepAmount) - this.turnStepAmount
+
+ this.direction = this.findNextRay(context, boids);
+
+ var vector = this.findPoint(this.x, this.y, this.stepAmount, this.direction);
+ this.x = vector.x;
+ this.y = vector.y;
+
+ this.update(context);
+ }
+
+ buildRays() {
+ let rays = new Array();
+
+ let rayInteval = 2;
+ let noOfSteps = this.fieldOfView / rayInteval;
+ for (let i = 0; i < noOfSteps / 2; i++) {
+ if (i != 0) {
+ rays.push(rayInteval * -i);
+ }
+ rays.push(rayInteval * i);
+ }
+
+ return rays;
+ }
+
+ findNextRay(context, boids) {
+ let rays = this.buildRays();
+
+ for (let i = 0; i < rays.length; i++) {
+ let tweakAngle = 0;
+ // if (Math.random() > 0.95) {
+ // tweakAngle = this.turnStepAmount * Math.random() - (this.turnStepAmount / 2);
+ // }
+
+ let rayAngle = tweakAngle + this.direction + rays[i];
+
+ if (i == 0 && this.detectBoid(context, rayAngle, boids)) {
+ continue;
+ }
+
+ if (this.detectBox(context, context.canvas.width, context.canvas.height, rayAngle)) {
+ continue;
+ }
+
+ return rayAngle;
+ }
+ console.log(this.x, this.y);
+ console.log('cannot find suitable ray');
+ }
+
+ detectBoid(context, direction, boids) {
+ for (let i = 0; i < boids.length; i++) {
+ // rule out ourselves
+ if (this.id == boids[i].id) {
+ continue;
+ }
+
+ let thisFututrePosition = this.findPoint(this.x, this.y, this.boidBuffer, direction);
+ let thisPath = {
+ x1: this.x,
+ y1: this.y,
+ x2: thisFututrePosition.x,
+ y2: thisFututrePosition.y
+ };
+
+ let boidFuturePosition = this.findPoint(boids[i].x, boids[i].y, boids[i].boidBuffer, boids[i].direction);
+ let boidPath = {
+ x1: boids[i].x,
+ y1: boids[i].y,
+ x2: boidFuturePosition.x,
+ y2: boidFuturePosition.y
+ };
+
+ let thisIntersectsBoid = this.pathsIntersect(
+ thisPath.x1, thisPath.y1, thisPath.x2, thisPath.y2, boidPath.x1, boidPath.y1, boidPath.x2, boidPath.y2
+ );
+
+ if (thisIntersectsBoid) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ pathsIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {
+ // Check if none of the lines are of length 0
+ if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) {
+ return false
+ }
+
+ let denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1))
+
+ // // Lines are parallel
+ // if (denominator === 0) {
+ // return false
+ // }
+
+ let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator
+ let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator
+
+ // is the intersection along the segments
+ if (ua < 0 || ua > 1 || ub < 0 || ub > 1) {
+ return false
+ }
+
+ // Return a object with the x and y coordinates of the intersection
+ let x = x1 + ua * (x2 - x1)
+ let y = y1 + ua * (y2 - y1)
+
+ return {
+ x,
+ y
+ }
+ }
+
+ detectBox(context, width, height, direction) {
+ let perceptionVector = this.findPoint(this.x, this.y, this.rayLength, direction);
+
+ if (perceptionVector.x - this.radius < 0 ||
+ perceptionVector.y - this.radius < 0 ||
+ perceptionVector.x + this.radius > width - 0 ||
+ perceptionVector.y + this.radius > height - 0
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ update(context) {
+ this.drawBoid(context);
+ this.drawRay(context, this.x, this.y, this.rayLength, this.direction);
+ }
+
+ drawBoid(context) {
+ context.beginPath();
+ context.fillStyle = "blue";
+ context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
+ context.stroke();
+ context.restore();
+ }
+
+ drawRay(context, x, y, perceptionDistance, direction) {
+ let point = this.findPoint(x, y, perceptionDistance, direction);
+ context.lineWidth = 1;
+ context.beginPath();
+ context.moveTo(x, y);
+ context.lineTo(point.x, point.y);
+ context.stroke();
+
+ context.restore();
+ }
+
+ lineToAngle(context, x1, y1, length, angle) {
+ angle *= Math.PI / 180;
+
+ var x2 = x1 + length * Math.cos(angle),
+ y2 = y1 + length * Math.sin(angle);
+
+ context.moveTo(x1, y1);
+ context.lineTo(x2, y2);
+
+ return {
+ x: x2,
+ y: y2
+ };
+ }
+
+ findPoint(x1, y1, length, angle) {
+ angle *= Math.PI / 180;
+
+ var x2 = x1 + length * Math.cos(angle),
+ y2 = y1 + length * Math.sin(angle);
+
+ return {
+ x: x2,
+ y: y2
+ };
+ }
+
+}