robotank/client-hodejs/rabbit.ts

135 lines
4.1 KiB
TypeScript
Raw Normal View History

2025-03-03 02:17:50 +01:00
// SPDX-License-Identifier: GPL-3.0-or-later
// Author: Sascha Nitsch https://contentnation.net/@grumpydevelop
import { RobotStatus } from './robotstatus';
import { RoboBase } from './robobase';
class Rabbit extends RoboBase {
carrotX: number = 0;
carrotY: number = 0;
running = false;
mode = 'MUNCH';
munchtime = 0;
ready() {
console.log('rabbit is ready');
}
start() {
console.log('simulation started');
this.cmd.powerRight = 0;
this.cmd.powerLeft = 0;
this.cmd.radarMin = 270;
this.cmd.radarMax = 90;
this.sendCmd();
this.running = true;
}
statusReady(status: RobotStatus) {
if (!this.running) {
return;
}
switch (this.mode) {
case 'RUN':
const dx = this.carrotX - status.posX;
const dy = this.carrotY - status.posY;
const dir = Math.atan2(dx, -dy) * 180 / Math.PI;
const dst = Math.sqrt(dx * dx + dy * dy);
let rot = dir - status.orientation;
if (rot < -180) {
rot += 360;
}
if (rot > 180) {
rot -= 360;
}
rot = Math.min(Math.max(-90, rot), 90);
let desiredSpeed = 1;
if (dst < 30) {
desiredSpeed = dst / 40;
}
const speedDiff = Math.sin(rot * Math.PI / 180.0);
// desired speed of left chain
let dsl = desiredSpeed + speedDiff;
// desired speed of right chain
let dsr = desiredSpeed - speedDiff;
// prevent overflows, reduce to limits but keep relative difference if possible
if (dsl > 1) {
dsr -= Math.max(dsl - 1, -1);
dsl = 1;
} else if (dsr > 1) {
dsl -= Math.max(dsr - 1, -1);
dsr = 1;
}
this.cmd.powerLeft = dsl;
this.cmd.powerRight = dsr;
// close and slow enough?
if (dst < 5 && Math.abs(status.chainSpeedLeft) < .1 && Math.abs(status.chainSpeedRight) < .1) {
this.mode = 'MUNCH';
this.cmd.powerLeft = 0;
this.cmd.powerRight = 0;
this.munchtime = 5 * 20; // 5 sec
console.log("munch");
}
break;
case "MUNCH":
if (this.munchtime) {
--this.munchtime;
} else {
this.mode = 'RUN';
this.carrotX = Math.random() * (this.width - 20) + 10;
this.carrotY = Math.random() * (this.height - 20) + 10;
console.log("target reached, new target", this.carrotX, this.carrotY);
}
break;
}
if (status.contactPoints && status.contactPoints.length > 0) {
status.contactPoints.forEach((cp) => {
// adjust angle by radar rotation
const angle = cp.angle + status.radarPos;
// global angle from position
const globalAngle = angle + status.orientation;
const targetX = Math.sin(globalAngle * Math.PI / 180)* cp.dist + status.posX;
const targetY = -Math.cos(globalAngle * Math.PI / 180)* cp.dist + status.posY;
// run the other way +- 45 degree
let newTargetAngle = globalAngle + 180 + Math.random()*90 - 45
if (newTargetAngle >= 360) {
newTargetAngle -= 360;
}
if (newTargetAngle < 0) {
newTargetAngle += 360;
}
// target is 50-100 units away
const newTargetDistance = Math.random() * 50 + 50;
this.carrotX = status.posX + Math.sin(newTargetAngle * Math.PI / 180) * newTargetDistance;
this.carrotY = status.posY - Math.cos(newTargetAngle * Math.PI / 180) * newTargetDistance;
if (this.carrotX > this.width - 10) {
this.carrotX = this.width - 10;
}
if (this.carrotY > this.height - 10) {
this.carrotY = this.height - 10;
}
if (this.carrotX < 0) {
this.carrotX = 10;
}
if (this.carrotY < 0) {
this.carrotY = 10;
}
console.log("enemy at", targetX, targetY, "run to", this.carrotX, this.carrotY);
});
}
this.sendCmd();
}
lost() {
console.log('we lost');
this.disconnect();
}
won() {
console.log('we won');
this.disconnect();
}
}
var rabbit = new Rabbit('rabbit', 'scout');
rabbit.connect();