Você pode criar um simulador de carro 3D simples c...
Criado em: 29 de maio de 2025
Criado em: 29 de maio de 2025
Você pode criar um simulador de carro 3D simples com Three.js em um único arquivo HTML? Por favor, adicione nuvens, montanhas, uma estrada, algumas árvores e um trem circulando. E também as teclas de seta e WASD para controlar o carro. Faça a câmera acompanhar o carrinho em terceira pessoa. Coloque moedas para coletar. E coloque uma iA para jogar contra. Quem coletar 10 moedas primeiro ganha. Quando uma moeda for coletada, outra deve spawnar para repor. Quando houver colisão o carro deve explodir e retornar para o ponto inicial. Informe no centro da tela quando a iA coletar uma moeda. A tecla Espaço deve iniciar e reiniciar o jogo.
Abaixo segue um arquivo HTML único que já carrega o Three.js via CDN e reúne todos os elementos que você pediu.
Basta salvar como index.html
, abrir no navegador moderno e pressionar Espaço para começar / reiniciar:
html<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8" /> <title>Mini Car 3D – Three.js</title> <style> html,body{margin:0;height:100%;overflow:hidden;background:#87ceeb;font-family:sans-serif} #ui{ position:fixed;top:0;left:0;right:0;text-align:center; color:#fff;font-size:22px;text-shadow:1px 1px 3px #000;pointer-events:none } #centerMsg{font-size:28px;margin-top:8px;color:#ffe400} canvas{display:block} </style> </head> <body> <div id="ui"> <div id="score">Jogador 0 | IA 0</div> <div id="centerMsg"></div> <div style="font-size:14px;opacity:.7;margin-top:4px"> Setas / WASD = dirigir · Espaço = iniciar / reiniciar </div> </div> <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/PointerLockControls.js"></script> <script> /* ----- variáveis globais ----- */ let scene, camera, renderer, clock, keys = {}; let player, ai, coins = [], train; let playerScore = 0, aiScore = 0, playing = false; const COINS_TO_WIN = 10; const uiScore = document.getElementById('score'); const centerMsg = document.getElementById('centerMsg'); /* ---------- setup básico ---------- */ init(); animate(); function init(){ scene = new THREE.Scene(); scene.fog = new THREE.Fog(0x87ceeb, 60, 400); camera = new THREE.PerspectiveCamera(60, innerWidth/innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer({antialias:true}); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); clock = new THREE.Clock(); /* luz */ const hemi = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0); scene.add(hemi); const dir = new THREE.DirectionalLight(0xffffff, .8); dir.position.set(-30,60,-30); scene.add(dir); buildGround(); buildMountains(); buildTrees(); buildClouds(); buildRoad(); buildTrain(); buildCars(); spawnCoins(15); window.addEventListener('resize', () => { camera.aspect = innerWidth/innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); }); /* controls */ document.addEventListener('keydown', (e)=>{keys[e.code]=true; if(e.code==='Space') resetGame(); }); document.addEventListener('keyup', (e)=>{keys[e.code]=false;}); } /* ---------- construção do mundo ---------- */ function buildGround(){ const geo = new THREE.PlaneGeometry(1000,1000,1,1); const mat = new THREE.MeshLambertMaterial({color:0x4db14d}); const ground = new THREE.Mesh(geo,mat); ground.rotation.x = -Math.PI/2; scene.add(ground); } function buildMountains(){ const mtMat = new THREE.MeshLambertMaterial({color:0x888888}); for(let i=0;i<20;i++){ const h = THREE.MathUtils.randFloat(30,60); const geo = new THREE.ConeGeometry(h*0.7,h,6); const mesh = new THREE.Mesh(geo,mtMat); const r = 200 + Math.random()*200; const angle = Math.random()*Math.PI*2; mesh.position.set(Math.cos(angle)*r,h/2,Math.sin(angle)*r); mesh.rotation.y = Math.random()*Math.PI; scene.add(mesh); } } function buildTrees(){ const trunkMat = new THREE.MeshLambertMaterial({color:0x8b5a2b}); const leafMat = new THREE.MeshLambertMaterial({color:0x1f7a28}); for(let i=0;i<50;i++){ const group = new THREE.Group(); const trunk = new THREE.Mesh(new THREE.CylinderGeometry(.7,.7,6,6),trunkMat); trunk.position.y = 3; const leaves = new THREE.Mesh(new THREE.ConeGeometry(2.5,6,8),leafMat); leaves.position.y = 8; group.add(trunk,leaves); const r = 140 + Math.random()*160; const angle = Math.random()*Math.PI*2; group.position.set(Math.cos(angle)*r,0,Math.sin(angle)*r); scene.add(group); } } function buildClouds(){ const cloudMat = new THREE.MeshLambertMaterial({color:0xffffff}); for(let i=0;i<25;i++){ const parts = new THREE.Group(); const base = new THREE.Mesh(new THREE.SphereGeometry(4,8,6),cloudMat); parts.add(base); for(let j=0;j<2;j++){ const puff = new THREE.Mesh(new THREE.SphereGeometry(3,8,6),cloudMat); puff.position.set(THREE.MathUtils.randFloatSpread(5),THREE.MathUtils.randFloatSpread(2),THREE.MathUtils.randFloatSpread(2)); parts.add(puff); } parts.position.set(THREE.MathUtils.randFloatSpread(400), 60+Math.random()*40, THREE.MathUtils.randFloatSpread(400)); scene.add(parts); } } function buildRoad(){ const roadMat = new THREE.MeshLambertMaterial({color:0x333333}); const road = new THREE.Mesh(new THREE.PlaneGeometry(600,12),roadMat); road.rotation.x = -Math.PI/2; scene.add(road); } function buildTrain(){ const railMat = new THREE.MeshLambertMaterial({color:0x554433}); const track = new THREE.TorusGeometry(80,0.4,8,100); scene.add(new THREE.Mesh(track,railMat)); train = new THREE.Group(); const carGeo = new THREE.BoxGeometry(6,4,4); const carMat = new THREE.MeshLambertMaterial({color:0xff0000}); for(let i=0;i<3;i++){ const wagon = new THREE.Mesh(carGeo,carMat); wagon.position.x = i*7; train.add(wagon); } train.position.y = 2; scene.add(train); } /* ---------- carros ---------- */ function buildCars(){ const carGeo = new THREE.BoxGeometry(4,2,2.5); const carMatP = new THREE.MeshLambertMaterial({color:0x2196f3}); const carMatAI= new THREE.MeshLambertMaterial({color:0xffc107}); player = new THREE.Mesh(carGeo,carMatP); ai = new THREE.Mesh(carGeo,carMatAI); resetCar(player,true); resetCar(ai,false); scene.add(player,ai); } function resetCar(car,isPlayer){ car.position.set(isPlayer? -20:20 ,1.1,0); car.rotation.set(0,isPlayer?0:Math.PI,0); car.userData.vel = new THREE.Vector3(); car.visible = true; } /* ---------- moedas ---------- */ function spawnCoins(n){ const coinGeo = new THREE.CylinderGeometry(1,1,0.4,16); const coinMat = new THREE.MeshLambertMaterial({color:0xffd700,emissive:0x604000}); for(let i=0;i<n;i++){ const coin = new THREE.Mesh(coinGeo,coinMat); coin.rotation.x = Math.PI/2; repositionCoin(coin); scene.add(coin); coins.push(coin); } } function repositionCoin(coin){ coin.position.set(THREE.MathUtils.randFloat(-280,280),1.5,THREE.MathUtils.randFloat(-40,40)); } /* ---------- lógica principal ---------- */ function resetGame(){ playerScore = aiScore = 0; updateScore(); resetCar(player,true); resetCar(ai,false); coins.forEach(repositionCoin); centerMsg.textContent = ''; playing = true; } function updateScore(){ uiScore.textContent = `Jogador ${playerScore} | IA ${aiScore}`; } function animate(){ requestAnimationFrame(animate); const dt = clock.getDelta(); if(playing){ updatePlayer(dt); updateAI(dt); updateTrain(dt); checkCoinCollisions(); checkCarCollision(); if(playerScore>=COINS_TO_WIN || aiScore>=COINS_TO_WIN){ playing = false; centerMsg.textContent = playerScore>aiScore? 'Você venceu!':'A IA venceu!'; } } /* câmera em terceira pessoa */ const camOffset = new THREE.Vector3(0,6,-10).applyQuaternion(player.quaternion); camera.position.copy(player.position).add(camOffset); camera.lookAt(player.position); renderer.render(scene,camera); } /* ---------------- updates ---------------- */ function updatePlayer(dt){ const acc = 25, maxSpd = 30, turn = 2.2; const vel = player.userData.vel; /* aceleração frontal/traseira */ const forward = (keys['KeyW']||keys['ArrowUp']) ? 1 : (keys['KeyS']||keys['ArrowDown']) ? -1 : 0; if(forward!==0){ vel.z = THREE.MathUtils.clamp(vel.z - forward*acc*dt, -maxSpd, maxSpd); }else{ vel.z *= 0.94; // arrasto } /* rotação */ if(keys['KeyA']||keys['ArrowLeft']) player.rotation.y += turn*dt; if(keys['KeyD']||keys['ArrowRight']) player.rotation.y -= turn*dt; /* aplicar movimento */ const dir = new THREE.Vector3(0,0,vel.z*dt).applyEuler(player.rotation); player.position.add(dir); } function updateAI(dt){ /* estratégia simples: sempre dirigir para a moeda mais próxima */ let target = null, bestDist = 1e9; coins.forEach(c=>{ const d = c.position.distanceTo(ai.position); if(d<bestDist){bestDist=d;target=c;} }); if(!target) return; const desiredDir = target.position.clone().sub(ai.position).normalize(); const forward = new THREE.Vector3(0,0,-1).applyEuler(ai.rotation); const turn = forward.clone().cross(desiredDir).y; ai.rotation.y -= THREE.MathUtils.clamp(turn,-1,1)*1.8*dt; ai.userData.vel = ai.userData.vel || new THREE.Vector3(); ai.userData.vel.z = -20; // velocidade constante const move = new THREE.Vector3(0,0,ai.userData.vel.z*dt).applyEuler(ai.rotation); ai.position.add(move); } function updateTrain(dt){ train.userData.t = (train.userData.t||0) + dt*0.25; const ang = train.userData.t*Math.PI*2; train.position.set(Math.cos(ang)*80,2,Math.sin(ang)*80); train.rotation.y = -ang; } function checkCoinCollisions(){ coins.forEach(c=>{ if(c.position.distanceTo(player.position)<3){ playerScore++; updateScore(); repositionCoin(c); }else if(c.position.distanceTo(ai.position)<3){ aiScore++; updateScore(); centerMsg.textContent = `IA coletou uma moeda!`; setTimeout(()=>{centerMsg.textContent='';},800); repositionCoin(c); } }); } function checkCarCollision(){ if(player.position.distanceTo(ai.position)<3){ explode(player); explode(ai); setTimeout(()=>{ resetCar(player,true); resetCar(ai,false); },1500); } } function explode(car){ car.visible=false; const boom = new THREE.Mesh(new THREE.SphereGeometry(5,8,6),new THREE.MeshBasicMaterial({color:0xff3300})); boom.position.copy(car.position); scene.add(boom); setTimeout(()=>scene.remove(boom),800); } </script> </body> </html>
O código é propositalmente enxuto para caber em um único arquivo, mas serve como base: você pode trocar geometrias por modelos GLTF, adicionar partículas de explosão, melhorar inteligência da IA, HUD, sons etc. Divirta-se! 🎮