const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const GRID_SIZE = 40; const ws = new WebSocket("ws://localhost:3000"); let objects = []; let selectedTool = "block"; // Select tool document.querySelectorAll(".tool").forEach(el => { el.onclick = () => { document.querySelectorAll(".tool").forEach(t => t.classList.remove("selected")); el.classList.add("selected"); selectedTool = el.dataset.type; }; }); // Draw grid function drawGrid() { ctx.strokeStyle = "#222"; for (let x = 0; x < canvas.width; x += GRID_SIZE) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke(); } for (let y = 0; y < canvas.height; y += GRID_SIZE) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); } } // Draw objects function drawObjects() { objects.forEach(obj => { if (obj.type === "block") { ctx.fillStyle = "#00aaff"; ctx.fillRect(obj.x, obj.y, GRID_SIZE, GRID_SIZE); } if (obj.type === "spike") { ctx.fillStyle = "#ff4444"; ctx.beginPath(); ctx.moveTo(obj.x, obj.y + GRID_SIZE); ctx.lineTo(obj.x + GRID_SIZE / 2, obj.y); ctx.lineTo(obj.x + GRID_SIZE, obj.y + GRID_SIZE); ctx.closePath(); ctx.fill(); } if (obj.type === "orb") { ctx.fillStyle = "#00ff88"; ctx.beginPath(); ctx.arc(obj.x + GRID_SIZE/2, obj.y + GRID_SIZE/2, 10, 0, Math.PI * 2); ctx.fill(); } }); } // Main draw function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawGrid(); drawObjects(); } // Snap to grid function snap(value) { return Math.floor(value / GRID_SIZE) * GRID_SIZE; } // Place object canvas.addEventListener("click", (e) => { const rect = canvas.getBoundingClientRect(); const obj = { x: snap(e.clientX - rect.left), y: snap(e.clientY - rect.top), type: selectedTool }; ws.send(JSON.stringify({ type: "add", object: obj })); }); // Multiplayer sync ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === "init") { objects = data.level; } if (data.type === "add") { objects.push(data.object); } draw(); };