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> |