about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2024-12-27 08:08:29 -0500
committerelioat <elioat@tilde.institute>2024-12-27 08:08:29 -0500
commitea50f9ee0875b9230174996af0f92922f747b974 (patch)
tree9c419f1af57bd6195a559137d9a004aabc4fb96a
parent6ea87b4e0a8cddca95c0a4f2b36264e7430e74aa (diff)
downloadtour-ea50f9ee0875b9230174996af0f92922f747b974.tar.gz
*
-rw-r--r--html/rogue/index.html3
-rw-r--r--html/rogue/js/camera.js19
-rw-r--r--html/rogue/js/config.js8
-rw-r--r--html/rogue/js/game.js155
-rw-r--r--html/rogue/js/hexGrid.js68
-rw-r--r--html/rogue/js/player.js30
6 files changed, 165 insertions, 118 deletions
diff --git a/html/rogue/index.html b/html/rogue/index.html
index 79aac67..46a49e3 100644
--- a/html/rogue/index.html
+++ b/html/rogue/index.html
@@ -19,6 +19,9 @@
 </head>
 <body>
     <canvas id="gameCanvas"></canvas>
+    <script src="js/config.js"></script>
+    <script src="js/hexGrid.js"></script>
+    <script src="js/camera.js"></script>
     <script src="js/player.js"></script>
     <script src="js/game.js"></script>
 </body>
diff --git a/html/rogue/js/camera.js b/html/rogue/js/camera.js
new file mode 100644
index 0000000..e7b2475
--- /dev/null
+++ b/html/rogue/js/camera.js
@@ -0,0 +1,19 @@
+const Camera = {
+    x: 0,
+    y: 0,
+    
+    centerOn(hex) {
+        const pixelCoord = HexGrid.toPixel(hex);
+        this.x = pixelCoord.x - state.canvas.width / 2;
+        this.y = pixelCoord.y - state.canvas.height / 2;
+    },
+
+    smoothFollow(target) {
+        const targetPixel = HexGrid.toPixel(target);
+        const targetX = targetPixel.x - state.canvas.width / 2;
+        const targetY = targetPixel.y - state.canvas.height / 2;
+        
+        this.x += (targetX - this.x) * 0.1;
+        this.y += (targetY - this.y) * 0.1;
+    }
+}; 
\ No newline at end of file
diff --git a/html/rogue/js/config.js b/html/rogue/js/config.js
new file mode 100644
index 0000000..aea067f
--- /dev/null
+++ b/html/rogue/js/config.js
@@ -0,0 +1,8 @@
+const Config = {
+    colors: {
+        BACKGROUND: 'rgba(135, 206, 235, 0.3)', // Pale blue
+        GRID: '#333333',                        // Off-black for grid lines
+        PLAYER: 'red',                          // Player color
+        HEX_FILL: '#ffffff'                     // White fill for passable hexes
+    }
+}; 
\ No newline at end of file
diff --git a/html/rogue/js/game.js b/html/rogue/js/game.js
index 0dde858..40c8826 100644
--- a/html/rogue/js/game.js
+++ b/html/rogue/js/game.js
@@ -1,94 +1,47 @@
-// Constants for hex grid
-const HEX_SIZE = 20; // Fixed hex size
-const HEX_WIDTH = HEX_SIZE * 2;
-const HEX_HEIGHT = Math.sqrt(3) * HEX_SIZE;
-const GRID_SIZE = 100; // Number of hexes in each dimension
-const HEX_COLOR = '#333333'; // Off-black color for hex grid
+const FPS = 60;
+const FRAME_TIME = 1000 / FPS;
+let lastFrameTime = 0;
 
-// Game state
 const state = {
     canvas: null,
-    ctx: null,
-    camera: { x: 0, y: 0 }, // Camera position in pixel coordinates
-    hexGrid: [], // Will store hex grid data
+    ctx: null
 };
 
-// Initialize the game
 function init() {
     state.canvas = document.getElementById('gameCanvas');
     state.ctx = state.canvas.getContext('2d');
     
-    // Initialize player
     player.init();
     
     function resize() {
         state.canvas.width = window.innerWidth;
         state.canvas.height = window.innerHeight;
-        // Center camera on player initially
-        centerCameraOnHex(player.position);
+        Camera.centerOn(player.position);
     }
     
     window.addEventListener('resize', resize);
     resize();
     state.canvas.addEventListener('click', handleClick);
-    requestAnimationFrame(gameLoop);
-}
-
-// Center camera on a specific hex
-function centerCameraOnHex(hex) {
-    const pixelCoord = hexToPixel(hex);
-    state.camera.x = pixelCoord.x - state.canvas.width / 2;
-    state.camera.y = pixelCoord.y - state.canvas.height / 2;
-}
-
-// Smoothly move camera to target position
-function updateCamera() {
-    const currentPos = player.getCurrentPosition();
-    const targetPixel = hexToPixel(currentPos);
-    const targetCameraX = targetPixel.x - state.canvas.width / 2;
-    const targetCameraY = targetPixel.y - state.canvas.height / 2;
-    
-    // Smooth camera movement
-    state.camera.x += (targetCameraX - state.camera.x) * 0.1;
-    state.camera.y += (targetCameraY - state.camera.y) * 0.1;
-}
-
-// Convert hex coordinates to pixel coordinates
-function hexToPixel(hex) {
-    const x = HEX_SIZE * (3/2 * hex.q);
-    const y = HEX_SIZE * (Math.sqrt(3)/2 * hex.q + Math.sqrt(3) * hex.r);
-    return {x, y};
-}
-
-// Convert pixel coordinates to hex coordinates (adjusted for camera position)
-function pixelToHex(screenX, screenY) {
-    const x = screenX + state.camera.x;
-    const y = screenY + state.camera.y;
     
-    const q = (2/3 * x) / HEX_SIZE;
-    const r = (-1/3 * x + Math.sqrt(3)/3 * y) / HEX_SIZE;
-    return hexRound(q, r);
+    requestAnimationFrame(gameLoop);
 }
 
 // Draw a single hex
-function drawHex(ctx, x, y) {
-    // Adjust position for camera
-    const screenX = x - state.camera.x;
-    const screenY = y - state.camera.y;
+function drawHex(ctx, x, y, hex) {
+    const screenX = x - Camera.x;
+    const screenY = y - Camera.y;
     
-    // Only draw if hex is visible on screen (with padding)
-    if (screenX < -HEX_WIDTH || screenX > state.canvas.width + HEX_WIDTH ||
-        screenY < -HEX_HEIGHT || screenY > state.canvas.height + HEX_HEIGHT) {
+    // Only draw if hex is visible on screen (with some padding)
+    if (screenX < -HexGrid.WIDTH || screenX > state.canvas.width + HexGrid.WIDTH ||
+        screenY < -HexGrid.HEIGHT || screenY > state.canvas.height + HexGrid.HEIGHT) {
         return;
     }
     
-    ctx.strokeStyle = HEX_COLOR;
-    ctx.lineWidth = 1;
     ctx.beginPath();
     for (let i = 0; i < 6; i++) {
         const angle = 2 * Math.PI / 6 * i;
-        const xPos = screenX + HEX_SIZE * Math.cos(angle);
-        const yPos = screenY + HEX_SIZE * Math.sin(angle);
+        const xPos = screenX + HexGrid.SIZE * Math.cos(angle);
+        const yPos = screenY + HexGrid.SIZE * Math.sin(angle);
         if (i === 0) {
             ctx.moveTo(xPos, yPos);
         } else {
@@ -96,77 +49,57 @@ function drawHex(ctx, x, y) {
         }
     }
     ctx.closePath();
+
+    // Fill hex with appropriate color
+    if (HexGrid.isPassable(hex)) {
+        ctx.fillStyle = Config.colors.HEX_FILL;
+    } else {
+        ctx.fillStyle = Config.colors.BACKGROUND;
+    }
+    ctx.fill();
+    
+    // Draw border
+    ctx.strokeStyle = HexGrid.COLOR;
+    ctx.lineWidth = 1;
     ctx.stroke();
 }
 
-// Calculate which hexes should be drawn
-function calculateViewportHexes() {
-    const hexes = [];
-    const halfGrid = Math.floor(GRID_SIZE / 2);
-    
-    for (let r = -halfGrid; r < halfGrid; r++) {
-        for (let q = -halfGrid; q < halfGrid; q++) {
-            hexes.push({q, r});
-        }
+function gameLoop(currentTime) {
+    if (currentTime - lastFrameTime < FRAME_TIME) {
+        requestAnimationFrame(gameLoop);
+        return;
     }
-    return hexes;
-}
+    
+    const deltaTime = currentTime - lastFrameTime;
+    lastFrameTime = currentTime;
 
-// Main game loop
-function gameLoop() {
+    // Clear the entire canvas first
     state.ctx.clearRect(0, 0, state.canvas.width, state.canvas.height);
     
-    // Update game state
+    // Then fill with background color
+    state.ctx.fillStyle = Config.colors.BACKGROUND;
+    state.ctx.fillRect(0, 0, state.canvas.width, state.canvas.height);
+    
     player.update();
-    updateCamera();
+    Camera.smoothFollow(player.getCurrentPosition());
     
-    // Draw hex grid
-    const viewportHexes = calculateViewportHexes();
-    viewportHexes.forEach(hex => {
-        const pixel = hexToPixel(hex);
-        drawHex(state.ctx, pixel.x, pixel.y);
+    HexGrid.getViewportHexes().forEach(hex => {
+        const pixel = HexGrid.toPixel(hex);
+        drawHex(state.ctx, pixel.x, pixel.y, hex);
     });
     
-    // Draw player
-    player.draw(state.ctx, hexToPixel, state.camera, HEX_SIZE);
+    player.draw(state.ctx, HexGrid.toPixel.bind(HexGrid), Camera, HexGrid.SIZE);
     
     requestAnimationFrame(gameLoop);
 }
 
-// Handle click/tap with camera offset
 function handleClick(event) {
     const rect = state.canvas.getBoundingClientRect();
     const x = event.clientX - rect.left;
     const y = event.clientY - rect.top;
     
-    const hexCoord = pixelToHex(x, y);
+    const hexCoord = HexGrid.fromPixel(x + Camera.x, y + Camera.y);
     player.moveTo(hexCoord);
 }
 
-// Round hex coordinates to nearest hex
-function hexRound(q, r) {
-    let x = q;
-    let z = r;
-    let y = -x-z;
-
-    let rx = Math.round(x);
-    let ry = Math.round(y);
-    let rz = Math.round(z);
-
-    const x_diff = Math.abs(rx - x);
-    const y_diff = Math.abs(ry - y);
-    const z_diff = Math.abs(rz - z);
-
-    if (x_diff > y_diff && x_diff > z_diff) {
-        rx = -ry-rz;
-    } else if (y_diff > z_diff) {
-        ry = -rx-rz;
-    } else {
-        rz = -rx-ry;
-    }
-
-    return {q: rx, r: rz};
-}
-
-// Start the game
 init();
\ No newline at end of file
diff --git a/html/rogue/js/hexGrid.js b/html/rogue/js/hexGrid.js
new file mode 100644
index 0000000..c45c981
--- /dev/null
+++ b/html/rogue/js/hexGrid.js
@@ -0,0 +1,68 @@
+// Hex grid utilities and calculations
+const HexGrid = {
+    SIZE: 40,
+    COLOR: Config.colors.GRID,
+    GRID_SIZE: 10,
+    IMPASSABLE_COLOR: Config.colors.BACKGROUND,
+
+    get WIDTH() { return this.SIZE * 2 },
+    get HEIGHT() { return Math.sqrt(3) * this.SIZE },
+
+    // Convert hex coordinates to pixel coordinates
+    toPixel(hex) {
+        const x = this.SIZE * (3/2 * hex.q);
+        const y = this.SIZE * (Math.sqrt(3)/2 * hex.q + Math.sqrt(3) * hex.r);
+        return {x, y};
+    },
+
+    // Convert pixel coordinates to hex coordinates
+    fromPixel(x, y) {
+        const q = (2/3 * x) / this.SIZE;
+        const r = (-1/3 * x + Math.sqrt(3)/3 * y) / this.SIZE;
+        return this.round(q, r);
+    },
+
+    // Round hex coordinates to nearest hex
+    round(q, r) {
+        let x = q;
+        let z = r;
+        let y = -x-z;
+
+        let rx = Math.round(x);
+        let ry = Math.round(y);
+        let rz = Math.round(z);
+
+        const x_diff = Math.abs(rx - x);
+        const y_diff = Math.abs(ry - y);
+        const z_diff = Math.abs(rz - z);
+
+        if (x_diff > y_diff && x_diff > z_diff) {
+            rx = -ry-rz;
+        } else if (y_diff > z_diff) {
+            ry = -rx-rz;
+        } else {
+            rz = -rx-ry;
+        }
+
+        return {q: rx, r: rz};
+    },
+
+    // Calculate visible hexes
+    getViewportHexes() {
+        const hexes = [];
+        const halfGrid = Math.floor(this.GRID_SIZE / 2);
+        
+        for (let r = -halfGrid; r < halfGrid; r++) {
+            for (let q = -halfGrid; q < halfGrid; q++) {
+                hexes.push({q, r});
+            }
+        }
+        return hexes;
+    },
+
+    // Add this method to check if a hex is passable
+    isPassable(hex) {
+        const halfGrid = Math.floor(this.GRID_SIZE / 2);
+        return Math.abs(hex.q) < halfGrid && Math.abs(hex.r) < halfGrid;
+    }
+}; 
\ No newline at end of file
diff --git a/html/rogue/js/player.js b/html/rogue/js/player.js
index 5b4a875..9a25715 100644
--- a/html/rogue/js/player.js
+++ b/html/rogue/js/player.js
@@ -14,6 +14,12 @@ const player = {
         return this;
     },
 
+    // Check if a hex coordinate is within grid bounds
+    isValidHex(hex) {
+        const halfGrid = Math.floor(HexGrid.GRID_SIZE / 2);
+        return Math.abs(hex.q) < halfGrid && Math.abs(hex.r) < halfGrid;
+    },
+
     // Get neighbors that share an edge with the given hex
     getEdgeNeighbors(hex) {
         const directions = [
@@ -25,10 +31,13 @@ const player = {
             {q: 1, r: -1}   // Northeast
         ];
         
-        return directions.map(dir => ({
-            q: hex.q + dir.q,
-            r: hex.r + dir.r
-        }));
+        // Only return neighbors that are within grid bounds
+        return directions
+            .map(dir => ({
+                q: hex.q + dir.q,
+                r: hex.r + dir.r
+            }))
+            .filter(hex => this.isValidHex(hex));
     },
 
     // Find path from current position to target
@@ -65,10 +74,17 @@ const player = {
 
     // Start moving to a target hex
     moveTo(targetHex) {
+        // Only start new movement if we're not already moving and target is valid
         if (!this.target) {
+            // Check if target is within grid bounds
+            if (!this.isValidHex(targetHex)) {
+                return; // Ignore movement request if target is out of bounds
+            }
+
             const path = this.findPath(targetHex);
             if (path) {
-                this.path = path.slice(1); // Remove starting position
+                // Filter out any path points that would go out of bounds
+                this.path = path.slice(1).filter(hex => this.isValidHex(hex));
                 if (this.path.length > 0) {
                     this.target = this.path.shift();
                     this.movementProgress = 0;
@@ -117,14 +133,14 @@ const player = {
         const screenX = pixelPos.x - camera.x;
         const screenY = pixelPos.y - camera.y;
 
-        ctx.fillStyle = 'red';
+        ctx.fillStyle = Config.colors.PLAYER;
         ctx.beginPath();
         ctx.arc(screenX, screenY, HEX_SIZE/3, 0, Math.PI * 2);
         ctx.fill();
         
         // Optionally, draw the remaining path
         if (this.path.length > 0) {
-            ctx.strokeStyle = 'rgba(255,0,0,0.3)';
+            ctx.strokeStyle = Config.colors.PLAYER + '4D'; // 30% opacity version of player color
             ctx.beginPath();
             let lastPos = this.target || this.position;
             this.path.forEach(point => {