games-folder / index.html
Asher18471's picture
Add 2 files
ad9e64d verified
Raw
History Blame Contribute Delete
30.4 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tron Light Cycles</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
body {
font-family: 'Orbitron', sans-serif;
background-color: #0f172a;
color: #00ff41;
overflow: hidden;
user-select: none;
}
#gameCanvas {
border: 2px solid #00ff41;
box-shadow: 0 0 20px #00ff41;
background-color: #111827;
}
.glow {
text-shadow: 0 0 10px #00ff41;
}
.trail-1 {
background-color: #3b82f6;
box-shadow: 0 0 10px #3b82f6;
}
.trail-2 {
background-color: #ef4444;
box-shadow: 0 0 10px #ef4444;
}
.power-up {
background-color: #f59e0b;
box-shadow: 0 0 15px #f59e0b;
animation: pulse 1.5s infinite;
border-radius: 50%;
}
@keyframes pulse {
0% { transform: scale(0.95); opacity: 0.8; }
50% { transform: scale(1.05); opacity: 1; }
100% { transform: scale(0.95); opacity: 0.8; }
}
.modal {
background-color: rgba(15, 23, 42, 0.9);
border: 2px solid #00ff41;
box-shadow: 0 0 30px #00ff41;
}
.btn {
transition: all 0.3s;
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 0 15px #00ff41;
}
.btn:active {
transform: scale(0.95);
}
@keyframes crash {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.5); opacity: 0.7; }
100% { transform: scale(2); opacity: 0; }
}
.crash-animation {
animation: crash 0.5s forwards;
}
.countdown {
font-size: 10rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
opacity: 0;
animation: countdownFade 1s;
}
@keyframes countdownFade {
0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
50% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
}
</style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen p-4">
<h1 class="text-4xl md:text-6xl font-bold mb-4 glow">TRON LIGHT CYCLES</h1>
<div class="relative">
<canvas id="gameCanvas" width="800" height="600" class="mb-4"></canvas>
<div id="countdown" class="countdown absolute hidden"></div>
<div id="startScreen" class="modal absolute inset-0 flex flex-col items-center justify-center p-8">
<h2 class="text-3xl font-bold mb-6 glow">WELCOME TO THE GRID</h2>
<div class="flex gap-4 mb-8">
<div class="text-center">
<h3 class="text-xl font-bold mb-2">PLAYER 1</h3>
<div class="flex flex-col items-center">
<div class="w-8 h-8 bg-blue-500 mb-2"></div>
<p>WASD to move</p>
</div>
</div>
<div class="text-center">
<h3 class="text-xl font-bold mb-2">PLAYER 2</h3>
<div class="flex flex-col items-center">
<div class="w-8 h-8 bg-red-500 mb-2"></div>
<p>Arrow keys to move</p>
</div>
</div>
</div>
<div class="flex gap-4">
<button id="startBtn" class="btn px-6 py-3 bg-transparent border-2 border-green-500 text-green-500 font-bold rounded hover:bg-green-500 hover:text-black">
START GAME
</button>
<button id="aiBtn" class="btn px-6 py-3 bg-transparent border-2 border-yellow-500 text-yellow-500 font-bold rounded hover:bg-yellow-500 hover:text-black">
VS COMPUTER
</button>
</div>
</div>
<div id="gameOverScreen" class="modal absolute inset-0 hidden flex-col items-center justify-center p-8">
<h2 id="winnerText" class="text-4xl font-bold mb-6 glow"></h2>
<p id="crashReason" class="text-xl mb-6 text-center max-w-md"></p>
<div class="flex gap-4">
<button id="restartBtn" class="btn px-6 py-3 bg-transparent border-2 border-green-500 text-green-500 font-bold rounded hover:bg-green-500 hover:text-black">
PLAY AGAIN
</button>
<button id="menuBtn" class="btn px-6 py-3 bg-transparent border-2 border-blue-500 text-blue-500 font-bold rounded hover:bg-blue-500 hover:text-black">
MAIN MENU
</button>
</div>
</div>
</div>
<div class="flex gap-8 mt-4">
<div class="text-center">
<h3 class="text-xl font-bold mb-2">PLAYER 1</h3>
<p id="p1Score" class="text-2xl">0</p>
</div>
<div class="text-center">
<h3 class="text-xl font-bold mb-2">PLAYER 2</h3>
<p id="p2Score" class="text-2xl">0</p>
</div>
</div>
<div class="mt-6 text-sm text-gray-400">
<p>Collect yellow power-ups for temporary speed boost!</p>
</div>
<script>
// Game constants
const GRID_SIZE = 20;
const CELL_SIZE = 20;
const GAME_WIDTH = 800;
const GAME_HEIGHT = 600;
const GRID_COLS = GAME_WIDTH / GRID_SIZE;
const GRID_ROWS = GAME_HEIGHT / GRID_SIZE;
// Game variables
let gameRunning = false;
let gameLoop;
let isAIEnabled = false;
let scores = [0, 0];
let crashPosition = null;
let crashColor = null;
let crashFrame = 0;
let crashReason = "";
// Players
const players = [
{
id: 0,
x: 5,
y: Math.floor(GRID_ROWS / 2),
dx: 1,
dy: 0,
color: '#3b82f6',
trail: [],
speed: 3, // Slower initial speed
boostTimer: 0,
controls: {
up: 'w',
down: 's',
left: 'a',
right: 'd'
},
keys: {
up: false,
down: false,
left: false,
right: false
}
},
{
id: 1,
x: GRID_COLS - 5,
y: Math.floor(GRID_ROWS / 2),
dx: -1,
dy: 0,
color: '#ef4444',
trail: [],
speed: 3, // Slower initial speed
boostTimer: 0,
controls: {
up: 'ArrowUp',
down: 'ArrowDown',
left: 'ArrowLeft',
right: 'ArrowRight'
},
keys: {
up: false,
down: false,
left: false,
right: false
}
}
];
// Power-ups
let powerUps = [];
const POWER_UP_DURATION = 300; // frames
const POWER_UP_BOOST = 2; // Reduced boost effect
// DOM elements
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const winnerText = document.getElementById('winnerText');
const crashReasonElement = document.getElementById('crashReason');
const startBtn = document.getElementById('startBtn');
const aiBtn = document.getElementById('aiBtn');
const restartBtn = document.getElementById('restartBtn');
const menuBtn = document.getElementById('menuBtn');
const p1Score = document.getElementById('p1Score');
const p2Score = document.getElementById('p2Score');
const countdownElement = document.getElementById('countdown');
// Event listeners
startBtn.addEventListener('click', startGame);
aiBtn.addEventListener('click', startAI);
restartBtn.addEventListener('click', restartGame);
menuBtn.addEventListener('click', showMenu);
document.addEventListener('keydown', handleKeyDown);
document.addEventListener('keyup', handleKeyUp);
// Initialize game
function initGame() {
// Reset players
players[0] = {
...players[0],
x: 5,
y: Math.floor(GRID_ROWS / 2),
dx: 1,
dy: 0,
trail: [],
speed: 3,
boostTimer: 0
};
players[1] = {
...players[1],
x: GRID_COLS - 5,
y: Math.floor(GRID_ROWS / 2),
dx: -1,
dy: 0,
trail: [],
speed: 3,
boostTimer: 0
};
// Clear power-ups
powerUps = [];
crashPosition = null;
crashColor = null;
crashFrame = 0;
// Generate initial trails
for (let i = 0; i < 5; i++) {
players[0].trail.push({
x: players[0].x - i * players[0].dx,
y: players[0].y - i * players[0].dy
});
players[1].trail.push({
x: players[1].x - i * players[1].dx,
y: players[1].y - i * players[1].dy
});
}
// Spawn initial power-ups
spawnPowerUp();
spawnPowerUp();
// Draw initial state
draw();
}
// Start countdown
function startCountdown() {
countdownElement.classList.remove('hidden');
let count = 3;
countdownElement.textContent = count;
const countdownInterval = setInterval(() => {
count--;
if (count > 0) {
countdownElement.textContent = count;
countdownElement.style.animation = 'none';
countdownElement.offsetHeight; // Trigger reflow
countdownElement.style.animation = 'countdownFade 1s';
} else {
countdownElement.textContent = 'GO!';
countdownElement.style.animation = 'none';
countdownElement.offsetHeight; // Trigger reflow
countdownElement.style.animation = 'countdownFade 0.5s';
setTimeout(() => {
countdownElement.classList.add('hidden');
clearInterval(countdownInterval);
gameRunning = true;
}, 500);
}
}, 1000);
}
// Start game
function startGame() {
isAIEnabled = false;
startScreen.classList.add('hidden');
initGame();
// Start countdown
startCountdown();
// Start game loop
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(update, 1000 / 60); // 60 FPS
}
// Start game vs AI
function startAI() {
isAIEnabled = true;
startScreen.classList.add('hidden');
initGame();
// Start countdown
startCountdown();
// Start game loop
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(update, 1000 / 60); // 60 FPS
}
// Restart game
function restartGame() {
gameOverScreen.classList.add('hidden');
initGame();
// Start countdown
startCountdown();
// Start game loop
if (gameLoop) clearInterval(gameLoop);
gameLoop = setInterval(update, 1000 / 60); // 60 FPS
}
// Show menu
function showMenu() {
gameOverScreen.classList.add('hidden');
startScreen.classList.remove('hidden');
gameRunning = false;
if (gameLoop) {
clearInterval(gameLoop);
gameLoop = null;
}
}
// Game over
function gameOver(winner, reason) {
gameRunning = false;
clearInterval(gameLoop);
crashReason = reason;
// Update scores
if (winner === 0) {
scores[0]++;
p1Score.textContent = scores[0];
winnerText.textContent = 'PLAYER 1 WINS!';
winnerText.className = 'text-4xl font-bold mb-6 glow text-blue-500';
} else {
scores[1]++;
p2Score.textContent = scores[1];
winnerText.textContent = isAIEnabled ? 'COMPUTER WINS!' : 'PLAYER 2 WINS!';
winnerText.className = 'text-4xl font-bold mb-6 glow text-red-500';
}
crashReasonElement.textContent = crashReason;
gameOverScreen.classList.remove('hidden');
}
// Update game state
function update() {
if (!gameRunning) {
draw();
return;
}
// Move players
players.forEach((player, index) => {
// Handle AI movement for player 2 if AI is enabled
if (isAIEnabled && index === 1) {
aiMovement(player);
}
// Handle player movement
handlePlayerMovement(player);
// Move player
if (frameCount % (15 - player.speed) === 0) { // Adjusted speed calculation
player.x += player.dx;
player.y += player.dy;
// Add new position to trail
player.trail.unshift({ x: player.x, y: player.y });
// Remove oldest trail segment if not boosting (longer trail when boosting)
if (player.boostTimer <= 0 && player.trail.length > 5) {
player.trail.pop();
}
// Check collisions
const collision = checkCollisions(player);
if (collision) {
crashPosition = { x: player.x, y: player.y };
crashColor = player.color;
crashFrame = 0;
gameOver(player.id === 0 ? 1 : 0, collision.reason);
return;
}
// Check power-up collection
checkPowerUps(player);
}
// Update boost timer
if (player.boostTimer > 0) {
player.boostTimer--;
if (player.boostTimer === 0) {
player.speed -= POWER_UP_BOOST;
}
}
});
// Spawn new power-ups occasionally
if (Math.random() < 0.005 && powerUps.length < 3) {
spawnPowerUp();
}
// Draw everything
draw();
frameCount++;
}
let frameCount = 0;
// AI movement logic
function aiMovement(player) {
// Simple AI that avoids walls and tries to trap the player
const directions = [
{ dx: 0, dy: -1 }, // up
{ dx: 0, dy: 1 }, // down
{ dx: -1, dy: 0 }, // left
{ dx: 1, dy: 0 } // right
];
// Don't reverse direction
const invalidDirection = { dx: -player.dx, dy: -player.dy };
// Find safe directions
const safeDirections = directions.filter(dir => {
// Skip invalid direction (reverse)
if (dir.dx === invalidDirection.dx && dir.dy === invalidDirection.dy) {
return false;
}
// Check if next position is safe
const nextX = player.x + dir.dx;
const nextY = player.y + dir.dy;
// Check boundaries
if (nextX < 0 || nextX >= GRID_COLS || nextY < 0 || nextY >= GRID_ROWS) {
return false;
}
// Check trails
for (const p of players) {
for (const segment of p.trail) {
if (segment.x === nextX && segment.y === nextY) {
return false;
}
}
}
return true;
});
// If no safe directions, game over is imminent
if (safeDirections.length === 0) return;
// Choose a random safe direction (could be enhanced with more sophisticated AI)
const randomIndex = Math.floor(Math.random() * safeDirections.length);
const newDir = safeDirections[randomIndex];
player.dx = newDir.dx;
player.dy = newDir.dy;
}
// Handle player movement based on key presses
function handlePlayerMovement(player) {
// Change direction based on key presses, but prevent 180-degree turns
if (player.keys.up && player.dy !== 1) {
player.dx = 0;
player.dy = -1;
} else if (player.keys.down && player.dy !== -1) {
player.dx = 0;
player.dy = 1;
} else if (player.keys.left && player.dx !== 1) {
player.dx = -1;
player.dy = 0;
} else if (player.keys.right && player.dx !== -1) {
player.dx = 1;
player.dy = 0;
}
}
// Check for collisions
function checkCollisions(player) {
// Check wall collisions
if (player.x < 0) {
return { reason: "Player " + (player.id + 1) + " crashed into the left wall!" };
}
if (player.x >= GRID_COLS) {
return { reason: "Player " + (player.id + 1) + " crashed into the right wall!" };
}
if (player.y < 0) {
return { reason: "Player " + (player.id + 1) + " crashed into the top wall!" };
}
if (player.y >= GRID_ROWS) {
return { reason: "Player " + (player.id + 1) + " crashed into the bottom wall!" };
}
// Check trail collisions (including own trail)
for (const p of players) {
// Skip the head of the current player
const startIndex = p === player ? 1 : 0;
for (let i = startIndex; i < p.trail.length; i++) {
const segment = p.trail[i];
if (segment.x === player.x && segment.y === player.y) {
if (p === player) {
return { reason: "Player " + (player.id + 1) + " crashed into their own trail!" };
} else {
return { reason: "Player " + (player.id + 1) + " crashed into " +
(p.id === 0 ? "Player 1" : isAIEnabled ? "the Computer" : "Player 2") + "'s trail!" };
}
}
}
}
return null;
}
// Check power-up collection
function checkPowerUps(player) {
for (let i = powerUps.length - 1; i >= 0; i--) {
const powerUp = powerUps[i];
if (powerUp.x === player.x && powerUp.y === player.y) {
// Apply speed boost
player.speed += POWER_UP_BOOST;
player.boostTimer = POWER_UP_DURATION;
// Remove power-up
powerUps.splice(i, 1);
// Spawn new power-up
spawnPowerUp();
}
}
}
// Spawn a new power-up
function spawnPowerUp() {
let x, y;
let validPosition = false;
// Keep trying until we find a valid position
while (!validPosition) {
x = Math.floor(Math.random() * GRID_COLS);
y = Math.floor(Math.random() * GRID_ROWS);
validPosition = true;
// Check if position is on any trail
for (const player of players) {
for (const segment of player.trail) {
if (segment.x === x && segment.y === y) {
validPosition = false;
break;
}
}
if (!validPosition) break;
}
// Check if position is on another power-up
for (const powerUp of powerUps) {
if (powerUp.x === x && powerUp.y === y) {
validPosition = false;
break;
}
}
}
powerUps.push({ x, y });
}
// Draw game
function draw() {
// Clear canvas
ctx.fillStyle = '#111827';
ctx.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
// Draw grid lines
ctx.strokeStyle = '#1e293b';
ctx.lineWidth = 1;
for (let x = 0; x <= GAME_WIDTH; x += GRID_SIZE) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, GAME_HEIGHT);
ctx.stroke();
}
for (let y = 0; y <= GAME_HEIGHT; y += GRID_SIZE) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(GAME_WIDTH, y);
ctx.stroke();
}
// Draw power-ups
powerUps.forEach(powerUp => {
ctx.fillStyle = '#f59e0b';
ctx.beginPath();
ctx.arc(
powerUp.x * GRID_SIZE + GRID_SIZE / 2,
powerUp.y * GRID_SIZE + GRID_SIZE / 2,
GRID_SIZE / 2 - 2,
0,
Math.PI * 2
);
ctx.fill();
});
// Draw trails
players.forEach(player => {
// Draw trail
player.trail.forEach((segment, index) => {
const alpha = index === 0 ? 1 : 0.7 - (index / player.trail.length) * 0.5;
ctx.fillStyle = player.color;
ctx.globalAlpha = alpha;
ctx.fillRect(
segment.x * GRID_SIZE,
segment.y * GRID_SIZE,
GRID_SIZE,
GRID_SIZE
);
});
// Reset alpha
ctx.globalAlpha = 1;
// Draw head (with different shape)
ctx.fillStyle = player.color;
ctx.beginPath();
// Draw a bike-like shape based on direction
const centerX = player.x * GRID_SIZE + GRID_SIZE / 2;
const centerY = player.y * GRID_SIZE + GRID_SIZE / 2;
if (player.dx === 1) { // right
ctx.moveTo(centerX - GRID_SIZE / 3, centerY - GRID_SIZE / 2);
ctx.lineTo(centerX + GRID_SIZE / 2, centerY);
ctx.lineTo(centerX - GRID_SIZE / 3, centerY + GRID_SIZE / 2);
} else if (player.dx === -1) { // left
ctx.moveTo(centerX + GRID_SIZE / 3, centerY - GRID_SIZE / 2);
ctx.lineTo(centerX - GRID_SIZE / 2, centerY);
ctx.lineTo(centerX + GRID_SIZE / 3, centerY + GRID_SIZE / 2);
} else if (player.dy === 1) { // down
ctx.moveTo(centerX - GRID_SIZE / 2, centerY - GRID_SIZE / 3);
ctx.lineTo(centerX, centerY + GRID_SIZE / 2);
ctx.lineTo(centerX + GRID_SIZE / 2, centerY - GRID_SIZE / 3);
} else { // up
ctx.moveTo(centerX - GRID_SIZE / 2, centerY + GRID_SIZE / 3);
ctx.lineTo(centerX, centerY - GRID_SIZE / 2);
ctx.lineTo(centerX + GRID_SIZE / 2, centerY + GRID_SIZE / 3);
}
ctx.closePath();
ctx.fill();
// Draw boost effect if active
if (player.boostTimer > 0) {
ctx.strokeStyle = player.color;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(
centerX,
centerY,
GRID_SIZE / 1.5,
0,
Math.PI * 2
);
ctx.stroke();
}
});
// Draw crash animation if active
if (crashPosition && crashFrame < 30) {
const progress = crashFrame / 30;
const size = GRID_SIZE * (1 + progress * 3);
const alpha = 1 - progress;
ctx.fillStyle = crashColor;
ctx.globalAlpha = alpha;
ctx.beginPath();
ctx.arc(
crashPosition.x * GRID_SIZE + GRID_SIZE / 2,
crashPosition.y * GRID_SIZE + GRID_SIZE / 2,
size / 2,
0,
Math.PI * 2
);
ctx.fill();
ctx.globalAlpha = 1;
crashFrame++;
}
}
// Handle key down events
function handleKeyDown(e) {
players.forEach(player => {
if (e.key.toLowerCase() === player.controls.up.toLowerCase()) {
player.keys.up = true;
}
if (e.key.toLowerCase() === player.controls.down.toLowerCase()) {
player.keys.down = true;
}
if (e.key.toLowerCase() === player.controls.left.toLowerCase()) {
player.keys.left = true;
}
if (e.key.toLowerCase() === player.controls.right.toLowerCase()) {
player.keys.right = true;
}
});
// Space to pause
if (e.key === ' ' && gameRunning) {
gameRunning = !gameRunning;
if (gameRunning) {
gameLoop = setInterval(update, 1000 / 60);
} else {
clearInterval(gameLoop);
}
}
}
// Handle key up events
function handleKeyUp(e) {
players.forEach(player => {
if (e.key.toLowerCase() === player.controls.up.toLowerCase()) {
player.keys.up = false;
}
if (e.key.toLowerCase() === player.controls.down.toLowerCase()) {
player.keys.down = false;
}
if (e.key.toLowerCase() === player.controls.left.toLowerCase()) {
player.keys.left = false;
}
if (e.key.toLowerCase() === player.controls.right.toLowerCase()) {
player.keys.right = false;
}
});
}
// Initial draw
draw();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Asher18471/games-folder" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>