Spaces:
Sleeping
Sleeping
| <html> | |
| <head> | |
| <style> | |
| body { margin: 0; } | |
| #game-container { | |
| width: 100%; | |
| height: 400px; | |
| background: black; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .lander { | |
| width: 32px; | |
| height: 32px; | |
| position: absolute; | |
| transform: translate(-50%, -50%); | |
| } | |
| .thrust-particle { | |
| width: 4px; | |
| height: 4px; | |
| background: red; | |
| position: absolute; | |
| border-radius: 50%; | |
| } | |
| .flag { | |
| width: 4px; | |
| height: 24px; | |
| background: yellow; | |
| position: absolute; | |
| bottom: 48px; | |
| } | |
| .hud { | |
| position: absolute; | |
| color: white; | |
| padding: 16px; | |
| font-family: sans-serif; | |
| } | |
| .controls { | |
| position: absolute; | |
| top: 16px; | |
| right: 16px; | |
| color: white; | |
| font-family: sans-serif; | |
| font-size: 14px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="game-container"> | |
| <div class="hud"> | |
| <div id="fuel">Fuel: 100%</div> | |
| <div id="velocity">Velocity: 0 m/s</div> | |
| <div id="score"></div> | |
| </div> | |
| <div class="controls"> | |
| <div>↑ - Thrust</div> | |
| <div>← → - Move</div> | |
| <div>Land between flags</div> | |
| </div> | |
| </div> | |
| <script> | |
| class LunarLander { | |
| constructor() { | |
| this.container = document.getElementById('game-container'); | |
| this.position = { x: 200, y: 50 }; | |
| this.velocity = { x: 0, y: 0 }; | |
| this.fuel = 100; | |
| this.gameState = 'playing'; | |
| this.thrust = false; | |
| this.GRAVITY = 0.05; | |
| this.THRUST = 0.15; | |
| this.LANDING_SPEED = 3; | |
| this.groundPoints = [ | |
| {x: 0, y: 380}, {x: 100, y: 360}, {x: 150, y: 370}, | |
| {x: 200, y: 350}, {x: 300, y: 350}, {x: 350, y: 370}, | |
| {x: 400, y: 360}, {x: 450, y: 380}, {x: 500, y: 370} | |
| ]; | |
| this.setupGame(); | |
| } | |
| setupGame() { | |
| this.createLander(); | |
| this.createFlags(); | |
| this.createGround(); | |
| this.setupControls(); | |
| this.gameLoop(); | |
| } | |
| createLander() { | |
| this.lander = document.createElement('div'); | |
| this.lander.className = 'lander'; | |
| this.lander.style.background = '#a855f7'; | |
| this.container.appendChild(this.lander); | |
| } | |
| createFlags() { | |
| const flag1 = document.createElement('div'); | |
| flag1.className = 'flag'; | |
| flag1.style.left = '190px'; | |
| const flag2 = document.createElement('div'); | |
| flag2.className = 'flag'; | |
| flag2.style.left = '310px'; | |
| this.container.appendChild(flag1); | |
| this.container.appendChild(flag2); | |
| } | |
| createGround() { | |
| const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | |
| svg.style.position = 'absolute'; | |
| svg.style.bottom = '0'; | |
| svg.style.width = '100%'; | |
| svg.style.height = '100%'; | |
| const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |
| const d = `M${this.groundPoints.map(p => `${p.x} ${p.y}`).join(' L')}`; | |
| path.setAttribute('d', d); | |
| path.setAttribute('stroke', 'white'); | |
| path.setAttribute('fill', 'none'); | |
| path.setAttribute('stroke-width', '2'); | |
| svg.appendChild(path); | |
| this.container.appendChild(svg); | |
| } | |
| setupControls() { | |
| document.addEventListener('keydown', (e) => { | |
| if (this.gameState !== 'playing' || this.fuel <= 0) return; | |
| switch (e.key) { | |
| case 'ArrowUp': | |
| this.thrust = true; | |
| this.velocity.y -= this.THRUST; | |
| this.fuel = Math.max(0, this.fuel - 0.5); | |
| this.updateThrust(); | |
| break; | |
| case 'ArrowLeft': | |
| this.velocity.x -= 0.1; | |
| this.fuel = Math.max(0, this.fuel - 0.2); | |
| break; | |
| case 'ArrowRight': | |
| this.velocity.x += 0.1; | |
| this.fuel = Math.max(0, this.fuel - 0.2); | |
| break; | |
| } | |
| }); | |
| document.addEventListener('keyup', (e) => { | |
| if (e.key === 'ArrowUp') { | |
| this.thrust = false; | |
| this.updateThrust(); | |
| } | |
| }); | |
| } | |
| updateThrust() { | |
| const particles = this.lander.querySelectorAll('.thrust-particle'); | |
| particles.forEach(p => p.remove()); | |
| if (this.thrust) { | |
| for (let i = 0; i < 4; i++) { | |
| const particle = document.createElement('div'); | |
| particle.className = 'thrust-particle'; | |
| particle.style.left = `${Math.random() * 8 - 4}px`; | |
| particle.style.top = `${Math.random() * 8}px`; | |
| this.lander.appendChild(particle); | |
| } | |
| } | |
| } | |
| checkCollision() { | |
| for (let i = 0; i < this.groundPoints.length - 1; i++) { | |
| const p1 = this.groundPoints[i]; | |
| const p2 = this.groundPoints[i + 1]; | |
| if (this.position.x >= p1.x && this.position.x <= p2.x) { | |
| const groundY = p1.y + ((p2.y - p1.y) * (this.position.x - p1.x)) / (p2.x - p1.x); | |
| if (this.position.y >= groundY - 10) { | |
| if (this.velocity.y < this.LANDING_SPEED * 1.5 && | |
| Math.abs(this.velocity.x) < 2 && | |
| this.position.x >= 190 && | |
| this.position.x <= 310) { | |
| this.gameState = 'won'; | |
| document.getElementById('score').textContent = `Score: ${Math.floor(this.fuel * 100)}`; | |
| } else { | |
| this.gameState = 'crashed'; | |
| } | |
| return true; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| updateHUD() { | |
| document.getElementById('fuel').textContent = `Fuel: ${Math.floor(this.fuel)}%`; | |
| document.getElementById('velocity').textContent = `Velocity: ${Math.floor(this.velocity.y * 10)} m/s`; | |
| } | |
| gameLoop = () => { | |
| if (this.gameState === 'playing') { | |
| this.position.x += this.velocity.x; | |
| this.position.y += this.velocity.y; | |
| this.velocity.x *= 0.99; | |
| this.velocity.y += this.GRAVITY; | |
| this.lander.style.left = `${this.position.x}px`; | |
| this.lander.style.top = `${this.position.y}px`; | |
| this.updateHUD(); | |
| this.checkCollision(); | |
| } | |
| requestAnimationFrame(this.gameLoop); | |
| } | |
| } | |
| new LunarLander(); | |
| </script> | |
| </body> | |
| </html> |