130 lines
3.9 KiB
JavaScript
130 lines
3.9 KiB
JavaScript
export class Sensor {
|
|
constructor(robot, offsetAngle, offsetDistance) {
|
|
this.robot = robot
|
|
this.value = null; // Last recorded value
|
|
this.offsetAngle = offsetAngle;
|
|
this.offsetDistance = offsetDistance;
|
|
this.hitX = null;
|
|
this.hitY = null;
|
|
this.hitObject = null;
|
|
|
|
}
|
|
|
|
updatePosition() {
|
|
const robotAngle = this.robot.angle * (Math.PI / 180);
|
|
const offsetAngleRad = this.offsetAngle * (Math.PI / 180);
|
|
this.startX = this.robot.x + this.offsetDistance * Math.cos(robotAngle + offsetAngleRad);
|
|
this.startY = this.robot.y + this.offsetDistance * Math.sin(robotAngle + offsetAngleRad);
|
|
}
|
|
|
|
read(robot, gameWorld) {
|
|
throw new Error("read() must be implemented in subclasses");
|
|
}
|
|
|
|
draw(ctx) {
|
|
// Default empty draw, can be overridden
|
|
}
|
|
}
|
|
|
|
export class RaycastSensor extends Sensor {
|
|
constructor(robot, offsetAngle, offsetDistance, angle, distance) {
|
|
super(robot, offsetAngle, offsetDistance); // Call the parent class constructor
|
|
this.angle = angle;
|
|
this.distance = distance;
|
|
this.range = 100;
|
|
}
|
|
|
|
updatePosition() {
|
|
const robotAngle = this.robot.angle * (Math.PI / 180);
|
|
const offsetAngleRad = this.offsetAngle * (Math.PI / 180);
|
|
this.startX = this.robot.x + this.offsetDistance * Math.cos(robotAngle + offsetAngleRad);
|
|
this.startY = this.robot.y + this.offsetDistance * Math.sin(robotAngle + offsetAngleRad);
|
|
const sensorAngle = robotAngle + (this.angle * (Math.PI / 180));
|
|
this.endX = this.startX + Math.cos(sensorAngle) * this.range;
|
|
this.endY = this.startY + Math.sin(sensorAngle) * this.range;
|
|
}
|
|
|
|
read(robot, gameWorld) {
|
|
//console.log(robot);
|
|
//console.log(gameWorld);
|
|
this.updatePosition();
|
|
|
|
const angleInRadians = (this.robot.direction + this.angle) * Math.PI / 180;
|
|
const x = this.robot.x + Math.cos(angleInRadians) * this.distance;
|
|
const y = this.robot.y + Math.sin(angleInRadians) * this.distance;
|
|
|
|
// Ensure gameWorld is available and properly passed to the sensor
|
|
let hitPos = gameWorld.rayCast(this.startX, this.startY, this.endX, this.endY);
|
|
if (hitPos != null) {
|
|
this.hitX = hitPos.x;
|
|
this.hitY = hitPos.y;
|
|
this.endX = this.hitX;
|
|
this.endY = this.hitY;
|
|
} else {
|
|
this.hitX = null;
|
|
this.hitY = null;
|
|
}
|
|
// console.log("Obstacle detected!");
|
|
// } else {
|
|
// console.log("Clear path!");
|
|
// }
|
|
}
|
|
|
|
draw(ctx) {
|
|
|
|
|
|
ctx.strokeStyle = "lime";
|
|
ctx.fillStyle = "green"
|
|
ctx.beginPath();
|
|
ctx.arc(this.startX, this.startY, 2, 0, 2 * Math.PI);
|
|
ctx.fillStyle = "red";
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
|
|
if (this.hitX != null) {
|
|
ctx.strokeStyle = "red";
|
|
ctx.fillStyle = "red"
|
|
ctx.beginPath();
|
|
ctx.arc(this.hitX, this.hitY, 2, 0, 2 * Math.PI);
|
|
ctx.fillStyle = "red";
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
}
|
|
|
|
|
|
ctx.strokeStyle = "yellow";
|
|
ctx.beginPath();
|
|
ctx.lineWidth = 2;
|
|
ctx.moveTo(this.startX, this.startY);
|
|
ctx.lineTo(this.endX, this.endY);
|
|
ctx.stroke();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
export class FloorColorSensor extends Sensor {
|
|
constructor(robot, offsetAngle, offsetDistance) {
|
|
super(robot, offsetAngle, offsetDistance); // No angle offset, directly below robot
|
|
}
|
|
|
|
read(robot, gameWorld) {
|
|
this.value = gameWorld.getFloorColor(robot.x, robot.y);
|
|
return this.value;
|
|
}
|
|
|
|
draw(ctx) {
|
|
this.updatePosition();
|
|
|
|
ctx.strokeStyle = "purple";
|
|
ctx.fillStyle = "green"
|
|
ctx.beginPath();
|
|
ctx.arc(this.startX, this.startY, 2, 0, 2 * Math.PI);
|
|
ctx.fillStyle = "red";
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
|
|
|
|
}
|
|
}
|