LetsMakeGames / index.html
awacke1's picture
Create index.html
c272100 verified
<!DOCTYPE html>
<html>
<head>
<title>3D Flying 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>
</a-assets>
<!-- Environment -->
<a-sky color="#001133"></a-sky>
<a-entity id="world">
<a-entity id="tileMap"></a-entity>
<a-entity id="decorativeShapes"></a-entity>
</a-entity>
<!-- Aircraft -->
<a-entity id="aircraft" position="0 10 0">
<!-- Main body -->
<a-box width="2" height="0.5" depth="4" color="#ff3333" metalness="0.8" roughness="0.2" shadow></a-box>
<!-- Wings -->
<a-box width="8" height="0.2" depth="1.5" position="0 0 0" color="#cc2222" metalness="0.8" roughness="0.2" shadow></a-box>
<!-- Tail -->
<a-box width="1" height="1" depth="0.2" position="0 0.5 -1.8" color="#cc2222" metalness="0.8" roughness="0.2" shadow></a-box>
<!-- Nose cone -->
<a-cone radius-bottom="0.8" radius-top="0.1" height="2" position="0 0 2.5" rotation="90 0 0" color="#cc2222" metalness="0.8" roughness="0.2"></a-cone>
<!-- Engine glow -->
<a-sphere radius="0.3" position="0 -0.2 -2" color="#ffaa44" emission="intensity: 1"></a-sphere>
</a-entity>
<!-- Camera -->
<a-entity id="rig">
<a-camera position="0 2 12" 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>
// Aircraft state
const aircraftState = {
position: { x: 0, y: 10, z: 0 },
rotation: { x: 0, y: 0, z: 0 },
velocity: { x: 0, y: 0, z: 0 },
maxSpeed: 1.0,
acceleration: 0.05,
turnSpeed: 2,
bankAngle: 0,
maxBankAngle: 45
};
// World generation parameters
const worldState = {
chunkSize: 20,
tileSize: 5,
visibleChunks: 3,
currentChunk: { x: 0, z: 0 }
};
const colors = ['#2244aa', '#22aa44', '#aa2244', '#aaaa22'];
// Generate a single chunk of terrain
function generateChunk(chunkX, chunkZ) {
const chunk = document.createElement('a-entity');
const startX = chunkX * worldState.chunkSize * worldState.tileSize;
const startZ = chunkZ * worldState.chunkSize * worldState.tileSize;
for (let x = 0; x < worldState.chunkSize; x++) {
for (let z = 0; z < worldState.chunkSize; z++) {
const tile = document.createElement('a-box');
const worldX = startX + x * worldState.tileSize;
const worldZ = startZ + z * worldState.tileSize;
tile.setAttribute('width', worldState.tileSize);
tile.setAttribute('height', 0.1);
tile.setAttribute('depth', worldState.tileSize);
tile.setAttribute('position', {
x: worldX,
y: -0.05,
z: worldZ
});
tile.setAttribute('material', {
color: colors[((x + z) + (chunkX + chunkZ)) % colors.length],
src: '#ground-tile',
repeat: { x: 1, y: 1 },
normalMap: '#bump-map'
});
tile.setAttribute('shadow', '');
chunk.appendChild(tile);
// Add random decorative shapes
if (Math.random() < 0.05) {
const shape = document.createElement('a-entity');
const type = Math.floor(Math.random() * 2);
const scale = 2 + Math.random() * 3;
const height = Math.random() * 10;
shape.setAttribute('position', `${worldX} ${height} ${worldZ}`);
shape.setAttribute('rotation', `0 ${Math.random() * 360} 0`);
shape.setAttribute('scale', `${scale} ${scale} ${scale}`);
if (type === 0) {
shape.setAttribute('geometry', 'primitive: cylinder; radius: 0.5; height: 1;');
shape.setAttribute('material', 'color: #ff88ff; metalness: 0.5; roughness: 0.2');
} else {
shape.setAttribute('geometry', 'primitive: cone; radiusBottom: 0.7; radiusTop: 0;');
shape.setAttribute('material', 'color: #ffff88; metalness: 0.5; roughness: 0.2');
}
chunk.appendChild(shape);
}
}
}
return chunk;
}
// Update visible chunks based on aircraft position
function updateWorld() {
const currentChunkX = Math.floor(aircraftState.position.x / (worldState.chunkSize * worldState.tileSize));
const currentChunkZ = Math.floor(aircraftState.position.z / (worldState.chunkSize * worldState.tileSize));
if (currentChunkX !== worldState.currentChunk.x || currentChunkZ !== worldState.currentChunk.z) {
const world = document.querySelector('#world');
world.innerHTML = '';
for (let x = -1; x <= 1; x++) {
for (let z = -1; z <= 1; z++) {
const chunk = generateChunk(currentChunkX + x, currentChunkZ + z);
world.appendChild(chunk);
}
}
worldState.currentChunk = { x: currentChunkX, z: currentChunkZ };
}
}
// Controls
const aircraft = document.querySelector('#aircraft');
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() {
// Aircraft controls
if (keys['s']) { // Forward (swapped)
aircraftState.velocity.z -= aircraftState.acceleration;
} else if (keys['w']) { // Backward (swapped)
aircraftState.velocity.z += aircraftState.acceleration;
}
// Banking controls
if (keys['q']) {
aircraftState.bankAngle = Math.min(aircraftState.bankAngle + 2, aircraftState.maxBankAngle);
aircraftState.velocity.x -= aircraftState.acceleration * 0.5;
} else if (keys['e']) {
aircraftState.bankAngle = Math.max(aircraftState.bankAngle - 2, -aircraftState.maxBankAngle);
aircraftState.velocity.x += aircraftState.acceleration * 0.5;
} else {
aircraftState.bankAngle *= 0.95; // Return to level flight
}
// Turning
if (keys['a']) {
aircraftState.rotation.y += aircraftState.turnSpeed;
}
if (keys['d']) {
aircraftState.rotation.y -= aircraftState.turnSpeed;
}
// Apply physics
aircraftState.velocity.z *= 0.99; // Air resistance
aircraftState.velocity.x *= 0.99;
// Clamp velocity
aircraftState.velocity.z = Math.max(Math.min(aircraftState.velocity.z, aircraftState.maxSpeed), -aircraftState.maxSpeed);
aircraftState.velocity.x = Math.max(Math.min(aircraftState.velocity.x, aircraftState.maxSpeed), -aircraftState.maxSpeed);
// Update position
const rad = (aircraftState.rotation.y * Math.PI) / 180;
aircraftState.position.x += Math.sin(rad) * aircraftState.velocity.z + aircraftState.velocity.x;
aircraftState.position.z += Math.cos(rad) * aircraftState.velocity.z;
// Update aircraft position and rotation
aircraft.setAttribute('position', aircraftState.position);
aircraft.setAttribute('rotation', {
x: -aircraftState.velocity.z * 15, // Pitch based on speed
y: aircraftState.rotation.y,
z: aircraftState.bankAngle
});
// Camera follow
const cameraDistance = 12;
const cameraHeight = 2;
camera.setAttribute('position', {
x: aircraftState.position.x - Math.sin(rad) * cameraDistance,
y: aircraftState.position.y + cameraHeight,
z: aircraftState.position.z - Math.cos(rad) * cameraDistance
});
camera.setAttribute('rotation', {
x: 15,
y: aircraftState.rotation.y,
z: 0
});
// Update world chunks
updateWorld();
requestAnimationFrame(updateGame);
}
// Start the game loop
updateGame();
</script>
</body>
</html>