<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Escape Road</title>
<style>
html, body {
margin: 0;
padding: 0;
background: #222;
height: 100%;
overflow: hidden;
font-family: Arial, sans-serif;
touch-action: none;
}
#wrap {
position: relative;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
#game {
position: relative;
width: 100%;
max-width: 900px;
height: 100vh;
background: linear-gradient(#8ba3b8, #cfd8dc 40%, #9e9e8a 40%, #9e9e8a 44%, #555 44%);
overflow: hidden;
border-left: 8px solid #ddd;
border-right: 8px solid #ddd;
box-sizing: border-box;
}
.lamp {
position: absolute;
width: 6px;
height: 40px;
background: #444;
}
.lamp::before {
content: '';
position: absolute;
top: -10px;
left: -5px;
width: 16px;
height: 12px;
background: #ffe066;
border-radius: 4px;
box-shadow: 0 0 8px rgba(255,224,102,0.8);
}
.building {
position: absolute;
background: #607080;
border: 2px solid #3e4a55;
box-sizing: border-box;
}
.building .window {
position: absolute;
width: 10px;
height: 12px;
background: #ffe066;
opacity: 0.85;
}
.sun {
position: absolute;
width: 70px;
height: 70px;
border-radius: 50%;
background: #fff3a0;
box-shadow: 0 0 30px 10px rgba(255,243,160,0.6);
}
.cloud {
position: absolute;
width: 80px;
height: 30px;
background: rgba(255,255,255,0.9);
border-radius: 20px;
}
.cloud::before, .cloud::after {
content: '';
position: absolute;
background: rgba(255,255,255,0.9);
border-radius: 50%;
}
.cloud::before {
width: 40px; height: 40px;
top: -18px; left: 10px;
}
.cloud::after {
width: 30px; height: 30px;
top: -12px; left: 45px;
}
.laneLine {
position: absolute;
width: 6px;
height: 40px;
background: #fff;
}
.car {
position: absolute;
width: 44px;
height: 74px;
border-radius: 8px;
}
#player {
background: #ffcc00;
border: 3px solid #b38f00;
z-index: 5;
}
.enemy {
background: #ff3b3b;
border: 3px solid #a00000;
}
.coin {
position: absolute;
width: 26px;
height: 26px;
border-radius: 50%;
background: radial-gradient(circle at 35% 35%, #fff6c0, #ffd700 60%, #b8860b 100%);
border: 2px solid #b8860b;
box-shadow: 0 0 8px rgba(255,215,0,0.8);
z-index: 4;
}
#score {
position: absolute;
top: 10px;
left: 10px;
color: #fff;
font-size: 22px;
font-weight: bold;
text-shadow: 1px 1px 2px black;
z-index: 10;
}
#overlay {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
z-index: 20;
font-size: 20px;
}
#overlay button {
margin-top: 20px;
padding: 14px 28px;
font-size: 20px;
border-radius: 10px;
border: none;
background: #ffcc00;
cursor: pointer;
font-weight: bold;
}
#controls {
position: absolute;
bottom: 20px;
right: 20px;
z-index: 15;
display: grid;
grid-template-columns: 60px 60px 60px;
grid-template-rows: 60px 60px 60px;
gap: 6px;
}
#controls div {
display: flex;
align-items: center;
justify-content: center;
color: rgba(255,255,255,0.7);
font-size: 30px;
user-select: none;
background: rgba(255,255,255,0.15);
border-radius: 10px;
}
#upBtn { grid-column: 2; grid-row: 1; }
#leftBtn { grid-column: 1; grid-row: 2; }
#rightBtn { grid-column: 3; grid-row: 2; }
#downBtn { grid-column: 2; grid-row: 3; }
</style>
</head>
<body>
<div id="wrap">
<div id="game">
<div id="score">Score: 0</div>
<div id="player" class="car"></div>
<div id="overlay">
<div>🚗 Escape Road 🚗</div>
<div>Use arrow keys or buttons to dodge every way!</div>
<button id="startBtn">Start Game</button>
</div>
<div id="controls">
<div id="upBtn">▲</div>
<div id="leftBtn">◀</div>
<div id="rightBtn">▶</div>
<div id="downBtn">▼</div>
</div>
</div>
</div>
<script>
const game = document.getElementById('game');
const player = document.getElementById('player');
const scoreEl = document.getElementById('score');
const overlay = document.getElementById('overlay');
const startBtn = document.getElementById('startBtn');
const upBtn = document.getElementById('upBtn');
const downBtn = document.getElementById('downBtn');
const leftBtn = document.getElementById('leftBtn');
const rightBtn = document.getElementById('rightBtn');
let gameWidth, gameHeight;
let playerX, playerY;
const playerW = 44, playerH = 74;
const playerSpeed = 6;
let keys = {};
let running = false;
let score = 0;
let scoreTimer = 0;
let speed = 6;
let enemies = [];
let spawnTimer = 0;
let spawnInterval = 70;
let coins = [];
let coinTimer = 0;
let coinInterval = 55;
let coinCount = 0;
let frame = 0;
let lines = [];
let buildings = [];
let clouds = [];
let lamps = [];
let sunEl = null;
const roadTop = () => gameHeight * 0.4;
function resize() {
gameWidth = game.clientWidth;
gameHeight = game.clientHeight;
}
window.addEventListener('resize', resize);
resize();
let worldOffset = 0;
let worldW = 0;
function setupScenery() {
buildings.forEach(m => m.el.remove());
clouds.forEach(c => c.el.remove());
lamps.forEach(l => l.el.remove());
if (sunEl) sunEl.remove();
buildings = [];
clouds = [];
lamps = [];
worldOffset = 0;
sunEl = document.createElement('div');
sunEl.className = 'sun';
game.appendChild(sunEl);
const roadY = gameHeight * 0.4;
const buildingCount = 22;
worldW = buildingCount * 90;
for (let i = 0; i < buildingCount; i++) {
const el = document.createElement('div');
el.className = 'building';
const w = 60 + Math.random() * 40;
const h = 80 + Math.random() * 140;
const y = roadY - h;
const x = i * 90 - 60;
el.style.width = w + 'px';
el.style.height = h + 'px';
for (let wx = 8; wx < w - 15; wx += 20) {
for (let wy = 10; wy < h - 15; wy += 22) {
const win = document.createElement('div');
win.className = 'window';
win.style.left = wx + 'px';
win.style.top = wy + 'px';
el.appendChild(win);
}
}
game.appendChild(el);
buildings.push({el: el, baseX: x, y: y, w: w, depth: 0.3 + Math.random() * 0.2});
}
const lampCount = 14;
const lampSpacing = worldW / lampCount;
for (let i = 0; i < lampCount; i++) {
const el = document.createElement('div');
el.className = 'lamp';
el.style.top = (roadY - 2) + 'px';
game.appendChild(el);
lamps.push({el: el, baseX: i * lampSpacing - 30});
}
for (let i = 0; i < 6; i++) {
const el = document.createElement('div');
el.className = 'cloud';
const baseX = i * 220;
const y = 20 + Math.random() * (gameHeight * 0.25);
el.style.top = y + 'px';
game.appendChild(el);
clouds.push({el: el, baseX: baseX, y: y, depth: 0.15 + Math.random() * 0.1});
}
}
function positionScenery() {
buildings.forEach(m => {
let x = ((m.baseX - worldOffset) % worldW + worldW) % worldW - 100;
m.el.style.left = x + 'px';
});
clouds.forEach(c => {
let x = ((c.baseX - worldOffset) % (gameWidth + 1320) + (gameWidth + 1320)) % (gameWidth + 1320) - 100;
c.el.style.left = x + 'px';
});
sunEl.style.left = (gameWidth - 110 - worldOffset) % (gameWidth + 200) + 'px';
sunEl.style.top = '20px';
lamps.forEach(l => {
let x = ((l.baseX - worldOffset) % worldW + worldW) % worldW - 30;
l.el.style.left = x + 'px';
});
}
function setupLines() {
lines.forEach(l => l.el.remove());
lines = [];
const laneCount = 5;
const laneWidth = gameWidth / laneCount;
for (let lane = 1; lane < laneCount; lane++) {
for (let i = 0; i < 8; i++) {
const el = document.createElement('div');
el.className = 'laneLine';
el.style.left = (lane * laneWidth - 3) + 'px';
game.appendChild(el);
lines.push({el: el, x: lane * laneWidth - 3, y: i * 100});
}
}
}
function resetGame() {
enemies.forEach(e => e.el.remove());
enemies = [];
coins.forEach(c => c.el.remove());
coins = [];
coinCount = 0;
coinTimer = 0;
score = 0;
scoreTimer = 0;
speed = 6;
spawnInterval = 70;
spawnTimer = 0;
frame = 0;
playerX = gameWidth/2 - playerW/2;
playerY = gameHeight - 120;
updatePlayerPos();
scoreEl.textContent = 'Score: 0 | Coins: 0';
setupLines();
setupScenery();
}
function updatePlayerPos() {
playerX = Math.max(0, Math.min(gameWidth - playerW, playerX));
playerY = Math.max(0, Math.min(gameHeight - playerH, playerY));
player.style.left = playerX + 'px';
player.style.top = playerY + 'px';
}
function spawnEnemy() {
const side = Math.random() < 0.5 ? 'top' : 'side';
const el = document.createElement('div');
el.className = 'car enemy';
let x, y, vx, vy;
if (side === 'top') {
x = Math.random() * (gameWidth - 44);
y = -100;
vx = 0;
vy = speed;
} else {
const fromLeft = Math.random() < 0.5;
x = fromLeft ? -60 : gameWidth + 20;
y = Math.random() * (gameHeight - 200);
vx = fromLeft ? speed * 0.8 : -speed * 0.8;
vy = speed * 0.4;
}
el.style.left = x + 'px';
el.style.top = y + 'px';
game.appendChild(el);
enemies.push({el: el, x: x, y: y, vx: vx, vy: vy});
}
function spawnCoin() {
const el = document.createElement('div');
el.className = 'coin';
const x = Math.random() * (gameWidth - 26);
const y = -60;
el.style.left = x + 'px';
el.style.top = y + 'px';
game.appendChild(el);
coins.push({el: el, x: x, y: y});
}
function checkCoinHit(c) {
return c.x < playerX + playerW && c.x + 26 > playerX &&
c.y < playerY + playerH && c.y + 26 > playerY;
}
function checkCollision(e) {
return e.x < playerX + playerW && e.x + 44 > playerX &&
e.y < playerY + playerH && e.y + 74 > playerY;
}
function gameOver() {
running = false;
overlay.style.display = 'flex';
overlay.innerHTML = '<div>💥 Crashed! 💥</div><div>Score: ' + score + ' | Coins: ' + coinCount + '</div><button id="startBtn2">Play Again</button>';
document.getElementById('startBtn2').addEventListener('click', startGame);
}
function loop() {
if (!running) return;
frame++;
if (keys['ArrowUp']) playerY -= playerSpeed;
if (keys['ArrowDown']) playerY += playerSpeed;
if (keys['ArrowLeft']) playerX -= playerSpeed;
if (keys['ArrowRight']) playerX += playerSpeed;
updatePlayerPos();
lines.forEach(l => {
l.y += speed;
if (l.y > gameHeight) l.y -= 8 * 100;
l.el.style.top = l.y + 'px';
});
worldOffset += speed;
positionScenery();
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnTimer = 0;
spawnEnemy();
}
coinTimer++;
if (coinTimer >= coinInterval) {
coinTimer = 0;
spawnCoin();
}
for (let i = coins.length - 1; i >= 0; i--) {
const c = coins[i];
c.y += speed;
c.el.style.top = c.y + 'px';
if (checkCoinHit(c)) {
coinCount++;
c.el.remove();
coins.splice(i, 1);
scoreEl.textContent = 'Score: ' + score + ' | Coins: ' + coinCount;
continue;
}
if (c.y > gameHeight + 50) {
c.el.remove();
coins.splice(i, 1);
}
}
for (let i = enemies.length - 1; i >= 0; i--) {
const e = enemies[i];
e.x += e.vx;
e.y += e.vy;
e.el.style.left = e.x + 'px';
e.el.style.top = e.y + 'px';
if (checkCollision(e)) {
gameOver();
return;
}
if (e.y > gameHeight + 50 || e.x < -100 || e.x > gameWidth + 100) {
e.el.remove();
enemies.splice(i, 1);
}
}
scoreTimer++;
if (scoreTimer >= 10) {
scoreTimer = 0;
score++;
scoreEl.textContent = 'Score: ' + score + ' | Coins: ' + coinCount;
}
if (frame % 300 === 0) {
speed += 0.6;
if (spawnInterval > 25) spawnInterval -= 4;
}
requestAnimationFrame(loop);
}
function startGame() {
overlay.style.display = 'none';
resetGame();
running = true;
requestAnimationFrame(loop);
}
startBtn.addEventListener('click', startGame);
document.addEventListener('keydown', (e) => {
if (['ArrowUp','ArrowDown','ArrowLeft','ArrowRight'].includes(e.key)) {
keys[e.key] = true;
e.preventDefault();
}
});
document.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
function heldBtn(el, key) {
el.addEventListener('touchstart', (e) => { e.preventDefault(); keys[key] = true; });
el.addEventListener('touchend', (e) => { e.preventDefault(); keys[key] = false; });
el.addEventListener('mousedown', (e) => { e.preventDefault(); keys[key] = true; });
el.addEventListener('mouseup', (e) => { keys[key] = false; });
el.addEventListener('mouseleave', (e) => { keys[key] = false; });
}
heldBtn(upBtn, 'ArrowUp');
heldBtn(downBtn, 'ArrowDown');
heldBtn(leftBtn, 'ArrowLeft');
heldBtn(rightBtn, 'ArrowRight');
resetGame();
</script>
</body>
</html>