diff options
author | elioat <elioat@tilde.institute> | 2025-04-09 21:14:39 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-04-09 21:14:39 -0400 |
commit | e83bd303e3186fd7823b39678feed753c20736d1 (patch) | |
tree | cb6b9ce885d6d17435a6c94b2a2454a30ef52c89 /html/space/renderer.js | |
parent | e0e75864e0d9981236bd50e2febdd0edd95019ea (diff) | |
download | tour-e83bd303e3186fd7823b39678feed753c20736d1.tar.gz |
*
Diffstat (limited to 'html/space/renderer.js')
-rw-r--r-- | html/space/renderer.js | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/html/space/renderer.js b/html/space/renderer.js new file mode 100644 index 0000000..3df55a7 --- /dev/null +++ b/html/space/renderer.js @@ -0,0 +1,171 @@ +// Renderer module using HTML5 Canvas +import { getPlayerState } from './physics.js'; +import { getGameState } from './gameState.js'; + +let canvas; +let ctx; +let width; +let height; + +// Star field +const stars = []; +const NUM_STARS = 2000; // Increased from 1000 +const STAR_FIELD_DEPTH = 20000; // Increased from 2000 + +// Initialize the renderer +export function initRenderer() { + canvas = document.createElement('canvas'); + document.body.appendChild(canvas); + ctx = canvas.getContext('2d'); + + // Make canvas fullscreen + function resize() { + width = window.innerWidth; + height = window.innerHeight; + canvas.width = width; + canvas.height = height; + } + + window.addEventListener('resize', resize); + resize(); + + // Initialize star field + for (let i = 0; i < NUM_STARS; i++) { + stars.push({ + x: (Math.random() - 0.5) * width * 4, // Increased spread + y: (Math.random() - 0.5) * height * 4, // Increased spread + z: Math.random() * STAR_FIELD_DEPTH, + size: Math.random() * 2 + }); + } +} + +// Project 3D point to 2D screen coordinates +function projectPoint(point, player) { + // Calculate relative position to player + const relativeX = point.x - player.position.x; + const relativeY = point.y - player.position.y; + const relativeZ = point.z - player.position.z; + + // Apply player rotation + const cosY = Math.cos(player.rotation.y); + const sinY = Math.sin(player.rotation.y); + const cosX = Math.cos(player.rotation.x); + const sinX = Math.sin(player.rotation.x); + + // Rotate around Y axis (yaw) + let rotatedX = relativeX * cosY - relativeZ * sinY; + let rotatedZ = relativeX * sinY + relativeZ * cosY; + + // Rotate around X axis (pitch) + let rotatedY = relativeY * cosX - rotatedZ * sinX; + rotatedZ = relativeY * sinX + rotatedZ * cosX; + + // Project to screen + if (rotatedZ <= 0) return null; // Behind camera + + const scale = 1000 / rotatedZ; + return { + x: width/2 + rotatedX * scale, + y: height/2 + rotatedY * scale, + scale + }; +} + +// Main render function +export function render() { + const player = getPlayerState(); + const gameState = getGameState(); + + // Clear canvas + ctx.fillStyle = 'black'; + ctx.fillRect(0, 0, width, height); + + // Draw star field + ctx.fillStyle = 'white'; + stars.forEach(star => { + // Calculate star position relative to player + const relativeX = star.x - player.position.x; + const relativeY = star.y - player.position.y; + const relativeZ = star.z - player.position.z; + + // Apply player rotation + const cosY = Math.cos(player.rotation.y); + const sinY = Math.sin(player.rotation.y); + const cosX = Math.cos(player.rotation.x); + const sinX = Math.sin(player.rotation.x); + + // Rotate around Y axis (yaw) + let rotatedX = relativeX * cosY - relativeZ * sinY; + let rotatedZ = relativeX * sinY + relativeZ * cosY; + + // Rotate around X axis (pitch) + let rotatedY = relativeY * cosX - rotatedZ * sinX; + rotatedZ = relativeY * sinX + rotatedZ * cosX; + + // Project to screen + if (rotatedZ <= 0) return; // Behind camera + + const scale = STAR_FIELD_DEPTH / rotatedZ; + const x = width/2 + rotatedX * scale; + const y = height/2 + rotatedY * scale; + const size = star.size * scale; + + if (x >= 0 && x <= width && y >= 0 && y <= height) { + ctx.beginPath(); + ctx.arc(x, y, size, 0, Math.PI * 2); + ctx.fill(); + } + }); + + // Draw planets + gameState.planets.forEach(planet => { + const projected = projectPoint(planet.position, player); + 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.position, player); + if (projected) { + const size = 10 * 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.position, player); + 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 cockpit overlay + ctx.strokeStyle = '#ffffff'; + ctx.lineWidth = 2; + + // Center 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(); +} \ No newline at end of file |