onlinecodesimulator/game.js

218 lines
6.0 KiB
JavaScript

import { Robot } from "./robot.js";
import { GameWorld } from "./gameworld.js";
const consoleElement = document.getElementById("console");
const gameCanvas = document.getElementById("gameCanvas");
const ctx = gameCanvas.getContext("2d");
const gameWorld = new GameWorld();
let pyodideWorker = startPyodideWorker();
let robots = null;//createInitialRobots();
//gameWorld.addRobot(robots["player"]);
let paused = false;
let scale = 1; // Zoom level
let offsetX = 0; // Pan X
let offsetY = 0; // Pan Y
let isPanning = false;
let startX, startY; // Mouse start positions
// ✅ Function to create the Pyodide Worker
function startPyodideWorker() {
const worker = new Worker("pyodide-worker.js");
// ✅ Reattach the event listener when a new worker is created
worker.onmessage = (event) => {
if (paused) return;
switch (event.data.type) {
case "console":
logToConsole(event.data.data);
break;
case "error":
logToConsole(`<span style="color:red;">${event.data.message}</span>`);
break;
case "fire":
fire();
break;
case "turn":
turn(event.data.data);
break;
case "move":
move(event.data.data);
break;
}
};
return worker;
}
// ✅ Function to create initial robots
function createInitialRobots() {
return {
"player": new Robot("player", 50, 50, "blue")
//"enemy1": new Robot("enemy1", 200, 150, "red"),
//"enemy2": new Robot("enemy2", 400, 250, "red")
};
}
// ✅ Function to log messages to console
function logToConsole(text) {
console.log(text.replace("<b>", "").replace("</b>", ""));
consoleElement.innerHTML += text.replace(/\n/g, "<br>") + "<br>";
consoleElement.scrollTop = consoleElement.scrollHeight;
}
// ✅ Game Control Functions
function fire() {
logToConsole("<b>🔥 Gun Fired! 🔥</b>");
}
function turn(deg) {
robots["player"].turn(deg);
}
function move(distance) {
robots["player"].move(distance);
}
// ✅ Pause/Resume Function
function togglePause() {
paused = !paused;
document.getElementById("pause-button").innerText = paused ? "Resume" : "Pause";
}
// ✅ Reset Function (Fixed)
function resetGame() {
// Terminate the worker
pyodideWorker.terminate();
// Restart the worker and rebind event listener
pyodideWorker = startPyodideWorker();
// Reset the robots to their initial state
robots = createInitialRobots();
gameWorld.reset();
gameWorld.addRobot(robots["player"]);
// Clear the console
consoleElement.innerHTML = "";
// Unpause the game if it was paused
paused = false;
document.getElementById("pause-button").innerText = "Pause";
}
const targetFPS = 30;
const targetInterval = 1000 / targetFPS; // Time in milliseconds per frame
let lastFrameTime = 0;
// ✅ Game Loop
function gameLoop(timestamp) {
const deltaTime = timestamp - lastFrameTime;
// If enough time has passed since the last frame, update and draw
if (deltaTime >= targetInterval) {
lastFrameTime = timestamp;
if (!paused) {
ctx.resetTransform();
// Fill the entire visible canvas to remove artifacts
ctx.fillStyle = "#DDD";
ctx.fillRect(0, 0, gameCanvas.width, gameCanvas.height);
ctx.translate(offsetX, offsetY); // Apply panning
ctx.scale(scale, scale); // Apply zooming
gameWorld.update();
gameWorld.draw(ctx);
pyodideWorker.postMessage({
type: "game_state",
state: gameWorld
});
}
}
requestAnimationFrame(gameLoop);
}
resetGame(); // Initialize the game and robots
// Start game loop
gameLoop();
// ✅ Update "distance" and "speed" every 2 seconds with random values
function updateSensorData() {
const distance = Math.random() * 100; // Random distance (0-100)
const speed = Math.random() * 10; // Random speed (0-10)
console.log(`Distance: ${distance.toFixed(2)}, Speed: ${speed.toFixed(2)}`);
pyodideWorker.postMessage({
type: "sensor_update",
data: { distance, speed }
});
//logToConsole(`📡 Sensor Update - Distance: ${distance.toFixed(2)}, Speed: ${speed.toFixed(2)}`);
}
setInterval(updateSensorData, 2000); // Call every 2 seconds
// ✅ Button Event Listeners
document.getElementById("compile-button").addEventListener("click", () => {
if (paused) return;
const code = document.getElementById("python-code").value;
consoleElement.innerHTML = "";
pyodideWorker.postMessage({
type: "execute",
code: code
});
});
document.getElementById("pause-button").addEventListener("click", togglePause);
document.getElementById("reset-button").addEventListener("click", resetGame);
gameCanvas.addEventListener("wheel", (event) => {
event.preventDefault();
const scaleFactor = 1.1;
const mouseX = event.offsetX;
const mouseY = event.offsetY;
// Convert mouse coordinates to world coordinates (before zoom)
const worldX = (mouseX - offsetX) / scale;
const worldY = (mouseY - offsetY) / scale;
// Apply zoom
if (event.deltaY < 0) {
scale *= scaleFactor; // Zoom in
} else {
scale /= scaleFactor; // Zoom out
}
// Keep zoom within limits
scale = Math.max(0.5, Math.min(3, scale));
// Adjust offset so zooming is centered at mouse position
offsetX = mouseX - worldX * scale;
offsetY = mouseY - worldY * scale;
});
gameCanvas.addEventListener("mousedown", (event) => {
isPanning = true;
startX = event.clientX - offsetX;
startY = event.clientY - offsetY;
});
gameCanvas.addEventListener("mousemove", (event) => {
if (!isPanning) return;
offsetX = event.clientX - startX;
offsetY = event.clientY - startY;
});
gameCanvas.addEventListener("mouseup", () => {
isPanning = false;
});