anycoder-5fe36db7 / index.html
defaultdolphin's picture
Upload folder using huggingface_hub
1208f75 verified
Raw
History Blame Contribute Delete
24.6 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Subspace Continuum: Zone Warfare</title>
<style>
:root {
--primary: #00ffcc;
--danger: #ff3366;
--bg: #0a0a12;
--ui-bg: rgba(10, 10, 18, 0.85);
--font-main: 'Courier New', Courier, monospace;
}
* {
box-sizing: border-box;
user-select: none;
}
body {
margin: 0;
overflow: hidden;
background-color: var(--bg);
font-family: var(--font-main);
color: white;
height: 100vh;
width: 100vw;
}
/* Game Container */
#game-container {
position: relative;
width: 100%;
height: 100%;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
/* UI Overlays */
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(5px);
z-index: 10;
transition: opacity 0.3s;
}
.hidden {
opacity: 0;
pointer-events: none;
z-index: -1;
}
/* Main Menu */
h1 {
font-size: 3rem;
text-transform: uppercase;
letter-spacing: 5px;
text-shadow: 0 0 20px var(--primary);
margin-bottom: 10px;
text-align: center;
}
.zone-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin-top: 30px;
}
.zone-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 20px;
width: 200px;
text-align: center;
cursor: pointer;
transition: all 0.2s;
border-radius: 8px;
}
.zone-card:hover {
transform: translateY(-5px);
background: rgba(255, 255, 255, 0.1);
border-color: var(--primary);
box-shadow: 0 0 15px rgba(0, 255, 204, 0.3);
}
.zone-title {
font-weight: bold;
font-size: 1.2rem;
margin-bottom: 5px;
display: block;
}
.zone-desc {
font-size: 0.8rem;
color: #aaa;
}
/* HUD */
#hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 5;
}
.hud-panel {
background: var(--ui-bg);
padding: 10px 20px;
border-radius: 4px;
border-left: 3px solid var(--primary);
font-size: 1.2rem;
text-shadow: 1px 1px 0 #000;
}
.hud-right {
text-align: right;
border-left: none;
border-right: 3px solid var(--primary);
}
#zone-indicator {
position: absolute;
top: 80px;
left: 20px;
font-size: 0.9rem;
color: #888;
text-transform: uppercase;
letter-spacing: 2px;
}
/* Chat Simulation */
#chat-box {
position: absolute;
bottom: 20px;
left: 20px;
width: 300px;
height: 150px;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-end;
pointer-events: none;
mask-image: linear-gradient(to bottom, transparent, black 20%);
}
.chat-msg {
background: rgba(0,0,0,0.5);
padding: 4px 8px;
margin-bottom: 2px;
font-size: 0.8rem;
border-radius: 2px;
}
.chat-name { color: var(--primary); font-weight: bold; }
.chat-text { color: #eee; }
/* Controller Hint */
#controller-hint {
position: absolute;
bottom: 20px;
right: 20px;
font-size: 0.8rem;
color: #666;
display: flex;
align-items: center;
gap: 10px;
}
.icon {
width: 20px;
height: 20px;
background: #333;
border-radius: 50%;
display: inline-block;
}
/* Branding */
.branding {
position: absolute;
top: 10px;
right: 10px;
z-index: 100;
}
.branding a {
color: rgba(255,255,255,0.5);
text-decoration: none;
font-size: 0.8rem;
transition: color 0.2s;
}
.branding a:hover { color: white; }
/* Responsive */
@media (max-width: 768px) {
.zone-grid { grid-template-columns: 1fr; }
h1 { font-size: 2rem; }
#hud { flex-direction: column; gap: 10px; }
.hud-right { border-right: none; border-bottom: 3px solid var(--primary); }
}
</style>
<!-- Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<div id="game-container">
<canvas id="gameCanvas"></canvas>
<!-- Branding -->
<div class="branding">
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a>
</div>
<!-- Main Menu -->
<div id="menu-overlay" class="overlay">
<h1>Subspace Continuum</h1>
<p>Choose Your Zone</p>
<div class="zone-grid">
<div class="zone-card" onclick="startGame('green')">
<span class="zone-title" style="color:#4caf50">Green Zone</span>
<span class="zone-desc">Standard Physics<br>Low Threat</span>
</div>
<div class="zone-card" onclick="startGame('ice')">
<span class="zone-title" style="color:#00bcd4">Ice Fields</span>
<span class="zone-desc">Low Friction<br>Slippery Combat</span>
</div>
<div class="zone-card" onclick="startGame('war')">
<span class="zone-title" style="color:#f44336">War Zone</span>
<span class="zone-desc">High Friction<br>Aggressive AI</span>
</div>
<div class="zone-card" onclick="startGame('chaos')">
<span class="zone-title" style="color:#9c27b0">Chaos Sector</span>
<span class="zone-desc">Zero Gravity<br>Erratic Enemies</span>
</div>
</div>
<p style="margin-top: 30px; font-size: 0.8rem; color: #888;">
Controls: WASD/Arrows to Move &bull; Space to Shoot<br>
Controller: Left Stick to Move &bull; A/Cross to Shoot
</p>
</div>
<!-- HUD -->
<div id="hud" class="hidden">
<div class="hud-panel">
<div>SCORE: <span id="score-display">0</span></div>
<div style="font-size: 0.8em; color: #aaa;">KILLS: <span id="kills-display">0</span></div>
</div>
<div id="zone-indicator">Current Zone: <span id="zone-name-display">GREEN</span></div>
<div class="hud-panel hud-right">
<div style="color: var(--danger)">HP: <span id="hp-display">100</span>%</div>
<div>ENERGY: <span id="energy-display">100</span>%</div>
</div>
</div>
<!-- Chat Simulation -->
<div id="chat-box" class="hidden"></div>
<!-- Controller Status -->
<div id="controller-hint">
<i class="fas fa-gamepad"></i> <span id="controller-status">No Controller Detected</span>
</div>
</div>
<script>
/**
* SUBSPACE CONTINUUM CLONE
* Single File Implementation
*/
// --- Configuration & Constants ---
const CANVAS = document.getElementById('gameCanvas');
const CTX = CANVAS.getContext('2d');
const UI = {
menu: document.getElementById('menu-overlay'),
hud: document.getElementById('hud'),
chat: document.getElementById('chat-box'),
score: document.getElementById('score-display'),
kills: document.getElementById('kills-display'),
hp: document.getElementById('hp-display'),
energy: document.getElementById('energy-display'),
zoneName: document.getElementById('zone-name-display'),
ctrlStatus: document.getElementById('controller-status')
};
const ZONES = {
green: { name: 'GREEN', color: '#1a2f1a', grid: '#2d4a2d', friction: 0.92, botCount: 5, botAggro: 0.01 },
ice: { name: 'ICE', color: '#0f1f2f', grid: '#1a3a5a', friction: 0.98, botCount: 8, botAggro: 0.02 },
war: { name: 'WAR', color: '#2f0f0f', grid: '#5a1a1a', friction: 0.85, botCount: 15, botAggro: 0.05 },
chaos: { name: 'CHAOS', color: '#1f0f2f', grid: '#3a1a5a', friction: 0.995, botCount: 10, botAggro: 0.03 }
};
let GAME_STATE = 'MENU'; // MENU, PLAYING, GAMEOVER
let CURRENT_ZONE = 'green';
let LAST_TIME = 0;
let GAMEPAD_INDEX = null;
// --- Game Entities ---
class Entity {
constructor(x, y, radius, color) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.vx = 0;
this.vy = 0;
this.angle = 0;
this.dead = false;
}
update(dt) {
// Apply velocity
this.x += this.vx;
this.y += this.vy;
// Screen Wrap (Subspace style)
if (this.x < -this.radius) this.x = CANVAS.width + this.radius;
if (this.x > CANVAS.width + this.radius) this.x = -this.radius;
if (this.y < -this.radius) this.y = CANVAS.height + this.radius;
if (this.y > CANVAS.height + this.radius) this.y = -this.radius;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
}
class Ship extends Entity {
constructor(x, y, isPlayer = false, name = "Bot") {
super(x, y, 12, isPlayer ? '#00ffcc' : '#ff4444');
this.isPlayer = isPlayer;
this.name = name;
this.hp = 100;
this.maxHp = 100;
this.energy = 100;
this.score = 0;
this.kills = 0;
this.reloadTime = 0;
this.thrusting = false;
// Physics overrides per zone handled in main loop
}
thrust(force) {
this.thrusting = true;
this.vx += Math.cos(this.angle) * force;
this.vy += Math.sin(this.angle) * force;
}
shoot() {
if (this.reloadTime <= 0 && this.energy >= 5) {
this.energy -= 5;
this.reloadTime = 15; // Frames
// Spawn bullet
const bVx = Math.cos(this.angle) * 12 + this.vx * 0.5;
const bVy = Math.sin(this.angle) * 12 + this.vy * 0.5;
const bullet = new Bullet(this.x, this.y, this.angle, bVx, bVy, this.isPlayer);
bullets.push(bullet);
return true;
}
return false;
}
update(dt) {
super.update(dt);
// Friction
const zoneData = ZONES[CURRENT_ZONE];
this.vx *= zoneData.friction;
this.vy *= zoneData.friction;
// Cap speed
const speed = Math.sqrt(this.vx*this.vx + this.vy*this.vy);
const maxSpeed = 8;
if (speed > maxSpeed) {
const ratio = maxSpeed / speed;
this.vx *= ratio;
this.vy *= ratio;
}
if (this.reloadTime > 0) this.reloadTime--;
if (this.energy < 100) this.energy += 0.2;
// Death check
if (this.hp <= 0) {
this.dead = true;
createExplosion(this.x, this.y, this.color);
if (!this.isPlayer) {
// Player killed bot
player.kills++;
player.score += 100;
spawnPrize(this.x, this.y);
addChatMessage("System", `${this.name} was destroyed.`);
} else {
// Player died
addChatMessage("System", "You were destroyed! Respawn in 3s...");
setTimeout(() => respawnPlayer(), 3000);
}
}
}
draw(ctx) {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
// Draw Ship Body
ctx.beginPath();
ctx.moveTo(15, 0);
ctx.lineTo(-10, 10);
ctx.lineTo(-5, 0);
ctx.lineTo(-10, -10);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
// Engine Glow
if (this.thrusting) {
ctx.beginPath();
ctx.moveTo(-8, 0);
ctx.lineTo(-18, 0);
ctx.strokeStyle = '#ffaa00';
ctx.lineWidth = 4;
ctx.stroke();
this.thrusting = false; // Reset for next frame
}
// Name Tag
if (!this.isPlayer) {
ctx.rotate(-this.angle); // Reset rotation for text
ctx.fillStyle = 'white';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.fillText(this.name, 0, -20);
}
ctx.restore();
}
}
class Bullet extends Entity {
constructor(x, y, angle, vx, vy, isPlayerBullet) {
super(x, y, 3, isPlayerBullet ? '#ffff00' : '#ff8800');
this.vx = vx;
this.vy = vy;
this.isPlayerBullet = isPlayerBullet;
this.life = 60; // Frames
}
update(dt) {
super.update(dt);
this.life--;
if (this.life <= 0) this.dead = true;
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
// Glow
ctx.shadowBlur = 5;
ctx.shadowColor = this.color;
ctx.fill();
ctx.shadowBlur = 0;
}
}
class Prize extends Entity {
constructor(x, y, type) {
super(x, y, 6, type === 'green' ? '#00ff00' : '#ffd700');
this.type = type; // green = health, gold = energy
this.bobOffset = Math.random() * Math.PI * 2;
}
draw(ctx) {
const bob = Math.sin(Date.now() / 200 + this.bobOffset) * 2;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.fillStyle = 'white';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.type === 'green' ? '+' : '⚡', this.x, this.y + bob);
}
}
class Particle extends Entity {
constructor(x, y, color) {
super(x, y, Math.random() * 3 + 1, color);
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 3;
this.vx = Math.cos(angle) * speed;
this.vy = Math.sin(angle) * speed;
this.life = 30;
}
update(dt) {
super.update(dt);
this.life--;
if(this.life <= 0) this.dead = true;
}
draw(ctx) {
ctx.globalAlpha = this.life / 30;
super.draw(ctx);
ctx.globalAlpha = 1;
}
}
// --- Global State ---
let player;
let bots = [];
let bullets = [];
let prizes = [];
let particles = [];
let chatMessages = [];
// --- Input Handling ---
const keys = {};
window.addEventListener('keydown', e => keys[e.code] = true);
window.addEventListener('keyup', e => keys[e.code] = false);
// Gamepad Polling
function handleGamepad() {
const gamepads = navigator.getGamepads();
if (!gamepads[0]) {
UI.ctrlStatus.innerText = "No Controller";
UI.ctrlStatus.style.color = "#666";
GAMEPAD_INDEX = null;
return;
}
const gp = gamepads[0];
if (gp) {
UI.ctrlStatus.innerText = "Controller Active";
UI.ctrlStatus.style.color = "#00ffcc";
GAMEPAD_INDEX = 0;
// Deadzone
const deadzone = 0.1;
let lx = gp.axes[0];
let ly = gp.axes[1];
if (Math.abs(lx) < deadzone) lx = 0;
if (Math.abs(ly) < deadzone) ly = 0;
// Movement (Rotate based on stick, Thrust if pushed)
if (lx !== 0 || ly !== 0) {
player.angle = Math.atan2(ly, lx);
// Calculate magnitude for thrust
const mag = Math.sqrt(lx*lx + ly*ly);
if (mag > 0.2) player.thrust(0.3);
}
// Shoot (Button 0 usually A/Cross)
if (gp.buttons[0].pressed) {
player.shoot();
}
}
}
// --- Game Logic Functions ---
function initGame(zoneKey) {
CURRENT_ZONE = zoneKey;
const zoneData = ZONES[zoneKey];
// Reset Arrays
bots = [];
bullets = [];
prizes = [];
particles = [];
// Create Player
player = new Ship(CANVAS.width/2, CANVAS.height/2, true, "You");
// Create Bots
for(let i=0; i<zoneData.botCount; i++) {
spawnBot();
}
// UI Updates
UI.zoneName.innerText = zoneData.name;
UI.menu.classList.add('hidden');
UI.hud.classList.remove('hidden');
UI.chat.classList.remove('hidden');
GAME_STATE = 'PLAYING';
requestAnimationFrame(gameLoop);
// Start Chat Simulation
setInterval(simulateChat, 4000);
}
function spawnBot() {
const names = ["Viper", "Wraith", "Nova", "Echo", "Razor", "Spectre", "Jinx", "Blade"];
const name = names[Math.floor(Math.random() * names.length)] + Math.floor(Math.random()*99);
const x = Math.random() * CANVAS.width;
const y = Math.random() * CANVAS.height;
bots.push(new Ship(x, y, false, name));
}
function spawnPrize(x, y) {
const type = Math.random() > 0.5 ? 'green' : 'gold';
prizes.push(new Prize(x, y, type));
}
function createExplosion(x, y, color) {
for(let i=0; i<15; i++) {
particles.push(new Particle(x, y, color));
}
}
function respawnPlayer() {
player.x = CANVAS.width/2;
player.y = CANVAS.height/2;
player.vx = 0;
player.vy = 0;
player.hp = 100;
player.energy = 100;
player.dead = false;
}
function checkCollisions() {
// Bullets vs Ships
bullets.forEach(b => {
if (b.dead) return;
// Check Player
if (b.isPlayerBullet) {
bots.forEach(bot => {
if (!bot.dead && dist(b, bot) < bot.radius + b.radius) {
b.dead = true;
bot.hp -= 10;
createExplosion(b.x, b.y, '#fff');
}
});
} else {
// Bot Bullet vs Player
if (!player.dead && dist(b, player) < player.radius + b.radius) {
b.dead = true;
player.hp -= 5;
createExplosion(b.x, b.y, '#f00');
}
}
});
// Player vs Prizes
prizes.forEach((p, index) => {
if (dist(player, p) < player.radius + p.radius) {
prizes.splice(index, 1);
if (p.type === 'green') player.hp = Math.min(player.hp + 20, 100);
if (p.type === 'gold') player.energy = 100;
}
});
}
function dist(e1, e2) {
return Math.sqrt((e1.x - e2.x)**2 + (e1.y - e2.y)**2);
}
// --- AI Logic ---
function updateBots() {
bots.forEach(bot => {
if (bot.dead) return;
const dToPlayer = dist(bot, player);
// Simple State Machine
if (dToPlayer < 300 && !player.dead) {
// Chase Player
bot.angle = Math.atan2(player.y - bot.y, player.x - bot.x);
bot.thrust(0.2);
// Shoot if aligned
const angleDiff = Math.abs(bot.angle - Math.atan2(player.y - bot.y, player.x - bot.x));
if (angleDiff < 0.5) bot.shoot();
} else {
// Wander
if (Math.random() < 0.02) bot.angle += (Math.random() - 0.5);
bot.thrust(0.1);
// Random shoot
if (Math.random() < ZONES[CURRENT_ZONE].botAggro) bot.shoot();
}
// Bot Physics (Simplified)
bot.vx *= ZONES[CURRENT_ZONE].friction;
bot.vy *= ZONES[CURRENT_ZONE].friction;
bot.x += bot.vx;
bot.y += bot.vy;
// Wrap
if (bot.x < 0) bot.x = CANVAS.width;
if (bot.x > CANVAS.width) bot.x = 0;
if (bot.y < 0) bot.y = CANVAS.height;
if (bot.y > CANVAS.height) bot.y = 0;
if (bot.hp <= 0) bot.dead = true;
});
// Respawn bots
bots = bots.filter(b => !b.dead);
if (bots.length < ZONES[CURRENT_ZONE].botCount) {
if (Math.random() < 0.01) spawnBot();
}
}
// --- Chat Simulation ---
const CHAT_PHRASES = [
"Lag?", "Nice shot!", "Anyone want to team?", "Where are the prizes?",
"Campers...", "GG", "brb", "Is this zone dead?", "Warbird incoming!"
];
const BOT_NAMES = ["Viper", "Wraith", "Nova", "Echo", "Razor"];
function simulateChat() {
if (GAME_STATE !== 'PLAYING') return;
if (Math.random() > 0.3) return; // 30% chance to chat
const name = BOT_NAMES[Math.floor(Math.random() * BOT_NAMES.length)];
const text = CHAT_PHRASES[Math.floor(Math.random() * CHAT_PHRASES.length)];
addChatMessage(name, text);
}
function addChatMessage(name, text) {
const div = document.createElement('div');
div.className = 'chat-msg';
div.innerHTML = `<span class="chat-name">${name}:</span> <span class="chat-text">${text}</span>`;
UI.chat.appendChild(div);
// Keep only last 6 messages
if (UI.chat.children.length > 6) {
UI.chat.removeChild(UI.chat.firstChild);
}
}
// --- Main Loop ---
function gameLoop(timestamp) {
if (GAME_STATE !== 'PLAYING') return;
const dt = timestamp - LAST_TIME;
LAST_TIME = timestamp;
// Clear Canvas
CTX.fillStyle = ZONES[CURRENT_ZONE].color;
CTX.fillRect(0, 0, CANVAS.width, CANVAS.height);
// Draw Grid
CTX.strokeStyle = ZONES[CURRENT_ZONE].grid;
CTX.lineWidth = 1;
CTX.beginPath();
for (let x = 0; x < CANVAS.width; x += 50) {
CTX.moveTo(x, 0);
CTX.lineTo(x, CANVAS.height);
}
for (let y = 0; y < CANVAS.height; y += 50) {
CTX.moveTo(0, y);
CTX.lineTo(CANVAS.width, y);
}
CTX.stroke();
// Handle Input (Keyboard)
if (!GAMEPAD_INDEX) {
if (keys['ArrowUp'] || keys['KeyW']) { player.thrust(0.3); }
if (keys['ArrowDown'] || keys['KeyS']) { player.thrust(-0.1); } // Reverse
if (keys['ArrowLeft'] || keys['KeyA']) { player.angle -= 0.08; }
if (keys['ArrowRight'] || keys['KeyD']) { player.angle += 0.08; }
if (keys['Space']) { player.shoot(); }
} else {
handleGamepad();
}
// Update Entities
if (!player.dead) player.update(dt);
updateBots();
bullets.forEach(b => b.update(dt));
bullets = bullets.filter(b => !b.dead);
prizes.forEach(p => p.draw(CTX)); // Prizes don't move, just draw
particles.forEach(p => p.update(dt));
particles = particles.filter(p => !p.dead);
particles.forEach(p => p.draw(CTX));
checkCollisions();
// Draw Entities
prizes.forEach(p => p.draw(CTX));
bots.forEach(b => b.draw(CTX));
bullets.forEach(b => b.draw(CTX));
if (!player.dead) player.draw(CTX);
// Update HUD
UI.score.innerText = player.score;
UI.kills.innerText = player.kills;
UI.hp.innerText = Math.floor(player.hp);
UI.energy.innerText = Math.floor(player.energy);
// HP Color
UI.hp.parentElement.style.color = player.hp < 30 ? 'red' : 'var(--danger)';
requestAnimationFrame(gameLoop);
}
// --- Initialization ---
function resize() {
CANVAS.width = window.innerWidth;
CANVAS.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Expose start function to HTML
window.startGame = initGame;
</script>
</body>
</html>