const canvas = document.getElementById('sand'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth - 12; canvas.height = window.innerHeight - 12; const gridSize = 10; const gridWidth = Math.floor(canvas.width / gridSize); const gridHeight = Math.floor(canvas.height / gridSize); const grid = Array(gridHeight).fill().map(() => Array(gridWidth).fill(0)); let mouseDown = false; let playerAdded = false; let keys = new Set(); canvas.addEventListener('mousedown', (e) => { mouseDown = true; addSand(e); }); canvas.addEventListener('mouseup', () => { mouseDown = false; }); canvas.addEventListener('mousemove', (e) => { if (mouseDown) { addSand(e); } }); canvas.addEventListener('touchstart', (e) => { mouseDown = true; e.preventDefault(); addSand(e.touches[0]); }); canvas.addEventListener('touchend', () => { mouseDown = false; }); canvas.addEventListener('touchmove', (e) => { if (mouseDown) { e.preventDefault(); addSand(e.touches[0]); } }); window.addEventListener('keydown', (e) => { keys.add(e.key); }); window.addEventListener('keyup', (e) => { keys.delete(e.key); }); window.addEventListener('keydown', (e) => { if (e.key === ' ' && !playerAdded) { addPlayer(); playerAdded = true; } }); window.addEventListener('keydown', (e) => { // reset the canvas if (e.key === 'r') { playerAdded = false; for (let y = 0; y < gridHeight; y++) { for (let x = 0; x < gridWidth; x++) { grid[y][x] = 0; } } return; } // move the character around for (let y = 0; y < gridHeight; y++) { for (let x = 0; x < gridWidth; x++) { if (grid[y][x] === 3) { if ((e.key === 'ArrowLeft' || e.key === 'a') && x > 0 && grid[y][x - 1] === 0) { grid[y][x] = 0; grid[y][x - 1] = 3; return; } else if ((e.key === 'ArrowRight' || e.key === 'd') && x < gridWidth - 1 && grid[y][x + 1] === 0) { grid[y][x] = 0; grid[y][x + 1] = 3; return; } else if (isJumpKey(e.key) && y < gridHeight - 1 && grid[y + 1][x] !== 0) { jumpPlayer(y, x); return; } } } } }); const jumpHeight = 10; const isJumpKey = key => { return key === ' ' || key === 'ArrowUp' || key === 'w'; } const jumpPlayer = (y, x) => { grid[y][x] = 0; grid[Math.max(y - jumpHeight, 0)][x] = 3; } const updateGrid = () => { for (let y = gridHeight - 2; y >= 0; y--) { for (let x = 0; x < gridWidth; x++) { if (grid[y][x] === 1) { if (grid[y + 1][x] === 0) { grid[y][x] = 0; grid[y + 1][x] = 1; } else if (x > 0 && grid[y + 1][x - 1] === 0) { grid[y][x] = 0; grid[y + 1][x - 1] = 1; } else if (x < gridWidth - 1 && grid[y + 1][x + 1] === 0) { grid[y][x] = 0; grid[y + 1][x + 1] = 1; } } else if (grid[y][x] === 3) { if (y < gridHeight - 1 && grid[y + 1][x] === 0) { grid[y][x] = 0; grid[y + 1][x] = 3; } } } } }; const drawGrid = () => { // clear the canvas ctx.fillStyle = 'beige'; ctx.fillRect(0, 0, canvas.width, canvas.height); // draw the sand and player ctx.fillStyle = 'black'; for (let y = 0; y < gridHeight; y++) { for (let x = 0; x < gridWidth; x++) { if (grid[y][x] === 1) { ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize); } else if (grid[y][x] === 3) { ctx.fillStyle = 'red'; ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize); ctx.fillStyle = 'black'; // Reset fill color to black after drawing the player } } } }; const framerate = 60; let lastFrameTime = 0; const gameLoop = (currentTime) => { const deltaTime = (currentTime - lastFrameTime) / 1000; if (deltaTime > 1 / framerate) { lastFrameTime = currentTime; updateGrid(); drawGrid(); } requestAnimationFrame(gameLoop); }; requestAnimationFrame(gameLoop); function addSand(e) { const rect = canvas.getBoundingClientRect(); const x = Math.floor((e.clientX - rect.left) / gridSize); const y = Math.floor((e.clientY - rect.top) / gridSize); if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) { grid[y][x] = 1; } } function addPlayer() { for (let y = 0; y < gridHeight; y++) { for (let x = 0; x < gridWidth; x++) { if (grid[y][x] === 1) { grid[Math.max(0, y - 10)][x] = 3; return; } } } }