diff options
Diffstat (limited to 'resources/js/boid.js')
-rw-r--r-- | resources/js/boid.js | 202 |
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 + }; + } + +} |