Meta Description" name="description" />
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Retro Car Dodger</title>
<style>
body {
margin: 0;
background-color: #111;
color: #fff;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
}
h1 {
margin: 5px 0;
font-size: 1.5rem;
letter-spacing: 2px;
color: #00ffcc;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0, 255, 204, 0.3);
border: 4px solid #333;
border-radius: 8px;
}
canvas {
background-color: #222;
display: block;
}
.instructions {
margin-top: 10px;
font-size: 0.9rem;
color: #888;
}
</style>
</head>
<body>
<h1>RETRO ROAD DODGER</h1>
<div id="game-container">
<canvas id="gameCanvas" width="400" height="600"></canvas>
</div>
<div class="instructions">Use <b>Left / Right Arrow Keys</b> or <b>A / D</b> to steer</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
// Game States
let score = 0;
let gameOver = false;
let gameStarted = false;
let roadSpeed = 5;
let roadLineOffset = 0;
// Player Car
const player = {
x: canvas.width / 2 - 20,
y: canvas.height - 100,
width: 40,
height: 70,
speed: 7,
color: "#ff3366"
};
// Obstacles Array
let obstacles = [];
let spawnTimer = 0;
// Input Tracking
const keys = {};
window.addEventListener("keydown", (e) => {
keys[e.code] = true;
if (!gameStarted && (e.code === "ArrowLeft" || e.code === "ArrowRight" || e.code === "KeyA" || e.code === "KeyD" || e.code === "Space")) {
gameStarted = true;
}
if (gameOver && e.code === "Space") {
resetGame();
}
});
window.addEventListener("keyup", (e) => {
keys[e.code] = false;
});
function resetGame() {
score = 0;
obstacles = [];
roadSpeed = 5;
player.x = canvas.width / 2 - 20;
gameOver = false;
gameStarted = true;
}
function spawnObstacle() {
const laneWidth = 100;
const lanes = [75, 175, 275]; // X coordinates for 3 distinct lanes
const randomLaneX = lanes[Math.floor(Math.random() * lanes.length)];
obstacles.push({
x: randomLaneX - 20,
y: -100,
width: 40,
height: 70,
color: "#33ccff",
speed: roadSpeed + (Math.random() * 2)
});
}
function update() {
if (!gameStarted || gameOver) return;
// Move player
if ((keys["ArrowLeft"] || keys["KeyA"]) && player.x > 40) {
player.x -= player.speed;
}
if ((keys["ArrowRight"] || keys["KeyD"]) && player.x < canvas.width - 80) {
player.x += player.speed;
}
// Animate road lines
roadLineOffset += roadSpeed;
if (roadLineOffset >= 40) {
roadLineOffset = 0;
}
// Spawn obstacles
spawnTimer++;
if (spawnTimer > 60) {
spawnObstacle();
spawnTimer = 0;
// Gradually increase difficulty
roadSpeed += 0.1;
}
// Update obstacles
for (let i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].y += obstacles[i].speed;
// Collision detection (AABB)
if (
player.x < obstacles[i].x + obstacles[i].width &&
player.x + player.width > obstacles[i].x &&
player.y < obstacles[i].y + obstacles[i].height &&
player.y + player.height > obstacles[i].y
) {
gameOver = true;
}
// Remove off-screen obstacles and increase score
if (obstacles[i].y > canvas.height) {
obstacles.splice(i, 1);
score += 10;
}
}
}
function drawCar(x, y, width, height, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.roundRect(x, y, width, height, 8);
ctx.fill();
// Windshield
ctx.fillStyle = "#111";
ctx.fillRect(x + 5, y + 15, width - 10, 15);
ctx.fillRect(x + 5, y + height - 20, width - 10, 10);
// Headlights
ctx.fillStyle = "#ffff33";
ctx.fillRect(x + 2, y + 2, 6, 4);
ctx.fillRect(x + width - 8, y + 2, 6, 4);
}
function draw() {
// Clear screen
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw Road
ctx.fillStyle = "#333";
ctx.fillRect(30, 0, canvas.width - 60, canvas.height);
// Road Borders
ctx.fillStyle = "#ffcc00";
ctx.fillRect(25, 0, 5, canvas.height);
ctx.fillRect(canvas.width - 30, 0, 5, canvas.height);
// Moving Center Dashes
ctx.strokeStyle = "#fff";
ctx.lineWidth = 4;
ctx.setLineDash([20, 20]);
ctx.lineDashOffset = -roadLineOffset;
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width / 2, canvas.height);
ctx.stroke();
ctx.setLineDash([]); // Reset line dash
// Draw Obstacles
for (let obs of obstacles) {
drawCar(obs.x, obs.y, obs.width, obs.height, obs.color);
}
// Draw Player
drawCar(player.x, player.y, player.width, player.height, player.color);
// Draw Score
ctx.fillStyle = "#fff";
ctx.font = "bold 18px sans-serif";
ctx.fillText("Score: " + score, 40, 35);
// Start Screen Overlay
if (!gameStarted) {
ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#00ffcc";
ctx.font = "bold 24px sans-serif";
ctx.textAlign = "center";
ctx.fillText("PRESS ANY KEY TO START", canvas.width / 2, canvas.height / 2);
ctx.textAlign = "left";
}
// Game Over Overlay
if (gameOver) {
ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#ff3366";
ctx.font = "bold 32px sans-serif";
ctx.textAlign = "center";
ctx.fillText("GAME OVER", canvas.width / 2, canvas.height / 2 - 20);
ctx.fillStyle = "#fff";
ctx.font = "18px sans-serif";
ctx.fillText("Final Score: " + score, canvas.width / 2, canvas.height / 2 + 20);
ctx.fillText("Press SPACE to Restart", canvas.width / 2, canvas.height / 2 + 60);
ctx.textAlign = "left";
}
}
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>
1
1
8KB
8KB
100.0ms
196.0ms
101.0ms