linefollower_instruction_site/LineFollowerSim.js

90 lines
2.0 KiB
JavaScript

export class LineFollowerSim {
constructor(canvas, updateBoxFn) {
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
this.box = {
x: 250,
y: 150,
width: 40,
height: 20,
speed: 0.4,
dir: 0
};
this.lineX = 250;
this.lineTargetX = 250;
this.lineWidth = 12;
this.updateBox = updateBoxFn || this.defaultUpdateBox.bind(this);
this.loop = this.loop.bind(this);
}
updateLine() {
if (Math.random() < 0.02) {
this.lineTargetX = 250 + (Math.random() - 0.5) * 200;
}
this.lineX += (this.lineTargetX - this.lineX) * 0.005;
}
defaultUpdateBox() {
const leftSensor = this.box.x - this.box.width / 2;
const rightSensor = this.box.x + this.box.width / 2;
const onLine = x => x >= this.lineX - this.lineWidth / 2 && x <= this.lineX + this.lineWidth / 2;
const leftOnLine = onLine(leftSensor);
const rightOnLine = onLine(rightSensor);
if (leftOnLine && !rightOnLine) {
this.box.dir = -1;
} else if (rightOnLine && !leftOnLine) {
this.box.dir = 1;
} else {
//this.box.dir = 0;
}
this.box.x += this.box.dir * this.box.speed;
}
draw() {
const ctx = this.ctx;
const { x, y, width, height } = this.box;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Line
ctx.beginPath();
ctx.moveTo(this.lineX, 0);
ctx.lineTo(this.lineX, this.canvas.height);
ctx.strokeStyle = "blue";
ctx.lineWidth = this.lineWidth;
ctx.stroke();
// Box
ctx.fillStyle = "red";
ctx.fillRect(x - width / 2, y - height / 2, width, height);
// Sensors
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(x - width / 2, y - height / 2, 3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(x + width / 2, y - height / 2, 3, 0, Math.PI * 2);
ctx.fill();
}
loop() {
this.updateLine();
this.updateBox();
this.draw();
requestAnimationFrame(this.loop);
}
start() {
this.loop();
}
}