anycoder-f95a4a78 / index.html
samirerty's picture
Upload folder using huggingface_hub
93ea218 verified
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>بازی ماشینی سرعتی (Top Down)</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700;900&display=swap');
:root {
--primary-color: #00f2ff;
--accent-color: #ff0055;
--road-color: #2a2a2a;
--grass-color: #1a4a1a;
--ui-bg: rgba(0, 0, 0, 0.85);
}
* {
box-sizing: border-box;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
body {
margin: 0;
padding: 0;
background-color: #0f0f0f;
color: white;
font-family: 'Vazirmatn', sans-serif;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
/* Header & Credit */
header {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 100;
pointer-events: none;
}
.game-title {
font-size: 1.5rem;
font-weight: 900;
text-transform: uppercase;
color: var(--primary-color);
text-shadow: 0 0 10px var(--primary-color);
}
.credit-link {
pointer-events: auto;
font-size: 0.8rem;
color: #aaa;
text-decoration: none;
background: rgba(255,255,255,0.1);
padding: 5px 10px;
border-radius: 15px;
transition: all 0.3s ease;
}
.credit-link:hover {
background: var(--primary-color);
color: #000;
box-shadow: 0 0 15px var(--primary-color);
}
/* Game Container */
#game-container {
position: relative;
width: 100%;
max-width: 450px;
height: 100vh;
max-height: 800px;
background-color: var(--road-color);
overflow: hidden;
box-shadow: 0 0 50px rgba(0,0,0,0.5);
border-left: 5px solid #111;
border-right: 5px solid #111;
}
/* Road Markings */
.road-line {
position: absolute;
width: 10px;
height: 100px;
background: rgba(255, 255, 255, 0.5);
left: 50%;
transform: translateX(-50%);
animation: moveRoad 1s linear infinite;
}
@keyframes moveRoad {
0% { top: -100px; }
100% { top: 100%; }
}
/* Player Car */
#player-car {
position: absolute;
bottom: 100px;
left: 50%;
width: 50px;
height: 90px;
background: linear-gradient(180deg, #ffcc00, #ff9900);
border-radius: 10px;
box-shadow: 0 10px 20px rgba(0,0,0,0.5);
z-index: 10;
transition: left 0.1s ease-out;
transform: translateX(-50%);
}
/* Car Details (Windshield, Lights) */
#player-car::before {
content: '';
position: absolute;
top: 20%;
left: 10%;
width: 80%;
height: 20%;
background: #333;
border-radius: 2px;
}
#player-car::after {
content: '';
position: absolute;
top: 0;
left: 5%;
width: 90%;
height: 10px;
background: #ff3333;
box-shadow: 0 0 10px #ff0000;
border-radius: 5px 5px 0 0;
}
/* Enemy Cars */
.enemy {
position: absolute;
width: 50px;
height: 90px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
z-index: 9;
top: -100px;
}
.enemy::before {
content: '';
position: absolute;
bottom: 20%;
left: 10%;
width: 80%;
height: 20%;
background: #222;
border-radius: 2px;
}
/* UI Overlays */
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--ui-bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 50;
backdrop-filter: blur(5px);
transition: opacity 0.3s;
}
.hidden {
opacity: 0;
pointer-events: none;
}
h1 {
font-size: 3rem;
margin-bottom: 10px;
color: var(--primary-color);
text-shadow: 2px 2px 0px var(--accent-color);
text-align: center;
}
p {
font-size: 1.2rem;
margin-bottom: 30px;
color: #ddd;
text-align: center;
max-width: 80%;
}
.btn {
background: var(--accent-color);
color: white;
padding: 15px 40px;
font-size: 1.5rem;
font-family: 'Vazirmatn', sans-serif;
border: none;
border-radius: 50px;
cursor: pointer;
box-shadow: 0 0 20px var(--accent-color);
transition: transform 0.2s, box-shadow 0.2s;
font-weight: 700;
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 0 30px var(--accent-color);
}
.btn:active {
transform: scale(0.95);
}
/* HUD (Heads Up Display) */
#hud {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
display: flex;
justify-content: space-between;
pointer-events: none;
z-index: 20;
}
.stat-box {
background: rgba(0,0,0,0.6);
padding: 10px 20px;
border-radius: 20px;
border: 1px solid rgba(255,255,255,0.2);
font-size: 1.5rem;
font-weight: bold;
color: white;
}
#score-display span, #speed-display span {
color: var(--primary-color);
}
/* Mobile Controls */
#mobile-controls {
position: absolute;
bottom: 20px;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 40;
pointer-events: none; /* Let clicks pass through empty space */
}
.control-btn {
width: 80px;
height: 80px;
background: rgba(255, 255, 255, 0.15);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: white;
pointer-events: auto;
transition: background 0.2s;
touch-action: manipulation;
}
.control-btn:active {
background: rgba(255, 255, 255, 0.4);
}
.control-btn.left:active { border-color: var(--primary-color); }
.control-btn.right:active { border-color: var(--primary-color); }
/* Responsive adjustments */
@media (min-width: 768px) {
#mobile-controls { display: none; } /* Hide touch controls on desktop */
h1 { font-size: 4rem; }
}
</style>
</head>
<body>
<header>
<div class="game-title">بازی ماشینی 🏎️</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="credit-link">Built with anycoder</a>
</header>
<div id="game-container">
<!-- Road Lines Animation -->
<div class="road-line" style="animation-delay: 0s;"></div>
<div class="road-line" style="animation-delay: 0.5s;"></div>
<!-- HUD -->
<div id="hud">
<div class="stat-box" id="score-display">امتیاز: <span id="score">0</span></div>
<div class="stat-box" id="speed-display">سرعت: <span id="speed">100</span> کیلومتر</div>
</div>
<!-- Player Car -->
<div id="player-car"></div>
<!-- Start Screen -->
<div id="start-screen" class="overlay">
<h1>تک سواست</h1>
<p>از موانع عبور کنید و امتیاز بگیرید.<br>برای حرکت از کلیدهای جهت‌نما یا دکمه‌های صفحه استفاده کنید.</p>
<button class="btn" onclick="startGame()">شروع بازی</button>
</div>
<!-- Game Over Screen -->
<div id="game-over-screen" class="overlay hidden">
<h1 style="color: var(--accent-color);">تصادف کردید!</h1>
<p>امتیاز نهایی شما: <span id="final-score" style="color: var(--primary-color); font-weight: bold;">0</span></p>
<button class="btn" onclick="resetGame()">بازی مجدد</button>
</div>
<!-- Mobile Controls -->
<div id="mobile-controls">
<div class="control-btn left" id="btn-left"></div>
<div class="control-btn right" id="btn-right"></div>
</div>
</div>
<script>
// --- Game Configuration & State ---
const gameContainer = document.getElementById('game-container');
const playerCar = document.getElementById('player-car');
const scoreEl = document.getElementById('score');
const finalScoreEl = document.getElementById('final-score');
const speedEl = document.getElementById('speed');
const startScreen = document.getElementById('start-screen');
const gameOverScreen = document.getElementById('game-over-screen');
let gameActive = false;
let score = 0;
let gameSpeed = 5;
let lane = 1; // 0: Left, 1: Center, 2: Right (approximate percentages)
let playerX = 50; // Percentage
let enemies = [];
let roadLines = [];
let animationId;
let spawnInterval;
let speedInterval;
// Constants
const CONTAINER_WIDTH = 450; // Max width in pixels
const CAR_WIDTH = 50;
const LANE_WIDTH_PERCENT = 33.33;
const BASE_SPEED = 5;
const MAX_SPEED = 20;
// --- Input Handling ---
// Keyboard
document.addEventListener('keydown', (e) => {
if (!gameActive) return;
if (e.key === 'ArrowLeft' || e.key === 'a') moveCar(-1);
if (e.key === 'ArrowRight' || e.key === 'd') moveCar(1);
});
// Touch / Mouse for Mobile Controls
const btnLeft = document.getElementById('btn-left');
const btnRight = document.getElementById('btn-right');
const handleInputStart = (direction) => {
if (!gameActive) return;
moveCar(direction);
};
// Add touch listeners
btnLeft.addEventListener('touchstart', (e) => { e.preventDefault(); handleInputStart(-1); });
btnRight.addEventListener('touchstart', (e) => { e.preventDefault(); handleInputStart(1); });
// Add mouse listeners for testing on desktop with mouse
btnLeft.addEventListener('mousedown', () => handleInputStart(-1));
btnRight.addEventListener('mousedown', () => handleInputStart(1));
function moveCar(direction) {
// Lane logic: 15% (Left), 50% (Center), 85% (Right)
if (direction === -1 && playerX > 15) {
playerX -= 35;
} else if (direction === 1 && playerX < 85) {
playerX += 35;
}
playerCar.style.left = `${playerX}%`;
}
// --- Game Logic ---
function startGame() {
startScreen.classList.add('hidden');
gameOverScreen.classList.add('hidden');
// Reset State
gameActive = true;
score = 0;
gameSpeed = BASE_SPEED;
enemies.forEach(enemy => enemy.remove());
enemies = [];
playerX = 50;
playerCar.style.left = '50%';
updateHUD();
// Start Loops
gameLoop();
spawnEnemies();
increaseSpeed();
}
function resetGame() {
startGame();
}
function gameOver() {
gameActive = false;
cancelAnimationFrame(animationId);
clearInterval(spawnInterval);
clearInterval(speedInterval);
finalScoreEl.innerText = score;
gameOverScreen.classList.remove('hidden');
// Simple crash effect
playerCar.style.background = 'linear-gradient(180deg, #555, #000)';
playerCar.style.transform = 'translateX(-50%) rotate(15deg)';
}
function spawnEnemies() {
spawnInterval = setInterval(() => {
if (!gameActive) return;
const enemy = document.createElement('div');
enemy.classList.add('enemy');
// Random Color for enemies
const colors = ['#ff0055', '#00f2ff', '#cc00ff', '#00ff66', '#ff9900'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
enemy.style.background = `linear-gradient(180deg, ${randomColor}, #000)`;
// Random Lane (15, 50, 85)
const lanes = [15, 50, 85];
const randomLane = lanes[Math.floor(Math.random() * lanes.length)];
enemy.style.left = `${randomLane}%`;
enemy.style.top = '-100px';
// Store data for movement
enemy.dataset.speed = gameSpeed * 1.2; // Enemies move slightly faster than road relative to player
enemy.dataset.lane = randomLane;
gameContainer.appendChild(enemy);
enemies.push(enemy);
}, 1000 - (score * 0.005)); // Spawn faster as score increases (min 400ms)
// Ensure minimum spawn time
if (spawnInterval) {
// This is a bit tricky with setInterval, so we just let it run or clear/restart
// For simplicity in this demo, we'll keep the interval constant or slightly dynamic
// Let's just use a timeout recursion for better control
spawnEnemyRecursive();
clearInterval(spawnInterval);
}
}
function spawnEnemyRecursive() {
if (!gameActive) return;
const enemy = document.createElement('div');
enemy.classList.add('enemy');
const colors = ['#ff0055', '#00f2ff', '#cc00ff', '#00ff66', '#ff9900'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
enemy.style.background = `linear-gradient(180deg, ${randomColor}, #000)`;
const lanes = [15, 50, 85];
const randomLane = lanes[Math.floor(Math.random() * lanes.length)];
// Prevent spawning on top of another car
const tooClose = enemies.some(e => Math.abs(parseInt(e.style.top) - (-100)) < 150 && Math.abs(parseInt(e.style.left) - randomLane) < 5);
if (!tooClose) {
enemy.style.left = `${randomLane}%`;
enemy.style.top = '-100px';
enemy.style.zIndex = 9;
gameContainer.appendChild(enemy);
enemies.push(enemy);
}
// Difficulty scaling for spawn rate
let spawnRate = 1000 - (score * 0.01);
if (spawnRate < 400) spawnRate = 400;
setTimeout(spawnEnemyRecursive, spawnRate);
}
function increaseSpeed() {
speedInterval = setInterval(() => {
if (!gameActive) return;
if (gameSpeed < MAX_SPEED) {
gameSpeed += 0.5;
updateHUD();
}
}, 5000);
}
function gameLoop() {
if (!gameActive) return;
// Move Road Lines (Visual effect)
const roadLines = document.querySelectorAll('.road-line');
roadLines.forEach(line => {
let top = parseFloat(getComputedStyle(line).top);
if (top > 100) {
line.style.top = '-100px';
}
line.style.top = `${top + gameSpeed * 2}px`;
});
// Move Enemies
enemies.forEach((enemy, index) => {
let currentTop = parseFloat(getComputedStyle(enemy).top);
let speed = gameSpeed * 1.5; // Relative speed
// Move enemy down
let newTop = currentTop + speed;
enemy.style.top = `${newTop}px`;
// Collision Detection
if (checkCollision(playerCar, enemy)) {
gameOver();
return;
}
// Remove if off screen
if (newTop > gameContainer.offsetHeight) {
enemy.remove();
enemies.splice(index, 1);
score += 10;
updateHUD();
}
});
animationId = requestAnimationFrame(gameLoop);
}
function checkCollision(player, enemy) {
const pRect = player.getBoundingClientRect();
const eRect = enemy.getBoundingClientRect();
// Shrink hitbox slightly for better gameplay feel
const padding = 5;
return !(
pRect.top + padding > eRect.bottom - padding ||
pRect.bottom - padding < eRect.top + padding ||
pRect.right - padding < eRect.left + padding ||
pRect.left + padding > eRect.right - padding
);
}
function updateHUD() {
scoreEl.innerText = score;
speedEl.innerText = Math.floor(100 + (gameSpeed * 10));
// Dynamic color for speed
if (gameSpeed > 15) speedEl.style.color = '#ff0055';
else if (gameSpeed > 10) speedEl.style.color = '#ffcc00';
else speedEl.style.color = '#00f2ff';
}
// Initialize Road Lines
function initRoadLines() {
for(let i=0; i<5; i++) {
const line = document.createElement('div');
line.classList.add('road-line');
line.style.top = `${i * 25}%`;
gameContainer.appendChild(line);
roadLines.push(line);
}
}
initRoadLines();
</script>
</body>
</html>