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;
}
}
}
}