const Camera = { x: 0, y: 0, centerOn(hex) { const pixelCoord = HexGrid.toPixel(hex); // Calculate desired camera position this.x = pixelCoord.x - state.canvas.width / 2; this.y = pixelCoord.y - state.canvas.height / 2; // Calculate grid dimensions const gridPixelWidth = Config.hex.GRID_SIZE * Config.hex.WIDTH; const gridPixelHeight = Config.hex.GRID_SIZE * Config.hex.HEIGHT; // Calculate grid bounds (accounting for centered grid) const minX = -gridPixelWidth / 2; const maxX = gridPixelWidth / 2 - state.canvas.width; const minY = -gridPixelHeight / 2; const maxY = gridPixelHeight / 2 - state.canvas.height; // Keep camera within grid bounds this.x = Math.max(minX, Math.min(this.x, maxX)); this.y = Math.max(minY, Math.min(this.y, maxY)); // Round to prevent sub-pixel rendering this.x = Math.round(this.x); this.y = Math.round(this.y); }, smoothFollow(target) { const targetPixel = HexGrid.toPixel(target); const screenX = Math.round(targetPixel.x - this.x); const screenY = Math.round(targetPixel.y - this.y); const centerX = state.canvas.width / 2; const centerY = state.canvas.height / 2; // Determine if we're on a narrow screen const isNarrowScreen = state.canvas.width <= Config.camera.NARROW_SCREEN_THRESHOLD; // Calculate dynamic deadzones based on screen size const deadzoneX = Math.min( Math.max( state.canvas.width * ( isNarrowScreen ? Config.camera.DEADZONE_RATIO_X.NARROW : Config.camera.DEADZONE_RATIO_X.WIDE ), Config.camera.MIN_DEADZONE ), Config.camera.MAX_DEADZONE ); const deadzoneY = Math.min( Math.max(state.canvas.height * Config.camera.DEADZONE_RATIO_Y, Config.camera.MIN_DEADZONE ), Config.camera.MAX_DEADZONE ); const deltaX = screenX - centerX; const deltaY = screenY - centerY; // Use more aggressive follow speed for narrow screens const followSpeed = isNarrowScreen ? Config.camera.FOLLOW_SPEED * 1.5 : Config.camera.FOLLOW_SPEED; // Ensure camera moves if player is near screen edges if (Math.abs(deltaX) > deadzoneX) { const adjustX = deltaX - (deltaX > 0 ? deadzoneX : -deadzoneX); this.x += Math.round(adjustX * followSpeed); } if (Math.abs(deltaY) > deadzoneY) { const adjustY = deltaY - (deltaY > 0 ? deadzoneY : -deadzoneY); this.y += Math.round(adjustY * followSpeed); } // Calculate grid bounds (accounting for centered grid) const gridPixelWidth = Config.hex.GRID_SIZE * Config.hex.WIDTH; const gridPixelHeight = Config.hex.GRID_SIZE * Config.hex.HEIGHT; const minX = -gridPixelWidth / 2; const maxX = gridPixelWidth / 2 - state.canvas.width; const minY = -gridPixelHeight / 2; const maxY = gridPixelHeight / 2 - state.canvas.height; // Keep camera within grid bounds this.x = Math.max(minX, Math.min(this.x, maxX)); this.y = Math.max(minY, Math.min(this.y, maxY)); } };