<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Real Drive Car Game</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: Arial, sans-serif;
background: #87ceeb;
}
canvas {
display: block;
}
#hud {
position: fixed;
top: 10px;
left: 10px;
right: 10px;
color: white;
z-index: 2;
pointer-events: none;
text-shadow: 1px 2px 3px black;
}
#controls {
position: fixed;
bottom: 20px;
left: 0;
right: 0;
display: flex;
justify-content: space-around;
z-index: 3;
}
button {
padding: 14px;
border: 0;
border-radius: 12px;
background: #087f5b;
color: white;
font-size: 15px;
font-weight: bold;
margin: 3px;
}
#menu {
position: fixed;
inset: 0;
background: #102536ee;
color: white;
z-index: 5;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div id="menu">
<h1>๐ REAL DRIVE</h1>
<p>Open World Car Simulator</p>
<button onclick="startGame()">PLAY GAME</button>
<button onclick="showCars()">CAR SHOWROOM</button>
<button onclick="toggleMusic()">๐ต MUSIC ON/OFF</button>
<button onclick="settings()">โ SETTINGS</button>
<div id="garage"></div>
</div>
<div id="hud">
<h2>Speed: <span id="speed">0</span> km/h</h2>
<p>Coins: <span id="coins">5000</span></p>
<p id="mission">Mission: Drive 500 metres</p>
<button onclick="engineStart()">๐ START ENGINE</button>
<button onclick="pauseGame()">โธ PAUSE</button>
</div>
<div id="controls">
<div>
<button ontouchstart="left=true"
ontouchend="left=false"
onmousedown="left=true"
onmouseup="left=false">โฌ
LEFT</button>
<button ontouchstart="right=true"
ontouchend="right=false"
onmousedown="right=true"
onmouseup="right=false">RIGHT โก</button>
</div>
<div>
<button ontouchstart="gas=true"
ontouchend="gas=false"
onmousedown="gas=true"
onmouseup="gas=false">GAS</button>
<button ontouchstart="brake=true"
ontouchend="brake=false"
onmousedown="brake=true"
onmouseup="brake=false">BRAKE</button>
</div>
</div>
<script type="module">
import * as THREE from
'https://cdn.jsdelivr.net/npm/three@0.164.1/build/three.module.js';
let scene, camera, renderer, car;
let speed = 0;
let coins = Number(localStorage.getItem("coins") || 5000);
let distance = 0;
let left = false, right = false;
let gas = false, brake = false;
let engine = false, music = false;
let audio;
const traffic = [];
const roadLines = [];
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x87ceeb);
scene.fog = new THREE.Fog(0x87ceeb, 40, 180);
camera = new THREE.PerspectiveCamera(
70, innerWidth / innerHeight, 0.1, 500
);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 1.5));
document.body.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xffffff, 0x557744, 2));
const sun = new THREE.DirectionalLight(0xffffff, 2);
sun.position.set(10, 30, 10);
scene.add(sun);
const grass = new THREE.Mesh(
new THREE.PlaneGeometry(300, 400),
new THREE.MeshStandardMaterial({ color: 0x448844 })
);
grass.rotation.x = -Math.PI / 2;
grass.position.set(0, -0.2, -100);
scene.add(grass);
const road = new THREE.Mesh(
new THREE.PlaneGeometry(12, 400),
new THREE.MeshStandardMaterial({ color: 0x333333 })
);
road.rotation.x = -Math.PI / 2;
road.position.set(0, -0.1, -100);
scene.add(road);
for (let z = 60; z > -300; z -= 10) {
const line = new THREE.Mesh(
new THREE.BoxGeometry(0.15, 0.03, 4),
new THREE.MeshStandardMaterial({ color: 0xffffff })
);
line.position.set(0, -0.04, z);
scene.add(line);
roadLines.push(line);
}
car = makeCar(0x00ccaa);
car.position.set(0, 0, 3);
scene.add(car);
for (let i = 0; i < 6; i++) {
const trafficCar = makeCar(
[0xff3333, 0xffffff, 0x3366ff][i % 3]
);
trafficCar.position.set(
[-3, 0, 3][i % 3],
0,
-25 - i * 28
);
scene.add(trafficCar);
traffic.push(trafficCar);
}
camera.position.set(0, 5, 10);
camera.lookAt(0, 1, -5);
animate();
}
function makeCar(color) {
const group = new THREE.Group();
const body = new THREE.Mesh(
new THREE.BoxGeometry(1.8, 0.6, 3.5),
new THREE.MeshStandardMaterial({
color: color, metalness: 0.3, roughness: 0.4
})
);
body.position.y = 0.65;
group.add(body);
const cabin = new THREE.Mesh(
new THREE.BoxGeometry(1.35, 0.65, 1.6),
new THREE.MeshStandardMaterial({ color: 0x223344 })
);
cabin.position.set(0, 1.2, 0);
group.add(cabin);
for (const x of [-0.95, 0.95]) {
for (const z of [-1.1, 1.1]) {
const wheel = new THREE.Mesh(
new THREE.CylinderGeometry(0.34, 0.34, 0.25, 16),
new THREE.MeshStandardMaterial({ color: 0x111111 })
);
wheel.rotation.z = Math.PI / 2;
wheel.position.set(x, 0.35, z);
group.add(wheel);
}
}
return group;
}
function engineStart() {
if (!audio) {
audio = new (
window.AudioContext || window.webkitAudioContext
)();
}
audio.resume();
engine = !engine;
if (engine) {
playTone(90, 0.4);
setTimeout(() => playTone(150, 0.4), 250);
document.querySelector(
'#hud button'
).textContent = "โป ENGINE ON";
} else {
speed = 0;
}
}
function playTone(freq, duration) {
if (!audio) return;
const osc = audio.createOscillator();
const gain = audio.createGain();
osc.type = "sawtooth";
osc.frequency.value = freq;
gain.gain.value = 0.06;
osc.connect(gain);
gain.connect(audio.destination);
osc.start();
gain.gain.exponentialRampToValueAtTime(
0.001, audio.currentTime + duration
);
osc.stop(audio.currentTime + duration);
}
function toggleMusic() {
music = !music;
alert(music ? "Music enabled" : "Music disabled");
}
function showCars() {
document.getElementById("garage").innerHTML = `
<h3>CAR SHOWROOM</h3>
<button onclick="buyCar(2500)">Sport Sedan - 2500 coins</button>
<button onclick="buyCar(4000)">SUV - 4000 coins</button>
<button onclick="buyCar(7000)">Sports Car - 7000 coins</button>
<button onclick="document.getElementById('garage').innerHTML=''">
CLOSE
</button>
`;
}
window.buyCar = function(price) {
if (coins >= price) {
coins -= price;
localStorage.setItem("coins", coins);
document.getElementById("coins").textContent = coins;
alert("Car purchased! Coins deducted.");
} else {
alert("Not enough coins!");
}
};
function settings() {
const volume = prompt("Enter volume from 0 to 100", "60");
if (volume !== null) {
alert("Volume preference: " + volume + "%");
}
}
function startGame() {
document.getElementById("menu").style.display = "none";
}
function pauseGame() {
alert("Game paused. Press OK to resume.");
}
function animate() {
requestAnimationFrame(animate);
if (document.getElementById("menu").style.display === "none") {
const dt = 0.016;
if (engine && gas) speed += 18 * dt;
else speed -= 5 * dt;
if (brake) speed -= 22 * dt;
speed = Math.max(0, Math.min(speed, 180));
if (left) car.position.x -= 0.08;
if (right) car.position.x += 0.08;
car.position.x = Math.max(-4.5, Math.min(4.5, car.position.x));
const movement = speed * dt * 0.12;
distance += movement;
roadLines.forEach(line => {
line.position.z += movement;
if (line.position.z > 12) line.position.z -= 360;
});
traffic.forEach(t => {
t.position.z += movement - 0.12;
if (t.position.z > 12) {
t.position.z = -150 - Math.random() * 80;
t.position.x = [-3, 0, 3][Math.floor(Math.random() * 3)];
}
if (
Math.abs(t.position.z - car.position.z) < 2 &&
Math.abs(t.position.x - car.position.x) < 1.5
) {
speed *= 0.97;
}
});
camera.position.x +=
(car.position.x * 0.5 - camera.position.x) * 0.08;
camera.lookAt(car.position.x * 0.4, 0.8, -5);
document.getElementById("speed").textContent =
Math.round(speed);
document.getElementById("coins").textContent = coins;
if (distance >= 500) {
distance = 0;
coins += 600;
localStorage.setItem("coins", coins);
alert("Mission complete! +600 coins");
}
if (audio && engine) {
// Simplified engine RPM tone
}
}
renderer.render(scene, camera);
}
window.addEventListener("resize", () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});
init();
</script>
</body>
</html>