132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
![]() |
import { RobotStatus } from "./robotstatus";
|
||
|
import { RoboBase } from "./robobase";
|
||
|
|
||
|
class SimpleHunter extends RoboBase {
|
||
|
targetX: number = 0;
|
||
|
targetY: number = 0;
|
||
|
fireCoolDown: number = 0;
|
||
|
mode: string = "SCAN";
|
||
|
ready() {
|
||
|
console.log("simpleHunter is ready");
|
||
|
this.cmd.radarMin = -1;
|
||
|
this.cmd.radarMax = -1;
|
||
|
this.sendCmd();
|
||
|
}
|
||
|
start() {
|
||
|
console.log("simulation started");
|
||
|
this.targetX = Math.random() * (this.width - 20) + 10;
|
||
|
this.targetY = Math.random() * (this.height - 20) + 10;
|
||
|
console.log("target", this.targetX, this.targetY);
|
||
|
}
|
||
|
driveToTarget(status: RobotStatus) {
|
||
|
const dx = this.targetX - status.posX;
|
||
|
const dy = this.targetY - 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 (this.mode === 'SCAN') {
|
||
|
if (dst < 30) {
|
||
|
desiredSpeed = dst / 40;
|
||
|
}
|
||
|
} else {
|
||
|
if (dst < 75) {
|
||
|
desiredSpeed = dst - 50 / 25;
|
||
|
}
|
||
|
}
|
||
|
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 === 'SCAN') {
|
||
|
this.targetX = Math.random() * (this.width - 20) + 10;
|
||
|
this.targetY = Math.random() * (this.height - 20) + 10;
|
||
|
console.log("target reached, new target", this.targetX, this.targetY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
statusReady(status: RobotStatus) {
|
||
|
this.driveToTarget(status);
|
||
|
if (this.fireCoolDown > 0) {
|
||
|
this.fireCoolDown -= this.deltaTime;
|
||
|
}
|
||
|
if (status.contactPoints && status.contactPoints.length > 0) {
|
||
|
status.contactPoints.forEach((cp) => {
|
||
|
// adjust angle by radar rotation
|
||
|
const angle = (cp.angle + status.radarPos) % 360;
|
||
|
// global angle from position
|
||
|
let newTargetAngle = angle + status.orientation;
|
||
|
if (newTargetAngle >= 360) {
|
||
|
newTargetAngle -= 360;
|
||
|
}
|
||
|
if (newTargetAngle < 0) {
|
||
|
newTargetAngle += 360;
|
||
|
}
|
||
|
this.targetX = Math.sin(newTargetAngle * Math.PI / 180)* (cp.dist - 50) + status.posX;
|
||
|
this.targetY = -Math.cos(newTargetAngle * Math.PI / 180)* (cp.dist - 50) + status.posY;
|
||
|
this.cmd.gunTarget = angle;
|
||
|
console.log("enemy at", this.targetX, this.targetY, "dist", cp.dist, "angle", angle);
|
||
|
this.mode = 'SEEK';
|
||
|
this.cmd.radarMin = angle - 20;
|
||
|
this.cmd.radarMax = angle + 20;
|
||
|
// shoot if aimed close enough
|
||
|
if (cp.dist < 100 && cp.dist > 25) {
|
||
|
console.log("diff", angle, status.gunOrient, Math.abs((angle-status.gunOrient)%360));
|
||
|
if (this.fireCoolDown <= 0 && (Math.abs(angle-status.gunOrient) < 2)) {
|
||
|
this.cmd.fire = true;
|
||
|
console.log("fire", cp.dist);
|
||
|
this.fireCoolDown = 10;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
if (this.mode === 'SEEK') { // lost track
|
||
|
this.cmd.radarMin = (this.cmd.radarMin + 359.5) % 360;
|
||
|
this.cmd.radarMax = (this.cmd.radarMax + .5) % 360;
|
||
|
//console.log("seek radar", this.cmd.radarMin, this.cmd.radarMax);
|
||
|
if (this.cmd.radarMax - this.cmd.radarMin > 180) {
|
||
|
this.cmd.radarMin = -1;
|
||
|
this.cmd.radarMax = -1;
|
||
|
this.mode = 'SCAN';
|
||
|
console.log("scan");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (status.causedDamage > 0) {
|
||
|
console.log("we hit with damage", status.causedDamage);
|
||
|
}
|
||
|
this.sendCmd();
|
||
|
}
|
||
|
|
||
|
lost() {
|
||
|
console.log("we lost");
|
||
|
this.disconnect();
|
||
|
}
|
||
|
won() {
|
||
|
console.log("we won");
|
||
|
this.disconnect();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
var simpleHunter = new SimpleHunter("targetPractise", "scout");
|
||
|
simpleHunter.connect();
|