JIT
create a fun alien 8-bit fighter game with customization and music
make it this: Index.html: Alien 8-Bit Fighter body { margin: 0; padding: 0; background: #000; overflow: hidden; font-family: 'Courier New', monospace; } canvas { display: block; margin: 0 auto; background: #111; } .player-info { position: absolute; color: #0f0; padding: 10px; font-size: 16px; } #player1 { top: 10px; left: 10px; } #player2 { top: 10px; right: 10px; } #round-info { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #fff; font-size: 24px; text-align: center; pointer-events: none; } .health-bar { height: 10px; margin-top: 5px; background: #333; } .health-fill { height: 100%; background: #0f0; } #player2 .health-fill { background: #f0f; } .powerup-timer { margin-top: 5px; height: 3px; background: #333; } .powerup-fill { height: 100%; } Player 1 Boost: 100% Player 2 Boost: 100% game.js: const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Game state const state = { players: [ { x: 200, y: 300, width: 40, height: 30, color: '#0f0', speedX: 0, speedY: 0, maxSpeed: 5, health: 100, boost: 100, facing: 1, lastShot: 0, score: 0, powerup: null, powerupEndTime: 0, originalColor: '#0f0' }, { x: 600, y: 300, width: 40, height: 30, color: '#f0f', speedX: 0, speedY: 0, maxSpeed: 5, health: 100, boost: 100, facing: -1, lastShot: 0, score: 0, powerup: null, powerupEndTime: 0, originalColor: '#f0f' } ], projectiles: [], powerups: [], round: 1, roundActive: true, roundTimer: 0, roundEndTime: 0, gameStarted: false, lastPowerupSpawn: 0, powerupSpawnInterval: 10000 }; // Enhanced powerup types const POWERUPS = { HEALTH: { name: 'HEALTH+', color: '#0f0', duration: 0, effect: (player) => { player.health = Math.min(player.health + 30, 100); } }, BOOST: { name: 'BOOST+', color: '#0af', duration: 10000, effect: (player) => { player.maxSpeed = 7; player.boost = 100; }, cleanup: (player) => { player.maxSpeed = 5; } }, RAPID_FIRE: { name: 'RAPID FIRE', color: '#f80', duration: 8000, effect: (player) => { player.rapidFire = true; }, cleanup: (player) => { player.rapidFire = false; } }, SHIELD: { name: 'SHIELD', color: '#0ff', duration: 6000, effect: (player) => { player.shield = true; }, cleanup: (player) => { player.shield = false; } }, INVISIBILITY: { name: 'INVISIBLE', color: '#888', duration: 5000, effect: (player) => { player.invisible = true; player.color = '#111'; }, cleanup: (player) => { player.invisible = false; player.color = player.originalColor; } }, TIME_SLOW: { name: 'TIME WARP', color: '#f0f', duration: 4000, effect: (player) => { player.timeSlow = true; state.powerupSpawnInterval = 15000; }, cleanup: (player) => { player.timeSlow = false; state.powerupSpawnInterval = 10000; } }, MULTI_SHOT: { name: 'MULTI SHOT', color: '#8f0', duration: 7000, effect: (player) => { player.multiShot = true; }, cleanup: (player) => { player.multiShot = false; } }, BOOST_OVERDRIVE: { name: 'OVERDRIVE', color: '#f00', duration: 5000, effect: (player) => { player.maxSpeed = 9; player.boost = 200; player.boostOverdrive = true; }, cleanup: (player) => { player.maxSpeed = 5; player.boostOverdrive = false; } }, BLACK_HOLE: { name: 'BLACK HOLE', color: '#000', duration: 0, effect: (player, index) => { const otherPlayer = state.players[index === 0 ? 1 : 0]; otherPlayer.x = player.x + (index === 0 ? 100 : -100); otherPlayer.y = player.y; } }, CONFUSION: { name: 'CONFUSION', color: '#a0a', duration: 6000, effect: (player, index) => { state.players[index === 0 ? 1 : 0].confused = true; }, cleanup: (player, index) => { state.players[index === 0 ? 1 : 0].confused = false; } } }; // Input handling const keys = { w: false, a: false, s: false, d: false, f: false, ArrowUp: false, ArrowLeft: false, ArrowDown: false, ArrowRight: false, Enter: false }; document.addEventListener('keydown', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = true; if (!state.gameStarted) { state.gameStarted = true; startRound(); } } }); document.addEventListener('keyup', (e) => { if (keys.hasOwnProperty(e.key)) { keys[e.key] = false; } }); // Game loop function gameLoop() { update(); render(); requestAnimationFrame(gameLoop); } // Update game state function update() { if (!state.roundActive) { if (state.roundEndTime > 0 && Date.now() - state.roundEndTime > 2000) { resetRound(); } return; } // Spawn powerups randomly if (Date.now() - state.lastPowerupSpawn > state.powerupSpawnInterval && Math.random() < 0.03) { spawnPowerup(); state.lastPowerupSpawn = Date.now(); } // Player 1 controls (WASD + F to shoot) if (keys.w && state.players[0].boost > 0) { state.players[0].speedY = -state.players[0].maxSpeed; state.players[0].boost -= state.players[0].boostOverdrive ? 0.8 : 0.5; } if (keys.s) state.players[0].speedY = state.players[0].maxSpeed/2; if (keys.a) { state.players[0].speedX = -state.players[0].maxSpeed; state.players[0].facing = -1; } if (keys.d) { state.players[0].speedX = state.players[0].maxSpeed; state.players[0].facing = 1; } if (keys.f) { const cooldown = state.players[0].rapidFire ? 200 : 500; if (Date.now() - state.players[0].lastShot > cooldown) { shoot(0); if (state.players[0].multiShot) { setTimeout(() => shoot(0), 100); setTimeout(() => shoot(0), 200); } state.players[0].lastShot = Date.now(); } } // Player 2 controls (Arrow keys + Enter to shoot) const upKey = state.players[1].confused ? 'ArrowDown' : 'ArrowUp'; const downKey = state.players[1].confused ? 'ArrowUp' : 'ArrowDown'; const leftKey = state.players[1].confused ? 'ArrowRight' : 'ArrowLeft'; const rightKey = state.players[1].confused ? 'ArrowLeft' : 'ArrowRight'; if (keys[upKey] && state.players[1].boost > 0) { state.players[1].speedY = -state.players[1].maxSpeed; state.players[1].boost -= state.players[1].boostOverdrive ? 0.8 : 0.5; } if (keys[downKey]) state.players[1].speedY = state.players[1].maxSpeed/2; if (keys[leftKey]) { state.players[1].speedX = -state.players[1].maxSpeed; state.players[1].facing = -1; } if (keys[rightKey]) { state.players[1].speedX = state.players[1].maxSpeed; state.players[1].facing = 1; } if (keys.Enter) { const cooldown = state.players[1].rapidFire ? 200 : 500; if (Date.now() - state.players[1].lastShot > cooldown) { shoot(1); if (state.players[1].multiShot) { setTimeout(() => shoot(1), 100); setTimeout(() => shoot(1), 200); } state.players[1].lastShot = Date.now(); } } // Update player positions and powerups state.players.forEach((player, index) => { player.x += player.speedX; player.y += player.speedY; // Apply friction player.speedX *= 0.9; player.speedY *= 0.9; // Recharge boost when not in use if (!(keys.w && index === 0) && !(keys[upKey] && index === 1)) { player.boost = Math.min(player.boost + (player.boostOverdrive ? 0.3 : 0.2), player.boostOverdrive ? 200 : 100); } // Check powerup expiration if (player.powerup && Date.now() > player.powerupEndTime) { if (player.powerup.cleanup) player.powerup.cleanup(player, index); player.powerup = null; document.getElementById(`p${index+1}-powerup`).style.display = 'none'; } // Update powerup timer display if (player.powerup) { const remaining = player.powerupEndTime - Date.now(); const percent = Math.max(0, (remaining / player.powerup.duration) * 100); document.getElementById(`p${index+1}-powerup-timer`).style.width = `${percent}%`; document.getElementById(`p${index+1}-powerup-timer`).style.background = player.powerup.color; } // Boundary checks player.x = Math.max(0, Math.min(canvas.width - player.width, player.x)); player.y = Math.max(0, Math.min(canvas.height - player.height, player.y)); }); // Update projectiles for (let i = state.projectiles.length - 1; i >= 0; i--) { const proj = state.projectiles[i]; proj.x += proj.speedX; proj.y += proj.speedY; // Check if projectile is out of bounds if (proj.x < 0 || proj.x > canvas.width || proj.y < 0 || proj.y > canvas.height) { state.projectiles.splice(i, 1); continue; } // Check for collisions with players for (let j = 0; j < state.players.length; j++) { if (proj.owner !== j && checkCollision(proj, state.players[j]) && !state.players[j].invisible) { if (!state.players[j].shield) { state.players[j].health -= 10; updateHealthBars(); } state.projectiles.splice(i, 1); // Check if player is defeated if (state.players[j].health <= 0) { const winner = j === 0 ? 1 : 0; state.players[winner].score++; endRound(winner); } break; } } } // Check powerup collisions for (let i = state.powerups.length - 1; i >= 0; i--) { const powerup = state.powerups[i]; for (let j = 0; j < state.players.length; j++) { if (checkCollision(powerup, state.players[j])) { applyPowerup(j, powerup.type); state.powerups.splice(i, 1); break; } } } } function spawnPowerup() { const types = Object.keys(POWERUPS); const weights = [10, 8, 7, 6, 5, 4, 3, 2, 1, 1]; // Weighted probabilities let totalWeight = weights.reduce((a, b) => a + b, 0); let random = Math.random() * totalWeight; let weightSum = 0; let typeIndex = 0; for (let i = 0; i < weights.length; i++) { weightSum += weights[i]; if (random <= weightSum) { typeIndex = i; break; } } const type = types[typeIndex]; state.powerups.push({ x: Math.random() * (canvas.width - 30), y: Math.random() * (canvas.height - 30), width: 30, height: 30, type: type, color: POWERUPS[type].color, flashTimer: 0 }); } function applyPowerup(playerIndex, type) { const player = state.players[playerIndex]; const powerup = POWERUPS[type]; // Clean up previous powerup if any if (player.powerup && player.powerup.cleanup) { player.powerup.cleanup(player, playerIndex); } // Apply new powerup powerup.effect(player, playerIndex); player.powerup = powerup; player.powerupEndTime = Date.now() + powerup.duration; // Update UI const powerupEl = document.getElementById(p${playerIndex+1}-powerup); powerupEl.style.display = 'block'; document.getElementById(p${playerIndex+1}-powerup-name).textContent = powerup.name; document.getElementById(p${playerIndex+1}-powerup-name).style.color = powerup.color; } function shoot(playerIndex) { const player = state.players[playerIndex]; const angleVariation = player.multiShot ? [0, -0.2, 0.2] : [0]; angleVariation.forEach(angle => { state.projectiles.push({ x: player.x + (player.facing > 0 ? player.width : -10), y: player.y + player.height/2 - 5, width: 10, height: 5, speedX: 10 * player.facing * (player.timeSlow ? 0.7 : 1), speedY: angle * 10, color: player.color, owner: playerIndex }); }); } function checkCollision(obj1, obj2) { return obj1.x < obj2.x + obj2.width && obj1.x + obj1.width > obj2.x && obj1.y < obj2.y + obj2.height && obj1.y + obj1.height > obj2.y; } function updateHealthBars() { document.getElementById('p1-health').style.width = ${state.players[0].health}%; document.getElementById('p2-health').style.width = ${state.players[1].health}%; document.getElementById('p1-boost').textContent = ${Math.floor(state.players[0].boost)}%; document.getElementById('p2-boost').textContent = ${Math.floor(state.players[1].boost)}%; } function startRound() { state.roundActive = true; document.getElementById('round-info').textContent = Round ${state.round}\nFIGHT!; setTimeout(() => { document.getElementById('round-info').textContent = ''; }, 1000); } function endRound(winner) { state.roundActive = false; state.roundEndTime = Date.now(); document.getElementById('round-info').textContent = Player ${winner + 1} wins!\nRound ${state.round}; } function resetRound() { state.round++; state.players[0].x = 200; state.players[0].y = 300; state.players[1].x = 600; state.players[1].y = 300; state.players[0].health = 100; state.players[1].health = 100; state.players[0].boost = 100; state.players[1].boost = 100; state.projectiles = []; state.powerups = []; // Clear powerups state.players.forEach((player, index) => { if (player.powerup && player.powerup.cleanup) { player.powerup.cleanup(player, index); } player.powerup = null; player.color = player.originalColor; document.getElementById(p${index+1}-powerup).style.display = 'none'; }); updateHealthBars(); startRound(); } // Render everything function render() { // Clear canvas ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw players state.players.forEach((player, index) => { if (player.invisible) return; // Draw shield if active if (player.shield) { ctx.beginPath(); ctx.arc( player.x + player.width/2, player.y + player.height/2, player.width + 10, 0, Math.PI * 2 ); ctx.strokeStyle = '#0ff'; ctx.lineWidth = 2; ctx.stroke(); } ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Draw alien eyes ctx.fillStyle = '#000'; ctx.fillRect(player.x + 10, player.y + 10, 5, 5); ctx.fillRect(player.x + 25, player.y + 10, 5, 5); // Draw boosters when active const upKey = index === 0 ? 'w' : (state.players[1].confused ? 'ArrowDown' : 'ArrowUp'); if (keys[upKey]) { ctx.fillStyle = player.boostOverdrive ? '#f00' : '#ff0'; ctx.fillRect(player.x + 5, player.y + player.height, 10, 10); ctx.fillRect(player.x + 25, player.y + player.height, 10, 10); } }); // Draw projectiles state.projectiles.forEach(proj => { ctx.fillStyle = proj.color; ctx.fillRect(proj.x, proj.y, proj.width, proj.height); }); // Draw powerups with flashing effect const now = Date.now(); state.powerups.forEach(powerup => { const flashPhase = Math.sin(now * 0.005) > 0; ctx.fillStyle = flashPhase ? powerup.color : '#fff'; ctx.fillRect(powerup.x, powerup.y, powerup.width, powerup.height); ctx.fillStyle = '#000'; ctx.font = '10px Courier New'; ctx.textAlign = 'center'; ctx.fillText(POWERUPS[powerup.type].name, powerup.x + powerup.width/2, powerup.y + powerup.height/2 + 3); }); // Draw score ctx.fillStyle = '#fff'; ctx.font = '20px Courier New'; ctx.textAlign = 'center'; ctx.fillText(${state.players[0].score} - ${state.players[1].score}, canvas.width/2, 30); } // Initialize game updateHealthBars(); gameLoop(); ( Just add all of this code with the menu , customization ,and settings , and music )

I'll help you set up the complete Alien 8-Bit Fighter game with all the requested features. Here's the complete project structure:

Updated files
v1
for customization , make a gui that pops up a representation of the alien player 1 and 2. Make it so theirs multiple color suggestions and the eyes of the alien as well. Can you also add some antennas that have physics.

I'll enhance the customization menu with visual alien representations, color options, and physics-based antennas. Here's the updated version:

The customization menu now features:

  1. Visual representations of both alien players with animated antennas
  2. Physics-based antenna movement that reacts to mouse interactions
  3. Expanded color palettes for both body and eyes
  4. Real-time preview of color changes
  5. Antennas that bounce and wiggle with physics
  6. Separate eye color customization
  7. Visual feedback when selecting colors

The antennas use spring physics to create natural movement, and they react when colors are changed or when the mouse moves near them. The previews give players a clear idea of how their customizations will look in-game.

Updated files
v2