Meteor Interceptor - Realistic Flight
by FrostCoder37478 lines15.5 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Meteor Interceptor - Realistic Flight</title>
<style>
* {
box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #050510;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #fff;
}
canvas {
display: block;
background: radial-gradient(circle at center, #101525 0%, #020205 100%);
width: 100vw;
height: 100vh;
}
#ui {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
display: flex;
justify-content: space-between;
pointer-events: none;
font-size: 16px;
font-weight: bold;
text-shadow: 0 2px 4px rgba(0,0,0,0.8);
z-index: 10;
}
.hud-panel {
background: rgba(0, 20, 40, 0.6);
border: 1px solid rgba(0, 150, 255, 0.4);
padding: 8px 14px;
border-radius: 4px;
backdrop-filter: blur(4px);
}
#controls-hint {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
pointer-events: none;
color: rgba(255, 255, 255, 0.5);
font-size: 13px;
text-shadow: 0 1px 2px rgba(0,0,0,0.9);
}
#start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(2, 2, 8, 0.85);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 20;
padding: 20px;
text-align: center;
}
h1 {
margin: 0 0 10px 0;
font-size: 28px;
letter-spacing: 2px;
color: #00bfff;
text-shadow: 0 0 10px rgba(0,191,255,0.5);
}
p {
color: #aaa;
max-width: 400px;
font-size: 14px;
line-height: 1.5;
margin-bottom: 25px;
}
.btn {
background: linear-gradient(135deg, #0077ff, #0044aa);
color: white;
border: none;
padding: 12px 30px;
font-size: 16px;
font-weight: bold;
border-radius: 6px;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 119, 255, 0.4);
transition: all 0.2s;
}
.btn:active {
transform: scale(0.95);
}
</style>
</head>
<body>
<div id="ui">
<div class="hud-panel" id="score-hud">SCORE: 0</div>
<div class="hud-panel" id="health-hud">INTEGRITY: 100%</div>
</div>
<div id="start-screen">
<h1>METEOR DEFENSE</h1>
<p>Pilot a high-altitude interceptor jet. Drag your finger across the screen to steer, tap the right side or use automatic fire to obliterate incoming meteors before they impact the atmosphere!</p>
<button class="btn" onclick="startGame()">ENGAGE</button>
</div>
<div id="controls-hint">Drag to Fly | Auto-Cannons Active</div>
<canvas id="gameCanvas"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let width, height;
function resize() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Audio Context for Sound Synthesis
let audioCtx = null;
function initAudio() {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
}
function playSound(type) {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
const now = audioCtx.currentTime;
if (type === 'laser') {
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(800, now);
osc.frequency.exponentialRampToValueAtTime(100, now + 0.15);
gain.gain.setValueAtTime(0.15, now);
gain.gain.linearRampToValueAtTime(0.01, now + 0.15);
osc.start(now);
osc.stop(now + 0.15);
} else if (type === 'explosion') {
osc.type = 'triangle';
osc.frequency.setValueAtTime(120, now);
osc.frequency.exponentialRampToValueAtTime(20, now + 0.4);
gain.gain.setValueAtTime(0.3, now);
gain.gain.linearRampToValueAtTime(0.01, now + 0.4);
osc.start(now);
osc.stop(now + 0.4);
}
}
// Game State
let gameState = 'START';
let score = 0;
let health = 100;
let gameTime = 0;
const player = {
x: width / 2,
y: height - 120,
targetX: width / 2,
targetY: height - 120,
width: 45,
height: 60,
speed: 0.15
};
let bullets = [];
let meteors = [];
let particles = [];
let stars = [];
// Generate static starfield
for (let i = 0; i < 80; i++) {
stars.push({
x: Math.random() * width,
y: Math.random() * height,
size: Math.random() * 1.5,
alpha: Math.random()
});
}
// Touch and Mouse Controls
let isDragging = false;
window.addEventListener('pointerdown', (e) => {
if (gameState === 'PLAYING') {
isDragging = true;
updateTarget(e);
}
});
window.addEventListener('pointermove', (e) => {
if (isDragging && gameState === 'PLAYING') {
updateTarget(e);
}
});
window.addEventListener('pointerup', () => { isDragging = false; });
function updateTarget(e) {
player.targetX = e.clientX;
player.targetY = e.clientY;
// Clamp within bounds
player.targetX = Math.max(30, Math.min(width - 30, player.targetX));
player.targetY = Math.max(50, Math.min(height - 50, player.targetY));
}
function startGame() {
initAudio();
document.getElementById('start-screen').style.display = 'none';
score = 0;
health = 100;
bullets = [];
meteors = [];
particles = [];
gameTime = 0;
gameState = 'PLAYING';
}
let shootTimer = 0;
function update() {
if (gameState !== 'PLAYING') return;
gameTime++;
// Smooth flight interpolation (Realistic inertia)
player.x += (player.targetX - player.x) * player.speed;
player.y += (player.targetY - player.y) * player.speed;
// Auto-fire cannons
shootTimer++;
if (shootTimer % 10 === 0) {
bullets.push({ x: player.x - 12, y: player.y - 20, vy: -18 });
bullets.push({ x: player.x + 12, y: player.y - 20, vy: -18 });
playSound('laser');
}
// Spawn Meteors dynamically based on score
if (Math.random() < 0.02 + (score * 0.0005)) {
meteors.push({
x: Math.random() * width,
y: -50,
size: Math.random() * 25 + 15,
vx: (Math.random() - 0.5) * 3,
vy: Math.random() * 2 + 2 + (score * 0.02),
rotation: Math.random() * Math.PI,
vRot: (Math.random() - 0.5) * 0.05,
hp: Math.floor(Math.random() * 2) + 1
});
}
// Update Bullets
for (let i = bullets.length - 1; i >= 0; i--) {
bullets[i].y += bullets[i].vy;
if (bullets[i].y < 0) bullets.splice(i, 1);
}
// Update Meteors
for (let i = meteors.length - 1; i >= 0; i--) {
let m = meteors[i];
m.x += m.vx;
m.y += m.vy;
m.rotation += m.vRot;
// Check collision with player
let distToPlayer = Math.hypot(m.x - player.x, m.y - player.y);
if (distToPlayer < m.size + 20) {
health -= 25;
createExplosion(m.x, m.y, 20, '#ff4500');
playSound('explosion');
meteors.splice(i, 1);
if (health <= 0) gameOver();
continue;
}
// Check out of bounds (ground impact)
if (m.y > height + 50) {
health -= 10;
playSound('explosion');
meteors.splice(i, 1);
if (health <= 0) gameOver();
continue;
}
// Check bullet collisions
for (let j = bullets.length - 1; j >= 0; j--) {
let b = bullets[j];
let dist = Math.hypot(m.x - b.x, m.y - b.y);
if (dist < m.size) {
m.hp--;
bullets.splice(j, 1);
createExplosion(b.x, b.y, 5, '#00bfff');
if (m.hp <= 0) {
createExplosion(m.x, m.y, 15, '#ff8800');
playSound('explosion');
score += 10;
meteors.splice(i, 1);
}
break;
}
}
}
// Update Particles
for (let i = particles.length - 1; i >= 0; i--) {
let p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.alpha -= 0.02;
if (p.alpha <= 0) particles.splice(i, 1);
}
// Update HUD
document.getElementById('score-hud').innerText = `SCORE: ${score}`;
document.getElementById('health-hud').innerText = `INTEGRITY: ${Math.max(0, health)}%`;
}
function createExplosion(x, y, count, color) {
for (let i = 0; i < count; i++) {
particles.push({
x: x,
y: y,
vx: (Math.random() - 0.5) * 6,
vy: (Math.random() - 0.5) * 6,
size: Math.random() * 3 + 1,
color: color,
alpha: 1
});
}
}
function gameOver() {
gameState = 'GAMEOVER';
let screen = document.getElementById('start-screen');
screen.style.display = 'flex';
screen.querySelector('h1').innerText = 'MISSION FAILED';
screen.querySelector('p').innerText = `Your aircraft was overwhelmed. Final Score: ${score}`;
screen.querySelector('.btn').innerText = 'PLAY AGAIN';
}
function draw() {
ctx.clearRect(0, 0, width, height);
// Draw Stars
ctx.fillStyle = '#ffffff';
stars.forEach(s => {
ctx.globalAlpha = s.alpha;
ctx.fillRect(s.x, s.y, s.size, s.size);
});
ctx.globalAlpha = 1;
// Draw Particles
particles.forEach(p => {
ctx.save();
ctx.globalAlpha = p.alpha;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
});
// Draw Bullets
ctx.fillStyle = '#00ffff';
ctx.shadowBlur = 10;
ctx.shadowColor = '#00ffff';
bullets.forEach(b => {
ctx.fillRect(b.x - 1.5, b.y, 3, 12);
});
ctx.shadowBlur = 0;
// Draw Realistic Jet Fighter
if (gameState === 'PLAYING') {
ctx.save();
ctx.translate(player.x, player.y);
// Slight bank angle based on movement direction
let bankAngle = (player.targetX - player.x) * 0.003;
ctx.rotate(bankAngle);
// Jet Body
ctx.fillStyle = '#1c2331';
ctx.strokeStyle = '#00bfff';
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(0, -30); // Nose
ctx.lineTo(18, 20); // Right Wing tip
ctx.lineTo(6, 15);
ctx.lineTo(4, 30); // Engine exhaust area
ctx.lineTo(-4, 30);
ctx.lineTo(-6, 15);
ctx.lineTo(-18, 20); // Left Wing tip
ctx.closePath();
ctx.fill();
ctx.stroke();
// Cockpit Glass
ctx.fillStyle = '#00e5ff';
ctx.beginPath();
ctx.moveTo(0, -15);
ctx.lineTo(5, 5);
ctx.lineTo(-5, 5);
ctx.closePath();
ctx.fill();
// Engine Afterburner Glow
ctx.fillStyle = '#ff4500';
ctx.fillRect(-3, 30, 6, Math.random() * 10 + 5);
ctx.restore();
}
// Draw Meteors
meteors.forEach(m => {
ctx.save();
ctx.translate(m.x, m.y);
ctx.rotate(m.rotation);
// Fiery atmospheric trail effect
let gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, m.size);
gradient.addColorStop(0, '#ff4500');
gradient.addColorStop(0.7, '#8b0000');
gradient.addColorStop(1, 'transparent');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(0, 0, m.size * 1.3, 0, Math.PI * 2);
ctx.fill();
// Rocky core
ctx.fillStyle = '#3a3a3a';
ctx.strokeStyle = '#ff6347';
ctx.lineWidth = 2;
ctx.beginPath();
// Irregular polygon for realistic rock shape
let points = 6;
for (let i = 0; i < points; i++) {
let angle = (i / points) * Math.PI * 2;
let r = m.size * (0.8 + Math.sin(i * 3) * 0.2);
let px = Math.cos(angle) * r;
let py = Math.sin(angle) * r;
if (i === 0) ctx.moveTo(px, py);
else ctx.lineTo(px, py);
}
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
});
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>Game Source: Meteor Interceptor - Realistic Flight
Creator: FrostCoder37
Libraries: none
Complexity: complex (478 lines, 15.5 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: meteor-interceptor-realistic-flight-frostcoder37" to link back to the original. Then publish at arcadelab.ai/publish.