xxxxxxxxxx
265
// idea and map from here https://www.codingame.com/ide/puzzle/mars-lander-episode-3
// codingame is a great platform to learn problem solving
GAME_SECONDS_PER_FRAME = 2; // 1 for play 10 for dsebug whatyever do whatever u want
const DEBUG = 1;
const SKIP_BOOT_SEQUENCE = DEBUG;
let angleSlider, thrustSlider, manualOverrideButton;
let manualOverride = false;
let bootlog;
let bootup = true;
let boot_i = 0;
function preload() {
bootlog = loadStrings("bootup.txt");
}
const surface_points = [
{ x: 0, y: 450 },{ x: 300, y: 750 },{ x: 1000, y: 450 },{ x: 1500, y: 650 },{ x: 1800, y: 850 },{ x: 2000, y: 1950 },{ x: 2200, y: 1850 },{ x: 2400, y: 2000 },{ x: 3100, y: 1800 },{ x: 3150, y: 1550 },{ x: 2500, y: 1600 },{ x: 2200, y: 1550 },{ x: 2100, y: 750 },{ x: 2200, y: 150 },{ x: 3200, y: 150 },{ x: 3500, y: 450 },{ x: 4000, y: 950 },{ x: 4500, y: 1450 },{ x: 5000, y: 1550 },{ x: 5500, y: 1500 },{ x: 6000, y: 950 },{ x: 6999, y: 1750 },
];
const MAP_HEIGHT = 3000;
const MAP_WIDTH = 7000;
var lander;
const GRAVITY = 3.7211;
function setup() {
let canvas = createCanvas(700, 300);
canvas.parent("canvas-container");
angleMode(DEGREES);
let lander_pos = createVector(6543, 2543);
let lander_vel = createVector(0, 0);
let lander_fuel = 10000;
lander = new Lander(lander_pos, lander_vel, lander_fuel);
lander.setCommand({ angle: 1, thrust: 3 });
textSize(12);
if (!SKIP_BOOT_SEQUENCE) background("blue");
frameRate(60);
angleSlider = select("#angleSlider");
thrustSlider = select("#thrustSlider");
manualOverrideButton = select("#manualOverride");
manualOverrideButton.style(
"background-color",
manualOverride ? "#a00" : "#8AFF00"
);
// Button listener for manual override
manualOverrideButton.mousePressed(() => {
manualOverride = !manualOverride;
manualOverrideButton.style(
"background-color",
manualOverride ? "#a00" : "#8AFF00"
);
});
}
class Lander {
constructor(pos, vel, fuel) {
this.initialPos = pos.copy(); // for resets.
this.pos = pos.copy();
this.vel = vel.copy();
this.curr_thrust = 0;
this.curr_angle = 0;
this.fuel = fuel;
this.command = { thrust: 0, angle: 0 };
}
show() {
let p = this.pos;
push();
translate(
map(p.x, 0, MAP_WIDTH, 0, width), //x pos mapped to mapsize
// MAP INVERTED to -Y by scale(1,-1) in draw() already
-map(p.y, 3000, 0, 0, height) //y pos mapped to mapsize
);
triangle(-5, 0, 0, 7.5, 5, 0);
pop();
}
setCommand(newCommand) {
this.targetCommand = {
angle: adjustAngle(newCommand.angle), // Adjust the angle to simulator requirements
thrust: newCommand.thrust,
};
}
update() {
const MAX_ANGLE_CHANGE = 15, MIN_ANGLE = -90, MAX_ANGLE = 90, MAX_THRUST_CHANGE = 1, MIN_THRUST = 0, MAX_THRUST = 4;
let desiredAngleChange = this.targetCommand.angle - this.curr_angle;
let angleChange = Math.max(-MAX_ANGLE_CHANGE, Math.min(MAX_ANGLE_CHANGE, desiredAngleChange));
this.curr_angle = Math.max(MIN_ANGLE, Math.min(MAX_ANGLE, this.curr_angle + angleChange));
let desiredThrustChange = this.targetCommand.thrust - this.curr_thrust;
let thrustChange = Math.max(-MAX_THRUST_CHANGE, Math.min(MAX_THRUST_CHANGE, desiredThrustChange));
this.curr_thrust = Math.max(MIN_THRUST, Math.min(MAX_THRUST, this.curr_thrust + thrustChange));
print(this.curr_thrust, this.curr_angle ,this.targetCommand.angle)
let angleRadians = Math.PI / 180 * (90 - this.curr_angle);
let dx = this.curr_thrust * Math.cos(angleRadians);
let dy = this.curr_thrust * Math.sin(angleRadians);
if (this.fuel >= this.curr_thrust) {
this.fuel -= this.curr_thrust;
this.vel.x += dx;
this.vel.y -= dy;
}
this.vel.y += GRAVITY;
this.pos.add(this.vel);
this.checkOutOfBoundsAndResetIfOutOfBounds();
}
checkOutOfBoundsAndResetIfOutOfBounds() {
if (
this.pos.x < 0 ||
this.pos.x > MAP_WIDTH ||
this.pos.y < 0 ||
this.pos.y > MAP_HEIGHT + 100
) {
print("OUT OF BOUNDS! RESET!");
this.vel = createVector(0, 0);
this.pos = this.initialPos.copy();
}
}
}
const MIN_INPUT = 90, MAX_INPUT = -90, MIN_OUTPUT = -180, MAX_OUTPUT = 0;
function mapValue(input) {
return ((input - MIN_INPUT) / (MAX_INPUT - MIN_INPUT)) * (MAX_OUTPUT - MIN_OUTPUT) + MIN_OUTPUT;
}
function adjustAngle(inputAngle) {
return mapValue(inputAngle)
}
function drawDebug(){
stroke(0)
fill(0)
strokeWeight(1)
scale(1,1)
debugDrawAngle()
}
function debugDrawAngle(){
[mx, my] = [mouseX, mouseY]
line(width/2, height/2, mouseX,mouseY)
text(atan2(mouseY - height/2, mouseX -width/2), 10+mouseX,mouseY)
a = createVector(mouseX, mouseY)
text(a.heading(), 10+mouseX, mouseY+16);
}
function drawSim() {
background(220);
checkForManualOverride();
// INVERT Y-AXSIS for drawing
scale(1, -1);
lander.update();
lander.show();
drawSurface();
}
function draw() {
push()
if (!SKIP_BOOT_SEQUENCE && bootup) {
if (boot_i < bootlog.length) {
drawLog();
boot_i++;
} else {
bootup = false;
}
} else {
if (frameCount % GAME_SECONDS_PER_FRAME == 0) drawSim();
}
pop()
drawDebug()
}
function checkForManualOverride() {
if (manualOverride) {
let manualAngle = angleSlider.value();
let manualThrust = thrustSlider.value();
lander.setCommand({ angle: manualAngle, thrust: manualThrust });
noStroke();
fill("rgb(8,8,8)");
textSize(12);
text(`Angle: ${manualAngle}`, 20, 28);
text(`Thrust: ${manualThrust}`, 20, 39);
stroke(0);
text("⚠MANUAL OVERRIDE ENABLED⚠", 22, 15);
fill("#FF0000");
text("⚠MANUAL OVERRIDE ENABLED⚠", 20, 14);
} else {
angleSlider.value(lander.curr_angle);
thrustSlider.value(lander.curr_thrust);
}
}
function drawLog() {
text(bootlog[boot_i], 20, boot_i * 14);
frameRate(random(0.5, 2.5));
}
// DRAWING OTHER STUFF
function drawSurface() {
stroke(0);
strokeWeight(2);
for (let i = 0; i < surface_points.length - 1; i++) {
let startX = map(surface_points[i].x, 0, 7000, 0, width);
let startY = -map(surface_points[i].y, 3000, 0, 0, height);
let endX = map(surface_points[i + 1].x, 0, 7000, 0, width);
let endY = -map(surface_points[i + 1].y, 3000, 0, 0, height);
line(startX, startY, endX, endY);
}
}