SandGame/index.js

148 lines
No EOL
4.1 KiB
JavaScript

import { canvas, resize, cursor, brushSize, setBrushSize } from './state.js';
import { setupUI, handleInput, setLastPos, updateBrushUI } from './ui.js';
import { update } from './physics.js';
import { draw } from './renderer.js';
import { loadSettings, config, saveSettings } from './config.js';
let updateAccumulator = 0;
export function stepOnce() {
update();
draw();
}
function init() {
loadSettings();
if (config.brush?.size) {
setBrushSize(config.brush.size);
}
resize();
window.addEventListener('resize', resize);
setupUI();
// Input Handling
let isMouseDown = false;
let isRightClick = false;
canvas.addEventListener('contextmenu', (e) => e.preventDefault());
canvas.addEventListener('mousedown', (e) => {
isMouseDown = true;
isRightClick = (e.button === 2);
cursor.visible = true;
cursor.x = e.clientX;
cursor.y = e.clientY;
handleInput(e, isRightClick ? 'eraser' : null);
});
window.addEventListener('mouseup', () => {
isMouseDown = false;
isRightClick = false;
setLastPos(null);
});
canvas.addEventListener('mousemove', (e) => {
cursor.visible = true;
cursor.x = e.clientX;
cursor.y = e.clientY;
if (isMouseDown) {
handleInput(e, isRightClick ? 'eraser' : null);
}
});
canvas.addEventListener('mouseenter', () => {
cursor.visible = true;
});
canvas.addEventListener('mouseleave', () => {
cursor.visible = false;
setLastPos(null);
});
// Mouse wheel to change brush size
canvas.addEventListener('wheel', (e) => {
e.preventDefault();
const delta = e.deltaY < 0 ? 1 : -1;
setBrushSize(brushSize + delta);
config.brush.size = brushSize;
saveSettings();
updateBrushUI();
}, { passive: false });
// Touch Support
canvas.addEventListener('touchstart', (e) => {
isMouseDown = true;
if (e.touches.length > 0) {
cursor.visible = true;
cursor.x = e.touches[0].clientX;
cursor.y = e.touches[0].clientY;
}
handleInput(e);
e.preventDefault();
}, { passive: false });
canvas.addEventListener('touchend', (e) => {
if (e.touches.length === 0) {
isMouseDown = false;
cursor.visible = false;
setLastPos(null);
}
});
canvas.addEventListener('touchmove', (e) => {
if (e.touches.length > 0) {
cursor.visible = true;
cursor.x = e.touches[0].clientX;
cursor.y = e.touches[0].clientY;
}
if (isMouseDown) handleInput(e);
e.preventDefault();
}, { passive: false });
// Keyboard Shortcuts
window.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (e.code === 'Space') {
e.preventDefault();
config.time.paused = !config.time.paused;
saveSettings();
const pauseBtn = document.getElementById('togglePause');
if (pauseBtn) pauseBtn.textContent = config.time.paused ? '▶' : '⏸';
} else if (e.code === 'KeyS' || e.code === 'Period') {
if (config.time.paused) {
stepOnce();
}
} else if (e.code === 'BracketLeft') {
setBrushSize(brushSize - 1);
config.brush.size = brushSize;
saveSettings();
updateBrushUI();
} else if (e.code === 'BracketRight') {
setBrushSize(brushSize + 1);
config.brush.size = brushSize;
saveSettings();
updateBrushUI();
}
});
gameLoop();
}
function gameLoop() {
if (!config.time.paused) {
updateAccumulator += config.time.speed;
while (updateAccumulator >= 1) {
update();
updateAccumulator -= 1;
if (updateAccumulator > 30) {
updateAccumulator = 0;
break;
}
}
}
draw();
requestAnimationFrame(gameLoop);
}
init();