feat: Add mouse-based world navigation with drag and touch support

This commit is contained in:
Kacper Kostka (aider) 2025-04-04 11:07:30 +02:00
parent dbcf3a0e61
commit eb9900478d
3 changed files with 89 additions and 26 deletions

View File

@ -6,7 +6,7 @@
<title>Pixel Sand Simulation</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<body oncontextmenu="return false;">
<div class="container">
<div class="controls">
<div class="tools">
@ -23,6 +23,7 @@
<div class="info">
<span id="coords">Chunk: 0,0</span>
<span id="fps">FPS: 0</span>
<span class="help-text">Hold Shift/Ctrl or right-click to drag the world</span>
</div>
</div>
<canvas id="simulation-canvas"></canvas>

108
script.js
View File

@ -17,6 +17,8 @@ const WALL = 3;
let canvas, ctx;
let currentTool = SAND;
let isDrawing = false;
let isDragging = false;
let lastMouseX, lastMouseY;
let lastFrameTime = 0;
let fps = 0;
let worldOffsetX = 0;
@ -44,15 +46,15 @@ window.onload = function() {
document.getElementById('move-down').addEventListener('click', () => moveWorld(0, CHUNK_SIZE/2));
// Drawing events
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseleave', stopDrawing);
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
canvas.addEventListener('mouseleave', handleMouseUp);
// Touch events for mobile
canvas.addEventListener('touchstart', handleTouchStart);
canvas.addEventListener('touchmove', handleTouchMove);
canvas.addEventListener('touchend', stopDrawing);
canvas.addEventListener('touchend', handleMouseUp);
// Initialize the first chunk
getOrCreateChunk(0, 0);
@ -79,28 +81,51 @@ function setTool(tool) {
}
}
function startDrawing(e) {
isDrawing = true;
draw(e);
}
function stopDrawing() {
isDrawing = false;
}
function draw(e) {
if (!isDrawing) return;
function handleMouseDown(e) {
const rect = canvas.getBoundingClientRect();
let x, y;
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (e.type.startsWith('touch')) {
x = e.touches[0].clientX - rect.left;
y = e.touches[0].clientY - rect.top;
// Right mouse button for dragging the world
if (e.button === 2 || e.ctrlKey || e.shiftKey) {
isDragging = true;
lastMouseX = x;
lastMouseY = y;
} else {
x = e.clientX - rect.left;
y = e.clientY - rect.top;
// Left mouse button for drawing
isDrawing = true;
draw(x, y);
}
}
function handleMouseMove(e) {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (isDragging) {
// Calculate how much the mouse has moved
const dx = x - lastMouseX;
const dy = y - lastMouseY;
// Move the world in the opposite direction (divide by pixel size to convert to world coordinates)
moveWorld(-dx / PIXEL_SIZE, -dy / PIXEL_SIZE);
// Update the last mouse position
lastMouseX = x;
lastMouseY = y;
} else if (isDrawing) {
draw(x, y);
}
}
function handleMouseUp(e) {
isDrawing = false;
isDragging = false;
}
function draw(x, y) {
if (!isDrawing) return;
// Convert to world coordinates
const worldX = Math.floor(x / PIXEL_SIZE) + worldOffsetX;
@ -116,12 +141,45 @@ function draw(e) {
function handleTouchStart(e) {
e.preventDefault();
startDrawing(e);
// Check if we have multiple touch points (for dragging)
if (e.touches.length > 1) {
isDragging = true;
lastMouseX = e.touches[0].clientX;
lastMouseY = e.touches[0].clientY;
} else {
// Single touch for drawing
isDrawing = true;
const rect = canvas.getBoundingClientRect();
const x = e.touches[0].clientX - rect.left;
const y = e.touches[0].clientY - rect.top;
draw(x, y);
}
}
function handleTouchMove(e) {
e.preventDefault();
draw(e);
const rect = canvas.getBoundingClientRect();
if (isDragging && e.touches.length > 1) {
// Calculate how much the touch has moved
const x = e.touches[0].clientX;
const y = e.touches[0].clientY;
const dx = x - lastMouseX;
const dy = y - lastMouseY;
// Move the world in the opposite direction
moveWorld(-dx / PIXEL_SIZE, -dy / PIXEL_SIZE);
// Update the last touch position
lastMouseX = x;
lastMouseY = y;
} else if (isDrawing) {
const x = e.touches[0].clientX - rect.left;
const y = e.touches[0].clientY - rect.top;
draw(x, y);
}
}
function moveWorld(dx, dy) {

View File

@ -54,6 +54,10 @@ body {
font-size: 14px;
}
.help-text {
color: #aaa;
}
#simulation-canvas {
flex-grow: 1;
background-color: #000;