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, maximum-scale=1.0, user-scalable=no">
<title>GTA VI • 3D Mobile</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<style>
body { margin:0; padding:0; overflow:hidden; background:#000; touch-action:none; font-family:system-ui; }
#container { position:relative; width:100vw; height:100vh; }
canvas { display:block; }
#titleScreen {
position:absolute; top:0; left:0; width:100%; height:100%; background:linear-gradient(#111, #000);
display:flex; align-items:center; justify-content:center; flex-direction:column; z-index:1000;
color:#0ff; text-align:center; transition: opacity 1.2s;
}
#title {
font-size:92px; font-weight:900; letter-spacing:8px;
text-shadow:
0 0 20px #0ff,
0 0 40px #0ff,
0 0 80px #f0f,
0 0 120px #f0f;
animation: neonPulse 1.5s infinite alternate;
}
#subtitle { font-size:28px; margin:10px 0 60px; color:#ff0; text-shadow:0 0 30px #ff0; }
#startBtn {
padding:18px 60px; font-size:28px; background:rgba(255,255,255,0.1);
border:6px solid #0f0; color:#0f0; border-radius:12px;
box-shadow:0 0 40px #0f0; cursor:pointer;
}
@keyframes neonPulse { from { text-shadow:0 0 20px #0ff; } to { text-shadow:0 0 80px #f0f; } }
#hud {
position:absolute; top:15px; left:15px; color:#0f0; font-size:18px; z-index:100;
text-shadow:2px 2px 6px #000;
}
.btn {
position:absolute; bottom:35px; width:88px; height:88px; border-radius:50%;
display:flex; align-items:center; justify-content:center; font-size:36px;
border:6px solid; background:rgba(0,0,0,0.5); z-index:200;
}
#shootBtn { left:35px; border-color:#f33; color:#f33; }
#enterBtn { right:35px; border-color:#0f0; color:#0f0; }
#wasted {
position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
font-size:110px; color:#f00; font-weight:900; display:none; z-index:300;
text-shadow:0 0 60px #f00;
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
<div id="titleScreen">
<div id="title">GTA VI</div>
<div id="subtitle">VICE CITY 2026</div>
<div id="startBtn">TAP TO START</div>
</div>
<div id="hud">
<div style="font-size:34px;color:#ff0;margin-bottom:8px;">GTA VI</div>
<div id="money">$1250</div>
<div id="wanted">WANTED: ★☆☆☆☆</div>
<div id="time">12:00</div>
</div>
<div id="shootBtn" class="btn">🔫</div>
<div id="enterBtn" class="btn">🚗</div>
<div id="wasted">WASTED</div>
</div>
<script>
let scene, camera, renderer;
let car, player, currentTarget;
let inCar = true;
let bullets = [];
let peds = [];
let pickups = [];
let police = null;
let buildings = [];
let money = 1250;
let wantedLevel = 0;
let gameTime = 720;
let gameOver = false;
let lastShot = 0;
// Touch controls
let moveTouch = null;
let movePower = 0;
let moveAngle = 0;
let shooting = false;
const WORLD_SIZE = 3000;
function createTitle() {
const title = document.getElementById('titleScreen');
title.addEventListener('touchstart', () => {
title.style.opacity = '0';
setTimeout(() => {
title.style.display = 'none';
initGame();
}, 1200);
});
}
function initGame() {
const canvas = document.getElementById('canvas');
renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x111111, 800, 2800);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 4000);
// Lights
const ambient = new THREE.AmbientLight(0x404040);
scene.add(ambient);
const sun = new THREE.DirectionalLight(0xffddaa, 1.2);
sun.position.set(200, 400, 300);
sun.castShadow = true;
scene.add(sun);
// Ground
const groundGeo = new THREE.PlaneGeometry(WORLD_SIZE*2, WORLD_SIZE*2);
const groundMat = new THREE.MeshLambertMaterial({ color: 0x113300 });
const ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// Roads
const roadMat = new THREE.MeshLambertMaterial({ color: 0x222222 });
const road1 = new THREE.Mesh(new THREE.PlaneGeometry(WORLD_SIZE*2, 280), roadMat);
road1.rotation.x = -Math.PI / 2;
road1.position.y = 0.1;
road1.position.z = 800;
scene.add(road1);
const road2 = road1.clone();
road2.position.z = -800;
scene.add(road2);
const road3 = new THREE.Mesh(new THREE.PlaneGeometry(280, WORLD_SIZE*2), roadMat);
road3.rotation.x = -Math.PI / 2;
road3.position.y = 0.1;
road3.position.x = 900;
scene.add(road3);
// Buildings
const buildingMat = new THREE.MeshLambertMaterial({ color: 0x555555 });
for (let i = 0; i < 18; i++) {
const w = 80 + Math.random() * 160;
const h = 120 + Math.random() * 380;
const d = 80 + Math.random() * 160;
const b = new THREE.Mesh(new THREE.BoxGeometry(w, h, d), buildingMat);
b.position.x = (Math.random() - 0.5) * WORLD_SIZE * 1.6;
b.position.z = (Math.random() - 0.5) * WORLD_SIZE * 1.6;
b.position.y = h / 2;
b.castShadow = true;
b.receiveShadow = true;
scene.add(b);
buildings.push(b);
}
// Car
car = new THREE.Group();
const bodyGeo = new THREE.BoxGeometry(5.2, 2.2, 2.6);
const bodyMat = new THREE.MeshLambertMaterial({ color: 0xff2222 });
const body = new THREE.Mesh(bodyGeo, bodyMat);
body.position.y = 1.4;
body.castShadow = true;
car.add(body);
const roof = new THREE.Mesh(new THREE.BoxGeometry(3.2, 1.4, 2.2), new THREE.MeshLambertMaterial({ color: 0x111111 }));
roof.position.set(0, 2.6, 0);
car.add(roof);
// Wheels
const wheelGeo = new THREE.CylinderGeometry(0.7, 0.7, 0.6, 32);
const wheelMat = new THREE.MeshLambertMaterial({ color: 0x111111 });
const positions = [[-2, 1, 1.4], [2, 1, 1.4], [-2, 1, -1.4], [2, 1, -1.4]];
positions.forEach(p => {
const w = new THREE.Mesh(wheelGeo, wheelMat);
w.rotation.z = Math.PI / 2;
w.position.set(p[0], p[1], p[2]);
car.add(w);
});
car.position.set(200, 0, 200);
car.castShadow = true;
scene.add(car);
// Player (on foot)
player = new THREE.Group();
const torso = new THREE.Mesh(new THREE.BoxGeometry(1.2, 2.2, 0.8), new THREE.MeshLambertMaterial({ color: 0x0066ff }));
torso.position.y = 2;
player.add(torso);
const head = new THREE.Mesh(new THREE.SphereGeometry(0.7, 32, 32), new THREE.MeshLambertMaterial({ color: 0xffddaa }));
head.position.y = 3.6;
player.add(head);
player.position.set(180, 0, 220);
scene.add(player);
currentTarget = car;
// Spawn some peds
for (let i = 0; i < 12; i++) {
const ped = new THREE.Mesh(new THREE.BoxGeometry(1.2, 2.4, 1), new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff }));
ped.position.set((Math.random()-0.5)*WORLD_SIZE, 1.2, (Math.random()-0.5)*WORLD_SIZE);
ped.userData = { vx: (Math.random()-0.5)*0.8, vz: (Math.random()-0.5)*0.8 };
scene.add(ped);
peds.push(ped);
}
// Pickups
for (let i = 0; i < 6; i++) {
const p = new THREE.Mesh(new THREE.BoxGeometry(1.5, 1.5, 1.5), new THREE.MeshLambertMaterial({ color: 0xffff00 }));
p.position.set((Math.random()-0.5)*WORLD_SIZE*1.4, 3, (Math.random()-0.5)*WORLD_SIZE*1.4);
p.userData = { bob: 0 };
scene.add(p);
pickups.push(p);
}
// Touch controls
setupControls();
animate();
setInterval(updateHUD, 200);
}
function setupControls() {
const container = document.getElementById('container');
container.addEventListener('touchstart', e => {
for (let t of e.changedTouches) {
const x = t.clientX / window.innerWidth;
if (x < 0.45 && !moveTouch) moveTouch = t.identifier;
else if (x > 0.55) shooting = true;
}
});
container.addEventListener('touchmove', e => {
e.preventDefault();
for (let t of e.touches) {
if (t.identifier === moveTouch) {
const centerX = window.innerWidth * 0.22;
const centerY = window.innerHeight * 0.75;
const dx = (t.clientX - centerX) / 130;
const dy = (t.clientY - centerY) / 130;
movePower = Math.min(1, Math.hypot(dx, dy));
moveAngle = Math.atan2(dy, dx);
}
}
});
container.addEventListener('touchend', e => {
for (let t of e.changedTouches) {
if (t.identifier === moveTouch) { moveTouch = null; movePower = 0; }
if (shooting) shooting = false;
}
});
// Buttons
document.getElementById('shootBtn').addEventListener('touchstart', () => shooting = true);
document.getElementById('shootBtn').addEventListener('touchend', () => shooting = false);
document.getElementById('enterBtn').addEventListener('touchstart', () => {
if (Math.hypot(car.position.x - player.position.x, car.position.z - player.position.z) < 12) {
inCar = !inCar;
currentTarget = inCar ? car : player;
}
});
}
function updateHUD() {
if (gameOver) return;
document.getElementById('money').textContent = '$' + money;
let stars = '★'.repeat(Math.min(5, wantedLevel)) + '☆'.repeat(5 - Math.min(5, wantedLevel));
document.getElementById('wanted').innerHTML = `WANTED: ${stars}`;
const h = Math.floor(gameTime / 60);
const m = Math.floor(gameTime % 60);
document.getElementById('time').textContent = `\( {h}: \){m<10?'0':''}${m}`;
}
function updateMovement(delta) {
if (!currentTarget) return;
if (inCar) {
// Car physics
const accel = movePower * 38 * (moveAngle > -1 && moveAngle < 1 ? 1 : -0.6);
car.userData.speed = (car.userData.speed || 0) * 0.92 + accel * delta * 18;
car.userData.speed = Math.max(Math.min(car.userData.speed, 42), -18);
const turn = movePower * (moveAngle > 1.4 || moveAngle < -1.4 ? 1 : -1) * 2.2;
car.rotation.y += turn * delta * (car.userData.speed / 20);
const dx = Math.sin(car.rotation.y) * car.userData.speed * delta * 3;
const dz = Math.cos(car.rotation.y) * car.userData.speed * delta * 3;
car.position.x += dx;
car.position.z += dz;
// Simple building collision
for (let b of buildings) {
if (Math.abs(car.position.x - b.position.x) < 8 && Math.abs(car.position.z - b.position.z) < 8) {
car.position.x -= dx * 1.8;
car.position.z -= dz * 1.8;
car.userData.speed *= -0.4;
}
}
} else {
// On foot
const speed = movePower * 18;
const dx = Math.sin(moveAngle) * speed * delta;
const dz = Math.cos(moveAngle) * speed * delta;
player.position.x += dx;
player.position.z += dz;
player.rotation.y = moveAngle + Math.PI;
}
// Clamp world
currentTarget.position.x = Math.max(-WORLD_SIZE*0.9, Math.min(WORLD_SIZE*0.9, currentTarget.position.x));
currentTarget.position.z = Math.max(-WORLD_SIZE*0.9, Math.min(WORLD_SIZE*0.9, currentTarget.position.z));
}
function updateCamera() {
const targetPos = currentTarget.position;
const offsetDistance = inCar ? 22 : 14;
const height = inCar ? 12 : 9;
const idealOffset = new THREE.Vector3(
-Math.sin(currentTarget.rotation.y) * offsetDistance,
height,
-Math.cos(currentTarget.rotation.y) * offsetDistance
);
camera.position.lerp(targetPos.clone().add(idealOffset), 0.12);
camera.lookAt(targetPos.x, targetPos.y + 4, targetPos.z);
}
function shoot() {
const now = Date.now();
if (now - lastShot < 180) return;
lastShot = now;
const pos = currentTarget.position.clone();
const dir = new THREE.Vector3(
-Math.sin(currentTarget.rotation.y),
0,
-Math.cos(currentTarget.rotation.y)
);
const bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.4, 8, 8),
new THREE.MeshBasicMaterial({ color: 0xffff00 })
);
bullet.position.copy(pos).add(new THREE.Vector3(0, 4, 0));
bullet.userData = { velocity: dir.multiplyScalar(120), life: 60 };
scene.add(bullet);
bullets.push(bullet);
}
function animate() {
requestAnimationFrame(animate);
if (gameOver) return;
const delta = 0.016;
gameTime += delta;
updateMovement(delta);
// Auto shoot when holding
if (shooting) shoot();
// Update bullets
for (let i = bullets.length - 1; i >= 0; i--) {
const b = bullets[i];
b.position.add(b.userData.velocity.clone().multiplyScalar(delta));
b.userData.life--;
if (b.userData.life <= 0) {
scene.remove(b);
bullets.splice(i, 1);
}
}
// Simple peds movement
peds.forEach(p => {
p.position.x += p.userData.vx;
p.position.z += p.userData.vz;
if (Math.random() < 0.03) {
p.userData.vx = (Math.random() - 0.5) * 1.6;
p.userData.vz = (Math.random() - 0.5) * 1.6;
}
});
// Pickups bob
pickups.forEach(p => {
p.userData.bob += 0.1;
p.position.y = 3 + Math.sin(p.userData.bob) * 1.2;
});
updateCamera();
renderer.render(scene, camera);
}
// Start
window.onload = () => {
createTitle();
};
// Resize
window.addEventListener('resize', () => {
if (camera && renderer) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
});
</script>
</body>
</html>2
2
139KB
619KB
296.0ms
384.0ms
296.0ms