import React, { useState, useEffect, useRef, useCallback } from 'react';
import { Play, Pause, RotateCcw, Trophy, Flag, Zap, Fuel } from 'lucide-react';
const HillClimbRacing = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [gameOver, setGameOver] = useState(false);
const [winner, setWinner] = useState(false);
const [playerPosition, setPlayerPosition] = useState(0);
const [opponentPosition, setOpponentPosition] = useState(0);
const [fuel, setFuel] = useState(100);
const [boost, setBoost] = useState(0);
const [terrain, setTerrain] = useState([]);
const [gameSpeed, setGameSpeed] = useState(1);
const gameLoopRef = useRef(null);
const keysPressed = useRef(new Set());
// Generate realistic terrain with hills and obstacles
useEffect(() => {
const generateTerrain = () => {
const newTerrain = [];
let currentHeight = 200;
for (let i = 0; i < 300; i++) {
// Create natural-looking hills with varying steepness
const hillFactor = Math.sin(i * 0.08) * 40 + Math.cos(i * 0.03) * 30;
const noise = (Math.random() - 0.5) * 10;
currentHeight = Math.max(100, Math.min(300, 200 + hillFactor + noise));
// Determine terrain type based on slope
let type = 'normal';
if (i > 0) {
const slope = currentHeight - newTerrain[i - 1].height;
if (Math.abs(slope) > 15) {
type = 'steep';
} else if (i % 25 === 0 && i > 50) {
type = 'boost';
} else if (i % 40 === 0 && i > 30) {
type = 'rough';
}
}
newTerrain.push({ height: currentHeight, type });
}
setTerrain(newTerrain);
};
generateTerrain();
}, []);
// Handle keyboard input
const handleKeyDown = useCallback((e) => {
keysPressed.current.add(e.code);
if (e.code === 'Space') {
e.preventDefault();
if (boost > 0 && isPlaying) {
setBoost(prev => Math.max(prev - 15, 0));
setGameSpeed(2);
}
}
}, [boost, isPlaying]);
const handleKeyUp = useCallback((e) => {
keysPressed.current.delete(e.code);
if (e.code === 'Space') {
setGameSpeed(1);
}
}, []);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
return () => {
window.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('keyup', handleKeyUp);
};
}, [handleKeyDown, handleKeyUp]);
// Game loop
useEffect(() => {
if (!isPlaying || gameOver) return;
const updateGame = () => {
// Update player position
if (fuel > 0) {
const baseSpeed = 1.2;
const terrainEffect = terrain[Math.floor(playerPosition)]?.type === 'rough' ? 0.7 : 1;
const steepEffect = terrain[Math.floor(playerPosition)]?.type === 'steep' ? 0.8 : 1;
const boostEffect = gameSpeed;
const speed = baseSpeed * terrainEffect * steepEffect * boostEffect;
const newPosition = Math.min(playerPosition + speed, 299);
setPlayerPosition(newPosition);
// Consume fuel based on speed and terrain
const fuelConsumption = 0.3 * (speed / baseSpeed);
setFuel(prev => Math.max(prev - fuelConsumption, 0));
// Collect boost items
if (terrain[Math.floor(playerPosition)]?.type === 'boost') {
setBoost(prev => Math.min(prev + 25, 100));
}
}
// Update opponent AI
const opponentBaseSpeed = 1.0;
const opponentTerrainEffect = terrain[Math.floor(opponentPosition)]?.type === 'rough' ? 0.8 : 1;
const opponentSteepEffect = terrain[Math.floor(opponentPosition)]?.type === 'steep' ? 0.9 : 1;
const opponentSpeed = opponentBaseSpeed * opponentTerrainEffect * opponentSteepEffect + (Math.random() * 0.3);
const newOpponentPosition = Math.min(opponentPosition + opponentSpeed, 299);
setOpponentPosition(newOpponentPosition);
// Check win/lose conditions
if (playerPosition >= 299 && opponentPosition < 299) {
setWinner(true);
setGameOver(true);
setIsPlaying(false);
} else if (opponentPosition >= 299 && playerPosition < 299) {
setWinner(false);
setGameOver(true);
setIsPlaying(false);
} else if (fuel <= 0 && playerPosition < 299) {
setWinner(false);
setGameOver(true);
setIsPlaying(false);
}
};
gameLoopRef.current = setInterval(updateGame, 50);
return () => clearInterval(gameLoopRef.current);
}, [isPlaying, gameOver, playerPosition, opponentPosition, fuel, boost, gameSpeed, terrain]);
const startGame = () => {
setIsPlaying(true);
setGameOver(false);
setWinner(false);
setPlayerPosition(0);
setOpponentPosition(0);
setFuel(100);
setBoost(30);
setGameSpeed(1);
};
const resetGame = () => {
setIsPlaying(false);
setGameOver(false);
setWinner(false);
setPlayerPosition(0);
setOpponentPosition(0);
setFuel(100);
setBoost(30);
setGameSpeed(1);
};
// Calculate positions for rendering
const trackLength = 1200; // Total track length in pixels
const playerCarX = (playerPosition / 299) * trackLength;
const opponentCarX = (opponentPosition / 299) * trackLength;
// Calculate car rotation based on terrain slope
const getPlayerCarRotation = () => {
const currentIndex = Math.floor(playerPosition);
if (currentIndex >= terrain.length - 1) return 0;
const currentHeight = terrain[currentIndex].height;
const nextHeight = terrain[currentIndex + 1].height;
const slope = nextHeight - currentHeight;
return Math.atan(slope / 4) * (180 / Math.PI);
};
const getOpponentCarRotation = () => {
const currentIndex = Math.floor(opponentPosition);
if (currentIndex >= terrain.length - 1) return 0;
const currentHeight = terrain[currentIndex].height;
const nextHeight = terrain[currentIndex + 1].height;
const slope = nextHeight - currentHeight;
return Math.atan(slope / 4) * (180 / Math.PI);
};
const playerRotation = getPlayerCarRotation();
const opponentRotation = getOpponentCarRotation();
return (
{/* Header */}
HILL CLIMB RACING
Race to the summit before your opponent!
{/* Game Stats */}
Fuel: {Math.round(fuel)}%
Boost: {Math.round(boost)}%
Distance: {Math.round(playerPosition)}m
{!gameOver ? (
<>
>
) : (
)}
{/* Game Area */}
{/* Sky with clouds */}
{/* Sun */}
{/* Clouds */}
{/* Mountains in background */}
{/* Finish flag */}
{/* Terrain Track */}
{/* Cars */}
{/* Player Car - Detailed design */}
{/* Windshield */}
{/* Headlights */}
{/* Wheels */}
{/* Exhaust */}
PLAYER
{/* Opponent Car */}
{/* Windshield */}
{/* Headlights */}
{/* Wheels */}
OPPONENT
{/* Controls hint */}
{!isPlaying && !gameOver && (
Press SPACE to BOOST!
Use boost strategically to climb steep hills faster
)}
{/* Game Over Modal */}
{gameOver && (
{winner ? (
VICTORY!
Champion of the Hills!
) : (
X
DEFEAT!
Better luck next time!
)}
Your Distance: {Math.round(playerPosition)}m
Opponent Distance: {Math.round(opponentPosition)}m
)}
{/* Instructions */}
Game Instructions
1 Press PLAY to start the race against AI opponent
2 Hold SPACEBAR to activate BOOST (consumes boost meter)
3 Collect YELLOW BOOST ZONES to refill boost
4 Avoid ROUGH TERRAIN and manage fuel carefully!
);
};
export default HillClimbRacing;