<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cyberpunk Hover Car Game</title>
<style>
body { margin: 0; overflow: hidden; }
#speedometer, #miniMap, #mission { position: absolute; color: white; font-family: Arial, sans-serif; }
#speedometer { top: 20px; left: 20px; font-size: 20px; }
#miniMap { bottom: 20px; left: 20px; background: rgba(0, 0, 0, 0.5); padding: 10px; }
#mission { top: 20px; right: 20px; font-size: 16px; background: rgba(0, 0, 0, 0.5); padding: 10px; }
</style>
<script type="module">
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.155.0/build/three.module.js';
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three@0.155.0/examples/jsm/controls/OrbitControls.js';
// Scene Setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Lighting
const ambientLight = new THREE.AmbientLight(0x3333ff, 1.5);
scene.add(ambientLight);
const neonLight = new THREE.PointLight(0x00ffff, 3, 100);
neonLight.position.set(0, 20, 0);
scene.add(neonLight);
// UI Elements
const speedometer = document.createElement("div");
speedometer.id = "speedometer";
document.body.appendChild(speedometer);
const miniMap = document.createElement("div");
miniMap.id = "miniMap";
miniMap.innerText = "Mini-Map (Coming Soon)";
document.body.appendChild(miniMap);
const mission = document.createElement("div");
mission.id = "mission";
mission.innerText = "Mission: Explore the Cyber City";
document.body.appendChild(mission);
// Load CyberCity
const loader = new GLTFLoader();
let city;
loader.load('cybercity_2099_v2.glb', (gltf) => {
city = gltf.scene;
city.scale.set(10, 10, 10);
city.position.set(0, -5, 0);
scene.add(city);
});
// Load Hover Car
let car;
loader.load('lotus_esprit_hover_gt_2076.glb', (gltf) => {
car = gltf.scene;
car.scale.set(1, 1, 1);
car.position.set(0, 2, 0);
scene.add(car);
});
// Movement & Collision Detection
const keys = { w: false, s: false, a: false, d: false, space: false, shift: false };
document.addEventListener('keydown', (e) => { if (keys[e.key] !== undefined) keys[e.key] = true; });
document.addEventListener('keyup', (e) => { if (keys[e.key] !== undefined) keys[e.key] = false; });
let speed = 0.3;
function moveCar() {
if (!car) return;
let currentSpeed = speed;
if (keys.shift) currentSpeed *= 2; // Boost Mode
if (keys.w) car.position.z -= currentSpeed;
if (keys.s) car.position.z += currentSpeed;
if (keys.a) car.position.x -= currentSpeed;
if (keys.d) car.position.x += currentSpeed;
if (keys.space) car.position.y += currentSpeed * 0.8;
if (keys.shift) car.position.y -= currentSpeed * 0.8;
car.rotation.y = Math.atan2(-car.position.x, -car.position.z);
// Collision Detection (basic bounding box)
if (city) {
const carBox = new THREE.Box3().setFromObject(car);
const cityBox = new THREE.Box3().setFromObject(city);
if (carBox.intersectsBox(cityBox)) {
car.position.z += 1; // Prevent passing through buildings
}
}
// Update UI
speedometer.innerText = `Speed: ${Math.round(currentSpeed * 10)} km/h`;
}
// Camera Follow Mode
function followCar() {
if (!car) return;
const targetPosition = new THREE.Vector3(car.position.x, car.position.y + 2, car.position.z + 10);
camera.position.lerp(targetPosition, 0.1);
camera.lookAt(car.position);
}
// AI Traffic
const traffic = [];
function spawnAIHoverCar(position) {
loader.load('lotus_esprit_hover_gt_2076.glb', (gltf) => {
const aiCar = gltf.scene.clone();
aiCar.scale.set(1, 1, 1);
aiCar.position.copy(position);
scene.add(aiCar);
traffic.push({ object: aiCar, speed: Math.random() * 0.05 + 0.02 });
});
}
for (let i = 0; i < 5; i++) {
spawnAIHoverCar(new THREE.Vector3(Math.random() * 40 - 20, 2, Math.random() * 40 - 20));
}
function moveTraffic() {
for (const ai of traffic) {
ai.object.position.z += ai.speed;
if (ai.object.position.z > 20) ai.object.position.z = -20;
}
}
// Animate Scene
function animate() {
requestAnimationFrame(animate);
moveCar();
moveTraffic();
followCar();
renderer.render(scene, camera);
}
animate();
// Responsive Resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</head>
<body>
</body>
</html>