Spaces:
Running
Running
<html> | |
<head> | |
<title>3D Tile Driving Game</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.4.2/aframe.min.js"></script> | |
</head> | |
<body> | |
<a-scene> | |
<!-- Assets --> | |
<a-assets> | |
<img id="ground-tile" src="/api/placeholder/128/128" /> | |
<img id="bump-map" src="/api/placeholder/128/128" /> | |
<!-- Custom SVG shapes --> | |
<svg id="crystal" viewBox="0 0 100 100"> | |
<path d="M50 0 L100 25 L100 75 L50 100 L0 75 L0 25 Z" fill="#88ff88"/> | |
</svg> | |
<svg id="starShape" viewBox="0 0 100 100"> | |
<path d="M50 0 L63 38 L100 38 L69 59 L81 100 L50 75 L19 100 L31 59 L0 38 L37 38 Z" fill="#ffff00"/> | |
</svg> | |
<svg id="pyramid" viewBox="0 0 100 100"> | |
<path d="M50 0 L100 100 L0 100 Z" fill="#ff88ff"/> | |
</svg> | |
</a-assets> | |
<!-- Environment --> | |
<a-sky color="#001133"></a-sky> | |
<a-entity id="tileMap"></a-entity> | |
<!-- Decorative 3D Shapes --> | |
<a-entity id="decorativeShapes"></a-entity> | |
<!-- Player Character --> | |
<a-entity id="player" position="2 0 2"> | |
<!-- Player body --> | |
<a-sphere radius="0.3" color="#44aaff"></a-sphere> | |
<!-- Player head --> | |
<a-sphere radius="0.2" position="0 0.4 0" color="#4488ff"></a-sphere> | |
<!-- Arms --> | |
<a-cylinder radius="0.08" height="0.5" position="0.3 0.1 0" rotation="0 0 90" color="#4488ff"></a-cylinder> | |
<a-cylinder radius="0.08" height="0.5" position="-0.3 0.1 0" rotation="0 0 90" color="#4488ff"></a-cylinder> | |
</a-entity> | |
<!-- Car --> | |
<a-entity id="car" position="0 0.5 0"> | |
<!-- Car body with gradient color --> | |
<a-box width="2" height="0.75" depth="4" color="#ff3333" metalness="0.8" roughness="0.2" shadow></a-box> | |
<!-- Car roof --> | |
<a-box width="1.5" height="0.75" depth="2" position="0 0.75 -0.5" color="#cc2222" metalness="0.8" roughness="0.2" shadow></a-box> | |
<!-- Wheels with chrome effect --> | |
<a-cylinder radius="0.4" height="0.3" rotation="0 0 90" position="1 -0.3 1" color="#333333" metalness="0.9" roughness="0.1"></a-cylinder> | |
<a-cylinder radius="0.4" height="0.3" rotation="0 0 90" position="-1 -0.3 1" color="#333333" metalness="0.9" roughness="0.1"></a-cylinder> | |
<a-cylinder radius="0.4" height="0.3" rotation="0 0 90" position="1 -0.3 -1" color="#333333" metalness="0.9" roughness="0.1"></a-cylinder> | |
<a-cylinder radius="0.4" height="0.3" rotation="0 0 90" position="-1 -0.3 -1" color="#333333" metalness="0.9" roughness="0.1"></a-cylinder> | |
<!-- Headlights --> | |
<a-sphere radius="0.2" position="0.8 0 1.8" color="#ffff88" emission="intensity: 0.5"></a-sphere> | |
<a-sphere radius="0.2" position="-0.8 0 1.8" color="#ffff88" emission="intensity: 0.5"></a-sphere> | |
</a-entity> | |
<!-- Camera --> | |
<a-entity id="rig" position="0 2 8"> | |
<a-camera look-controls wasd-controls="enabled: false"></a-camera> | |
</a-entity> | |
<!-- Lighting --> | |
<a-light type="ambient" color="#445566"></a-light> | |
<a-light type="directional" position="2 4 1" color="#ffffff" intensity="0.8" cast-shadow="true"></a-light> | |
</a-scene> | |
<script> | |
// Car physics parameters | |
const carState = { | |
position: { x: 0, z: 0 }, | |
rotation: 0, | |
velocity: 0, | |
acceleration: 0, | |
maxSpeed: 0.2, | |
turnSpeed: 2, | |
friction: 0.98 | |
}; | |
// Player state | |
const playerState = { | |
position: { x: 2, y: 0, z: 2 }, | |
velocity: { x: 0, y: 0, z: 0 }, | |
speed: 0.1, | |
jumpForce: 0.2, | |
isJumping: false | |
}; | |
// Generate tile map with varying colors | |
const tileMap = document.querySelector('#tileMap'); | |
const mapSize = 20; | |
const tileSize = 5; | |
const colors = ['#2244aa', '#22aa44', '#aa2244', '#aaaa22']; | |
for (let x = 0; x < mapSize; x++) { | |
for (let z = 0; z < mapSize; z++) { | |
const tile = document.createElement('a-box'); | |
tile.setAttribute('width', tileSize); | |
tile.setAttribute('height', 0.1); | |
tile.setAttribute('depth', tileSize); | |
tile.setAttribute('position', { | |
x: x * tileSize - (mapSize * tileSize) / 2, | |
y: -0.05, | |
z: z * tileSize - (mapSize * tileSize) / 2 | |
}); | |
tile.setAttribute('material', { | |
color: colors[(x + z) % colors.length], | |
src: '#ground-tile', | |
repeat: { x: 1, y: 1 }, | |
normalMap: '#bump-map' | |
}); | |
tile.setAttribute('shadow', ''); | |
tileMap.appendChild(tile); | |
} | |
} | |
// Generate decorative shapes | |
const shapes = document.querySelector('#decorativeShapes'); | |
const numShapes = 30; | |
for (let i = 0; i < numShapes; i++) { | |
const shape = document.createElement('a-entity'); | |
const type = Math.floor(Math.random() * 3); | |
const scale = 2 + Math.random() * 3; | |
const x = (Math.random() - 0.5) * mapSize * tileSize; | |
const z = (Math.random() - 0.5) * mapSize * tileSize; | |
const rotY = Math.random() * 360; | |
shape.setAttribute('position', `${x} ${scale/2} ${z}`); | |
shape.setAttribute('rotation', `0 ${rotY} 0`); | |
shape.setAttribute('scale', `${scale} ${scale} ${scale}`); | |
switch(type) { | |
case 0: | |
shape.setAttribute('geometry', 'primitive: cylinder; radius: 0.5; height: 1;'); | |
shape.setAttribute('material', 'color: #ff88ff; metalness: 0.5; roughness: 0.2'); | |
break; | |
case 1: | |
shape.setAttribute('geometry', 'primitive: box; width: 1; height: 1; depth: 1;'); | |
shape.setAttribute('material', 'color: #88ffff; metalness: 0.5; roughness: 0.2'); | |
break; | |
case 2: | |
shape.setAttribute('geometry', 'primitive: cone; radiusBottom: 0.7; radiusTop: 0;'); | |
shape.setAttribute('material', 'color: #ffff88; metalness: 0.5; roughness: 0.2'); | |
break; | |
} | |
shapes.appendChild(shape); | |
} | |
// Controls | |
const car = document.querySelector('#car'); | |
const player = document.querySelector('#player'); | |
const camera = document.querySelector('#rig'); | |
let keys = {}; | |
document.addEventListener('keydown', (e) => { | |
keys[e.key.toLowerCase()] = true; | |
}); | |
document.addEventListener('keyup', (e) => { | |
keys[e.key.toLowerCase()] = false; | |
}); | |
// Game loop | |
function updateGame() { | |
// Car controls | |
if (keys['w']) { | |
carState.acceleration = 0.001; | |
} else if (keys['s']) { | |
carState.acceleration = 0; | |
carState.velocity *= 0.9; | |
} else if (keys['x']) { | |
carState.acceleration = -0.001; | |
} else { | |
carState.acceleration = 0; | |
} | |
if (keys['a']) { | |
carState.rotation += carState.turnSpeed * Math.abs(carState.velocity); | |
} | |
if (keys['d']) { | |
carState.rotation -= carState.turnSpeed * Math.abs(carState.velocity); | |
} | |
// Player controls (IJKL + Space) | |
if (keys['i']) { | |
playerState.position.z -= playerState.speed; | |
} | |
if (keys['k']) { | |
playerState.position.z += playerState.speed; | |
} | |
if (keys['j']) { | |
playerState.position.x -= playerState.speed; | |
} | |
if (keys['l']) { | |
playerState.position.x += playerState.speed; | |
} | |
if (keys[' '] && !playerState.isJumping) { | |
playerState.velocity.y = playerState.jumpForce; | |
playerState.isJumping = true; | |
} | |
// Player physics | |
playerState.velocity.y -= 0.01; // Gravity | |
playerState.position.y += playerState.velocity.y; | |
// Ground collision | |
if (playerState.position.y < 0) { | |
playerState.position.y = 0; | |
playerState.velocity.y = 0; | |
playerState.isJumping = false; | |
} | |
// Update car physics | |
carState.velocity += carState.acceleration; | |
carState.velocity *= carState.friction; | |
carState.velocity = Math.max(Math.min(carState.velocity, carState.maxSpeed), -carState.maxSpeed); | |
const rad = (carState.rotation * Math.PI) / 180; | |
carState.position.x += Math.sin(rad) * carState.velocity; | |
carState.position.z += Math.cos(rad) * carState.velocity; | |
// Update positions | |
car.setAttribute('position', { | |
x: carState.position.x, | |
y: 0.5, | |
z: carState.position.z | |
}); | |
car.setAttribute('rotation', { | |
x: 0, | |
y: carState.rotation, | |
z: 0 | |
}); | |
player.setAttribute('position', { | |
x: playerState.position.x, | |
y: playerState.position.y + 0.5, | |
z: playerState.position.z | |
}); | |
// Camera follows car | |
const cameraDistance = 8; | |
const cameraHeight = 2; | |
camera.setAttribute('position', { | |
x: carState.position.x - Math.sin(rad) * cameraDistance, | |
y: cameraHeight, | |
z: carState.position.z - Math.cos(rad) * cameraDistance | |
}); | |
camera.setAttribute('rotation', { | |
x: 15, | |
y: carState.rotation, | |
z: 0 | |
}); | |
requestAnimationFrame(updateGame); | |
} | |
// Start the game loop | |
updateGame(); | |
</script> | |
</body> | |
</html> |