about summary refs log tree commit diff stats
path: root/html/space/renderer.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/space/renderer.js')
-rw-r--r--html/space/renderer.js358
1 files changed, 358 insertions, 0 deletions
diff --git a/html/space/renderer.js b/html/space/renderer.js
new file mode 100644
index 0000000..04646cf
--- /dev/null
+++ b/html/space/renderer.js
@@ -0,0 +1,358 @@
+// Renderer module using HTML5 Canvas
+import { getPlayerState, getWeaponStates } from './physics.js';
+import { getGameState } from './gameState.js';
+
+// Import weapon constants
+import {
+    PRIMARY_COOLDOWN,
+    SECONDARY_COOLDOWN,
+    PRIMARY_BURST_COUNT,
+    PRIMARY_BURST_DELAY
+} from './physics.js';
+
+let canvas;
+let ctx;
+let width;
+let height;
+
+// Star field
+let starfield = [];  // Declare starfield array
+const NUM_STARS = 2000;  // Increased from 1000
+const STAR_FIELD_DEPTH = 20000;  // Increased from 2000
+
+// HUD constants
+const HUD_COLOR = '#00ff00';
+const HUD_ALPHA = 0.7;
+const RADAR_RADIUS = 100;
+const RADAR_CENTER_X = 100;
+const RADAR_CENTER_Y = 100;
+const RADAR_SCALE = 0.1; // Scale factor for radar display
+const TARGET_LOCK_COLOR = '#ff0000';
+const TARGET_LOCK_THRESHOLD = 20; // Pixels from center to consider locked
+
+// Initialize the renderer
+export function initRenderer() {
+    console.log('Initializing renderer...');
+    canvas = document.getElementById('gameCanvas');
+    ctx = canvas.getContext('2d');
+    
+    // Set canvas size
+    width = canvas.width = window.innerWidth;
+    height = canvas.height = window.innerHeight;
+    
+    // Initialize starfield
+    console.log('Creating starfield with', NUM_STARS, 'stars...');
+    starfield = Array.from({ length: NUM_STARS }, () => ({
+        x: (Math.random() - 0.5) * STAR_FIELD_DEPTH,
+        y: (Math.random() - 0.5) * STAR_FIELD_DEPTH,
+        z: Math.random() * STAR_FIELD_DEPTH,
+        size: Math.random() * 2 + 1
+    }));
+    console.log('Starfield initialized');
+}
+
+// Project 3D point to 2D screen coordinates
+function projectPoint(x, y, z) {
+    if (z <= 0) return null; // Behind camera
+    
+    const scale = 2000 / z; // Increased scale factor
+    return {
+        x: width/2 + x * scale,
+        y: height/2 + y * scale,
+        scale
+    };
+}
+
+// Check if any enemy ship is in targeting range
+function getTargetLock(player, gameState) {
+    const centerX = width / 2;
+    const centerY = height / 2;
+    
+    for (const ship of gameState.enemyShips) {
+        const projected = projectPoint(ship.x - player.x, ship.y - player.y, ship.z - player.z);
+        if (projected) {
+            const distance = Math.sqrt(
+                Math.pow(projected.x - centerX, 2) +
+                Math.pow(projected.y - centerY, 2)
+            );
+            
+            if (distance < TARGET_LOCK_THRESHOLD) {
+                return {
+                    ship,
+                    distance
+                };
+            }
+        }
+    }
+    return null;
+}
+
+// Draw radar/minimap
+function drawRadar(player, gameState, targetLock) {
+    // Save context
+    ctx.save();
+    
+    // Set radar style
+    ctx.strokeStyle = targetLock ? TARGET_LOCK_COLOR : HUD_COLOR;
+    ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+    ctx.lineWidth = 1;
+    
+    // Draw radar background
+    ctx.beginPath();
+    ctx.arc(RADAR_CENTER_X, RADAR_CENTER_Y, RADAR_RADIUS, 0, Math.PI * 2);
+    ctx.fill();
+    ctx.stroke();
+    
+    // Draw radar grid
+    ctx.beginPath();
+    ctx.moveTo(RADAR_CENTER_X - RADAR_RADIUS, RADAR_CENTER_Y);
+    ctx.lineTo(RADAR_CENTER_X + RADAR_RADIUS, RADAR_CENTER_Y);
+    ctx.moveTo(RADAR_CENTER_X, RADAR_CENTER_Y - RADAR_RADIUS);
+    ctx.lineTo(RADAR_CENTER_X, RADAR_CENTER_Y + RADAR_RADIUS);
+    ctx.stroke();
+    
+    // Draw objects on radar
+    ctx.fillStyle = HUD_COLOR;
+    
+    // Draw planets
+    gameState.planets.forEach(planet => {
+        const dx = (planet.x - player.x) * RADAR_SCALE;
+        const dy = (planet.z - player.z) * RADAR_SCALE;
+        const distance = Math.sqrt(dx * dx + dy * dy);
+        
+        if (distance < RADAR_RADIUS) {
+            ctx.beginPath();
+            ctx.arc(
+                RADAR_CENTER_X + dx,
+                RADAR_CENTER_Y + dy,
+                5,
+                0,
+                Math.PI * 2
+            );
+            ctx.fill();
+        }
+    });
+    
+    // Draw enemy ships
+    gameState.enemyShips.forEach(ship => {
+        const dx = (ship.x - player.x) * RADAR_SCALE;
+        const dy = (ship.z - player.z) * RADAR_SCALE;
+        const distance = Math.sqrt(dx * dx + dy * dy);
+        
+        if (distance < RADAR_RADIUS) {
+            ctx.beginPath();
+            ctx.arc(
+                RADAR_CENTER_X + dx,
+                RADAR_CENTER_Y + dy,
+                4,
+                0,
+                Math.PI * 2
+            );
+            ctx.fill();
+        }
+    });
+    
+    // Restore context
+    ctx.restore();
+}
+
+// Draw speed and direction indicators
+function drawSpeedIndicator(player, targetLock) {
+    ctx.save();
+    ctx.fillStyle = targetLock ? TARGET_LOCK_COLOR : HUD_COLOR;
+    ctx.font = '14px monospace';
+    
+    // Calculate speed from velocity components
+    const speed = Math.sqrt(
+        player.vx * player.vx +
+        player.vy * player.vy +
+        player.vz * player.vz
+    );
+    
+    // Draw speed
+    ctx.fillText(`Speed: ${speed.toFixed(2)}`, 20, height - 40);
+    
+    // Draw direction (using x and z components for heading)
+    const direction = Math.atan2(player.vx, player.vz);
+    ctx.fillText(`Heading: ${(direction * 180 / Math.PI).toFixed(1)}°`, 20, height - 20);
+    
+    ctx.restore();
+}
+
+// Draw enhanced targeting reticle
+function drawTargetingReticle(player, gameState) {
+    ctx.save();
+    
+    // Check for target lock
+    const targetLock = getTargetLock(player, gameState);
+    const currentColor = targetLock ? TARGET_LOCK_COLOR : HUD_COLOR;
+    
+    ctx.strokeStyle = currentColor;
+    ctx.lineWidth = 1;
+    
+    // Outer circle
+    ctx.beginPath();
+    ctx.arc(width/2, height/2, 20, 0, Math.PI * 2);
+    ctx.stroke();
+    
+    // Inner crosshair
+    ctx.beginPath();
+    ctx.moveTo(width/2 - 10, height/2);
+    ctx.lineTo(width/2 + 10, height/2);
+    ctx.moveTo(width/2, height/2 - 10);
+    ctx.lineTo(width/2, height/2 + 10);
+    ctx.stroke();
+    
+    // Target brackets
+    ctx.beginPath();
+    ctx.moveTo(width/2 - 30, height/2 - 30);
+    ctx.lineTo(width/2 - 20, height/2 - 30);
+    ctx.lineTo(width/2 - 20, height/2 - 20);
+    ctx.moveTo(width/2 + 30, height/2 - 30);
+    ctx.lineTo(width/2 + 20, height/2 - 30);
+    ctx.lineTo(width/2 + 20, height/2 - 20);
+    ctx.moveTo(width/2 - 30, height/2 + 30);
+    ctx.lineTo(width/2 - 20, height/2 + 30);
+    ctx.lineTo(width/2 - 20, height/2 + 20);
+    ctx.moveTo(width/2 + 30, height/2 + 30);
+    ctx.lineTo(width/2 + 20, height/2 + 30);
+    ctx.lineTo(width/2 + 20, height/2 + 20);
+    ctx.stroke();
+    
+    // Draw target lock indicator if locked
+    if (targetLock) {
+        // Draw pulsing circle around target
+        const pulseSize = 30 + Math.sin(Date.now() * 0.01) * 5;
+        ctx.beginPath();
+        ctx.arc(width/2, height/2, pulseSize, 0, Math.PI * 2);
+        ctx.stroke();
+        
+        // Draw target distance
+        ctx.fillStyle = currentColor;
+        ctx.font = '14px monospace';
+        ctx.fillText(`Target Lock: ${targetLock.distance.toFixed(1)}`, width/2 - 50, height/2 + 50);
+    }
+    
+    ctx.restore();
+}
+
+// Draw weapon cooldown indicators
+function drawWeaponCooldowns() {
+    const weaponStates = getWeaponStates();
+    ctx.save();
+    ctx.fillStyle = HUD_COLOR;
+    ctx.font = '14px monospace';
+
+    // Primary weapon cooldown (bottom left)
+    const primaryCooldown = weaponStates.primary.cooldown / PRIMARY_COOLDOWN;
+    ctx.fillText('Primary:', 20, height - 80);
+    ctx.fillStyle = `rgba(0, 255, 0, ${primaryCooldown})`;
+    ctx.fillRect(20, height - 70, 100, 10);
+    ctx.strokeStyle = HUD_COLOR;
+    ctx.strokeRect(20, height - 70, 100, 10);
+
+    // Secondary weapon cooldown (bottom left, below primary)
+    const secondaryCooldown = weaponStates.secondary.cooldown / SECONDARY_COOLDOWN;
+    ctx.fillStyle = HUD_COLOR;
+    ctx.fillText('Secondary:', 20, height - 50);
+    ctx.fillStyle = `rgba(0, 255, 0, ${secondaryCooldown})`;
+    ctx.fillRect(20, height - 40, 100, 10);
+    ctx.strokeStyle = HUD_COLOR;
+    ctx.strokeRect(20, height - 40, 100, 10);
+
+    // Draw burst indicator for primary weapon
+    if (weaponStates.primary.burstCount > 0) {
+        ctx.fillStyle = HUD_COLOR;
+        ctx.fillText(`Burst: ${weaponStates.primary.burstCount}`, 20, height - 20);
+    }
+
+    ctx.restore();
+}
+
+// Main render function
+export function render() {
+    const player = getPlayerState();
+    const gameState = getGameState();
+    const targetLock = getTargetLock(player, gameState);
+
+    // Clear canvas
+    ctx.fillStyle = '#000000';
+    ctx.fillRect(0, 0, canvas.width, canvas.height);
+    
+    // Draw starfield
+    let starsRendered = 0;
+    starfield.forEach(star => {
+        // Calculate star position relative to player
+        let relativeX = star.x - player.x;
+        let relativeY = star.y - player.y;
+        let relativeZ = star.z - player.z;
+        
+        // Apply player rotation
+        let rotatedX = relativeX * Math.cos(player.rotation) - relativeY * Math.sin(player.rotation);
+        let rotatedY = relativeX * Math.sin(player.rotation) + relativeY * Math.cos(player.rotation);
+        let rotatedZ = relativeZ;
+        
+        // Project to screen coordinates
+        if (rotatedZ > 0) {
+            const projected = projectPoint(rotatedX, rotatedY, rotatedZ);
+            if (projected) {
+                const brightness = Math.min(1, 2000 / rotatedZ);
+                ctx.fillStyle = `rgba(255, 255, 255, ${brightness})`;
+                ctx.beginPath();
+                ctx.arc(projected.x, projected.y, star.size * brightness, 0, Math.PI * 2);
+                ctx.fill();
+                starsRendered++;
+            }
+        }
+    });
+    
+    // Debug output
+    if (Math.random() < 0.01) { // Only log occasionally to avoid spam
+        console.log('Stars rendered:', starsRendered);
+    }
+
+    // Draw planets
+    gameState.planets.forEach(planet => {
+        const projected = projectPoint(planet.x - player.x, planet.y - player.y, planet.z - player.z);
+        if (projected) {
+            const radius = planet.radius * projected.scale;
+            ctx.fillStyle = planet.color;
+            ctx.beginPath();
+            ctx.arc(projected.x, projected.y, radius, 0, Math.PI * 2);
+            ctx.fill();
+        }
+    });
+
+    // Draw enemy ships
+    gameState.enemyShips.forEach(ship => {
+        const projected = projectPoint(ship.x - player.x, ship.y - player.y, ship.z - player.z);
+        if (projected) {
+            const size = 20 * projected.scale;
+            ctx.fillStyle = '#ff0000';
+            ctx.beginPath();
+            ctx.moveTo(projected.x, projected.y - size);
+            ctx.lineTo(projected.x + size, projected.y + size);
+            ctx.lineTo(projected.x - size, projected.y + size);
+            ctx.closePath();
+            ctx.fill();
+        }
+    });
+
+    // Draw projectiles
+    gameState.projectiles.forEach(projectile => {
+        const projected = projectPoint(projectile.x - player.x, projectile.y - player.y, projectile.z - player.z);
+        if (projected) {
+            const size = 3 * projected.scale;
+            ctx.fillStyle = projectile.type === 'primary' ? '#ffff00' : '#00ffff';
+            ctx.beginPath();
+            ctx.arc(projected.x, projected.y, size, 0, Math.PI * 2);
+            ctx.fill();
+        }
+    });
+
+    // Draw HUD elements
+    drawRadar(player, gameState, targetLock);
+    drawSpeedIndicator(player, targetLock);
+    drawTargetingReticle(player, gameState);
+    drawWeaponCooldowns();
+} 
\ No newline at end of file