import Matter from "https://cdn.jsdelivr.net/npm/matter-js@0.19.0/+esm"; export class GameWorld { constructor() { this.engine = Matter.Engine.create(); this.world = this.engine.world; this.engine.world.gravity.y = 0.01; Matter.Runner.run(this.engine); let ground = Matter.Bodies.rectangle(400, 600, 800, 50, { isStatic: true }); Matter.World.add(this.world, ground); this.obstacles = []; this.robots = []; this.addObstacle([ { x: 80 + 100, y: 0 }, // Vertex 1 { x: 250 + 100, y: 370 }, // Vertex 2 { x: 200 + 100, y: 370 }, // Vertex 3 { x: 150 + 100, y: 200 } // Vertex 4 ]); this.addObstacle([ { x: 300, y: 380 }, // Vertex 1 { x: 420, y: 380 }, // Vertex 2 { x: 350, y: 550 }, // Vertex 3 { x: 280, y: 420 } // Vertex 4 ]); } update() { // Update the physics simulation Matter.Engine.update(this.engine); } addObstacle(vertices) { // Convert the polygon points into a Matter.js body let body = Matter.Bodies.fromVertices(-30, 300, [vertices], { isStatic: true, // Obstacles shouldn't move }); // Add body to world and store it Matter.World.add(this.world, body); this.obstacles.push(body); } addRobot(robot) { console.log("added robot"); // Create the robot's Matter.js body let robotBody = Matter.Bodies.fromVertices(robot.x, robot.y, [robot.hull], { friction: 0.05, restitution: 0.2, // Slight bounce }); // Add to the world Matter.World.add(this.world, robotBody); this.robots.push(robotBody); } // Return the floor color based on (x, y) coordinates getFloorColor(x, y) { return (x + y) % 50 < 25 ? "black" : "white"; // Example pattern } // Draw the game world (e.g., obstacles, background) draw(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(); let vertices = body.vertices; ctx.moveTo(vertices[0].x, vertices[0].y); for (let i = 1; i < vertices.length; i++) { ctx.lineTo(vertices[i].x, vertices[i].y); } ctx.closePath(); ctx.stroke(); }); this.robots.forEach(body => { ctx.strokeStyle = "blue"; let vertices = body.vertices; ctx.beginPath(); ctx.moveTo(vertices[0].x, vertices[0].y); for (let i = 1; i < vertices.length; i++) { ctx.lineTo(vertices[i].x, vertices[i].y); } ctx.closePath(); ctx.stroke(); }); } rayCast(startX, startY, endX, endY) { let closestIntersection = null; // Loop through all obstacles for (let i = 0; i < this.obstacles.length; i++) { let obstacle = this.obstacles[i]; return this.lineIntersectsPolygon(startX, startY, endX, endY, obstacle); } return closestIntersection; } lineIntersection(line1Start, line1End, line2Start, line2End) { let denom = (line1Start.x - line1End.x) * (line2Start.y - line2End.y) - (line1Start.y - line1End.y) * (line2Start.x - line2End.x); if (denom === 0) return null; // Lines are parallel let t = ((line1Start.x - line2Start.x) * (line2Start.y - line2End.y) - (line1Start.y - line2Start.y) * (line2Start.x - line2End.x)) / denom; let u = ((line1Start.x - line2Start.x) * (line1Start.y - line1End.y) - (line1Start.y - line2Start.y) * (line1Start.x - line1End.x)) / denom; if (t >= 0 && t <= 1 && u >= 0 && u <= 1) { let ix = line1Start.x + t * (line1End.x - line1Start.x); let iy = line1Start.y + t * (line1End.y - line1Start.y); return { x: ix, y: iy }; } return null; // No intersection } lineIntersectsPolygon(startX, startY, endX, endY, polygon) { let lineStart = { x: startX, y: startY }; let lineEnd = { x: endX, y: endY }; // Loop through all edges of the polygon for (let i = 0; i < polygon.length; i++) { let currentVertex = polygon[i]; let nextVertex = polygon[(i + 1) % polygon.length]; // Loop back to the first vertex let intersection = this.lineIntersection(lineStart, lineEnd, currentVertex, nextVertex); if (intersection) { return intersection; // Return the first intersection found } } return null; // No intersection with any edge of the polygon } lineSegmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4) { let den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); if (den === 0) return null; // Parallel lines let t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den; let u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den; if (t >= 0 && t <= 1 && u >= 0 && u <= 1) { return { x: x1 + t * (x2 - x1), y: y1 + t * (y2 - y1) }; } return null; } polygonsIntersect(poly1, poly2) { for (let i = 0; i < poly1.length; i++) { let p1 = poly1[i]; let p2 = poly1[(i + 1) % poly1.length]; // Next point, wrap around // Loop through each edge of the second polygon for (let j = 0; j < poly2.length; j++) { let p3 = poly2[j]; let p4 = poly2[(j + 1) % poly2.length]; // Next point, wrap around let intersection = this.lineIntersection(p1, p2, p3, p4); if (intersection) { // Calculate the normal of the intersecting edge let normal = this.calculateNormal(p1, p2); return { intersection, normal }; } } } return null; // No intersection } calculateNormal(p1, p2) { // Vector of the edge (from p1 to p2) let dx = p2.x - p1.x; let dy = p2.y - p1.y; // The normal is the perpendicular vector to the edge // We can rotate the vector 90 degrees counterclockwise (for a counterclockwise normal) let normal = { x: -dy, y: dx }; // Normalize the normal vector let length = Math.sqrt(normal.x * normal.x + normal.y * normal.y); normal.x /= length; normal.y /= length; return normal; } polygonLineIntersection(polygon, p1, p2) { for (let i = 0; i < polygon.length; i++) { let p3 = polygon[i]; let p4 = polygon[(i + 1) % polygon.length]; // Next point, wrap around let intersection = this.lineIntersection(p1, p2, p3, p4); if (intersection) { return intersection; } } return null; } checkAndResolveCollision(robot) { for (let obstacle of this.obstacles) { let result = this.polygonsIntersect(robot.get_hull(), obstacle); if (result) { let { intersection, normal } = result; //console.log("Intersection point:", intersection); //console.log("Normal vector:", normal); // Resolve the collision by sliding the robot along the normal this.resolveSlide(robot, normal); return true; } } return false; } resolveSlide(robot, normal) { const radians = (robot.angle * Math.PI) / 180; let vx = Math.cos(radians) * robot.velocity; let vy = Math.sin(radians) * robot.velocity; let dot = vx * normal.x + vy * normal.y; // Subtract the normal component from velocity to make it slide vx -= 2 * dot * normal.x; // Reflect velocity along the normal (away from the surface) vy -= 2 * dot * normal.y; // Reflect velocity along the normal (away from the surface) // Apply the adjusted movement robot.x = robot.prevX; robot.y = robot.prevY; robot.x += vx; robot.y += vy; //robot.updateHull(); } }