diff --git a/game.js b/game.js index 20f57a6..8aae3ed 100644 --- a/game.js +++ b/game.js @@ -525,6 +525,12 @@ gameCanvas.addEventListener("wheel", (event) => { offsetY = mouseY - worldY * scale; }); +const canvas = document.getElementById("gameCanvas"); +window.addEventListener("resize", () => { + // console.log("RESIZE"); + // gameWorld.resizeCanvas(canvas) +}); + gameCanvas.addEventListener("mousedown", (event) => { isPanning = true; @@ -574,6 +580,7 @@ function setupCanvas() { const canvas = document.getElementById("gameCanvas"); const context = canvas.getContext("2d"); + // Get the device pixel ratio const dpr = window.devicePixelRatio || 1; @@ -590,7 +597,7 @@ function setupCanvas() { } // Call this function when the page loads -fetch('/data/levels.json') +fetch('./data/levels.json') .then(response => response.json()) .then(data => { gameWorld.levelData = data; @@ -601,7 +608,7 @@ fetch('/data/levels.json') // Start game loop gameLoop(); - showLesson(0); + showLesson(10); }); diff --git a/gameworld.js b/gameworld.js index bacf487..b866ad9 100644 --- a/gameworld.js +++ b/gameworld.js @@ -19,6 +19,21 @@ export class GameWorld { this.obstacles = []; this.robots = []; + this.lineColor = `rgba(0,0,0,1)`; + this.floorLines = [ + { x: 170, y: 75 }, + { x: 300, y: 75 }, + { x: 500, y: 300 }, + { x: 500, y: 400 }, + { x: 450, y: 450 }, + { x: 400, y: 450 }, + { x: 100, y: 350 }, + { x: 50, y: 250 }, + { x: 80, y: 150 }, + { x: 170, y: 75 }, + // add more points as needed + ]; + this.lineWidth = 3; @@ -171,24 +186,24 @@ export class GameWorld { getCentroid(vertices) { let area = 0, cx = 0, cy = 0; - for (let i = 0; i < vertices.length; i++) { - const p1 = vertices[i]; - const p2 = vertices[(i + 1) % vertices.length]; - const cross = p1.x * p2.y - p2.x * p1.y; + for (let i = 0; i < vertices.length; i++) { + const p1 = vertices[i]; + const p2 = vertices[(i + 1) % vertices.length]; + const cross = p1.x * p2.y - p2.x * p1.y; - area += cross; - cx += (p1.x + p2.x) * cross; - cy += (p1.y + p2.y) * cross; - } + area += cross; + cx += (p1.x + p2.x) * cross; + cy += (p1.y + p2.y) * cross; + } - area *= 0.5; - if (area === 0) return vertices[0]; // fallback to first point + area *= 0.5; + if (area === 0) return vertices[0]; // fallback to first point - cx /= (6 * area); - cy /= (6 * area); + cx /= (6 * area); + cy /= (6 * area); - return { x: cx, y: cy }; -} + return { x: cx, y: cy }; + } addObstacle(vertices, strokeColor = "black", fillColor = "gray") { // Sort vertices clockwise (Matter requires this) @@ -247,15 +262,24 @@ export class GameWorld { // Return the floor color based on (x, y) coordinates getFloorColor(x, y) { - return (x + y) % 50 < 25 ? "black" : "white"; // Example pattern + const isUnderLine = this.isPointNearLine(x, y, this.floorLines, this.lineWidth); + return isUnderLine; + // if (isUnderLine) { + // console.log("Robot is over a floor line"); + // } } // Draw the game world (e.g., obstacles, background) draw(ctx) { + //this.render(ctx); + + + this.drawFloorLines(ctx); // Draw obstacles ctx.strokeStyle = "gray"; // Obstacle outline color ctx.lineWidth = 2; // Optional: to make the outline thicker + // Draw obstacles this.obstacles.forEach(body => { ctx.beginPath(); @@ -313,8 +337,45 @@ export class GameWorld { robot.draw(ctx); // Draw the robot's hull and sensors }); + + } + drawFloorLines(ctx) { + if (this.floorLines.length < 2) return; + + ctx.strokeStyle = this.lineColor; + ctx.lineWidth = this.lineWidth; + ctx.beginPath(); + ctx.moveTo(this.floorLines[0].x, this.floorLines[0].y); + for (let i = 1; i < this.floorLines.length; i++) { + ctx.lineTo(this.floorLines[i].x, this.floorLines[i].y); + } + ctx.stroke(); + } + + + resizeCanvasToDisplaySize(ctx) { + let canvas = ctx.canvas; + const width = canvas.clientWidth; + const height = canvas.clientHeight; + + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + } + } + + render(ctx) { + let canvas = ctx.canvas; + this.resizeCanvasToDisplaySize(canvas); // 👈 ensures drawing resolution matches display size + ctx.clearRect(0, 0, canvas.width, canvas.height); + game.draw(ctx); + requestAnimationFrame(render); + } + + + rayCast(startX, startY, endX, endY, ignoreBodies = []) { let closestIntersection = null; let startPoint = { x: startX, y: startY }; @@ -389,8 +450,45 @@ export class GameWorld { return null; // No valid intersection } + isPointNearLine(x, y, linePoints, width) { + const threshold = width / 2; + for (let i = 0; i < linePoints.length - 1; i++) { + const p1 = linePoints[i]; + const p2 = linePoints[i + 1]; + const dist = this.pointToSegmentDistance(x, y, p1.x, p1.y, p2.x, p2.y); + if (dist <= threshold) { + return true; + } + } + return false; + } + + pointToSegmentDistance(px, py, x1, y1, x2, y2) { + const dx = x2 - x1; + const dy = y2 - y1; + const lengthSquared = dx * dx + dy * dy; + + if (lengthSquared === 0) { + // p1 == p2 + const dxp = px - x1; + const dyp = py - y1; + return Math.sqrt(dxp * dxp + dyp * dyp); + } + + // Project point onto the segment + let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared; + t = Math.max(0, Math.min(1, t)); // clamp to segment + + const projX = x1 + t * dx; + const projY = y1 + t * dy; + + const dxp = px - projX; + const dyp = py - projY; + + return Math.sqrt(dxp * dxp + dyp * dyp); + } } diff --git a/index.html b/index.html index 4c66d7a..2af1f75 100644 --- a/index.html +++ b/index.html @@ -17,12 +17,12 @@