Spaces:
Running
Running
Create index.html
Browse files- index.html +240 -0
index.html
ADDED
@@ -0,0 +1,240 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html>
|
3 |
+
<head>
|
4 |
+
<title>3D Flying Game</title>
|
5 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.4.2/aframe.min.js"></script>
|
6 |
+
</head>
|
7 |
+
<body>
|
8 |
+
<a-scene>
|
9 |
+
<!-- Assets -->
|
10 |
+
<a-assets>
|
11 |
+
<img id="ground-tile" src="/api/placeholder/128/128" />
|
12 |
+
<img id="bump-map" src="/api/placeholder/128/128" />
|
13 |
+
|
14 |
+
<!-- Custom SVG shapes -->
|
15 |
+
<svg id="crystal" viewBox="0 0 100 100">
|
16 |
+
<path d="M50 0 L100 25 L100 75 L50 100 L0 75 L0 25 Z" fill="#88ff88"/>
|
17 |
+
</svg>
|
18 |
+
|
19 |
+
<svg id="starShape" viewBox="0 0 100 100">
|
20 |
+
<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"/>
|
21 |
+
</svg>
|
22 |
+
</a-assets>
|
23 |
+
|
24 |
+
<!-- Environment -->
|
25 |
+
<a-sky color="#001133"></a-sky>
|
26 |
+
<a-entity id="world">
|
27 |
+
<a-entity id="tileMap"></a-entity>
|
28 |
+
<a-entity id="decorativeShapes"></a-entity>
|
29 |
+
</a-entity>
|
30 |
+
|
31 |
+
<!-- Aircraft -->
|
32 |
+
<a-entity id="aircraft" position="0 10 0">
|
33 |
+
<!-- Main body -->
|
34 |
+
<a-box width="2" height="0.5" depth="4" color="#ff3333" metalness="0.8" roughness="0.2" shadow></a-box>
|
35 |
+
<!-- Wings -->
|
36 |
+
<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>
|
37 |
+
<!-- Tail -->
|
38 |
+
<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>
|
39 |
+
<!-- Nose cone -->
|
40 |
+
<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>
|
41 |
+
<!-- Engine glow -->
|
42 |
+
<a-sphere radius="0.3" position="0 -0.2 -2" color="#ffaa44" emission="intensity: 1"></a-sphere>
|
43 |
+
</a-entity>
|
44 |
+
|
45 |
+
<!-- Camera -->
|
46 |
+
<a-entity id="rig">
|
47 |
+
<a-camera position="0 2 12" look-controls wasd-controls="enabled: false"></a-camera>
|
48 |
+
</a-entity>
|
49 |
+
|
50 |
+
<!-- Lighting -->
|
51 |
+
<a-light type="ambient" color="#445566"></a-light>
|
52 |
+
<a-light type="directional" position="2 4 1" color="#ffffff" intensity="0.8" cast-shadow="true"></a-light>
|
53 |
+
</a-scene>
|
54 |
+
|
55 |
+
<script>
|
56 |
+
// Aircraft state
|
57 |
+
const aircraftState = {
|
58 |
+
position: { x: 0, y: 10, z: 0 },
|
59 |
+
rotation: { x: 0, y: 0, z: 0 },
|
60 |
+
velocity: { x: 0, y: 0, z: 0 },
|
61 |
+
maxSpeed: 1.0,
|
62 |
+
acceleration: 0.05,
|
63 |
+
turnSpeed: 2,
|
64 |
+
bankAngle: 0,
|
65 |
+
maxBankAngle: 45
|
66 |
+
};
|
67 |
+
|
68 |
+
// World generation parameters
|
69 |
+
const worldState = {
|
70 |
+
chunkSize: 20,
|
71 |
+
tileSize: 5,
|
72 |
+
visibleChunks: 3,
|
73 |
+
currentChunk: { x: 0, z: 0 }
|
74 |
+
};
|
75 |
+
|
76 |
+
const colors = ['#2244aa', '#22aa44', '#aa2244', '#aaaa22'];
|
77 |
+
|
78 |
+
// Generate a single chunk of terrain
|
79 |
+
function generateChunk(chunkX, chunkZ) {
|
80 |
+
const chunk = document.createElement('a-entity');
|
81 |
+
const startX = chunkX * worldState.chunkSize * worldState.tileSize;
|
82 |
+
const startZ = chunkZ * worldState.chunkSize * worldState.tileSize;
|
83 |
+
|
84 |
+
for (let x = 0; x < worldState.chunkSize; x++) {
|
85 |
+
for (let z = 0; z < worldState.chunkSize; z++) {
|
86 |
+
const tile = document.createElement('a-box');
|
87 |
+
const worldX = startX + x * worldState.tileSize;
|
88 |
+
const worldZ = startZ + z * worldState.tileSize;
|
89 |
+
|
90 |
+
tile.setAttribute('width', worldState.tileSize);
|
91 |
+
tile.setAttribute('height', 0.1);
|
92 |
+
tile.setAttribute('depth', worldState.tileSize);
|
93 |
+
tile.setAttribute('position', {
|
94 |
+
x: worldX,
|
95 |
+
y: -0.05,
|
96 |
+
z: worldZ
|
97 |
+
});
|
98 |
+
tile.setAttribute('material', {
|
99 |
+
color: colors[((x + z) + (chunkX + chunkZ)) % colors.length],
|
100 |
+
src: '#ground-tile',
|
101 |
+
repeat: { x: 1, y: 1 },
|
102 |
+
normalMap: '#bump-map'
|
103 |
+
});
|
104 |
+
tile.setAttribute('shadow', '');
|
105 |
+
chunk.appendChild(tile);
|
106 |
+
|
107 |
+
// Add random decorative shapes
|
108 |
+
if (Math.random() < 0.05) {
|
109 |
+
const shape = document.createElement('a-entity');
|
110 |
+
const type = Math.floor(Math.random() * 2);
|
111 |
+
const scale = 2 + Math.random() * 3;
|
112 |
+
const height = Math.random() * 10;
|
113 |
+
|
114 |
+
shape.setAttribute('position', `${worldX} ${height} ${worldZ}`);
|
115 |
+
shape.setAttribute('rotation', `0 ${Math.random() * 360} 0`);
|
116 |
+
shape.setAttribute('scale', `${scale} ${scale} ${scale}`);
|
117 |
+
|
118 |
+
if (type === 0) {
|
119 |
+
shape.setAttribute('geometry', 'primitive: cylinder; radius: 0.5; height: 1;');
|
120 |
+
shape.setAttribute('material', 'color: #ff88ff; metalness: 0.5; roughness: 0.2');
|
121 |
+
} else {
|
122 |
+
shape.setAttribute('geometry', 'primitive: cone; radiusBottom: 0.7; radiusTop: 0;');
|
123 |
+
shape.setAttribute('material', 'color: #ffff88; metalness: 0.5; roughness: 0.2');
|
124 |
+
}
|
125 |
+
|
126 |
+
chunk.appendChild(shape);
|
127 |
+
}
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
return chunk;
|
132 |
+
}
|
133 |
+
|
134 |
+
// Update visible chunks based on aircraft position
|
135 |
+
function updateWorld() {
|
136 |
+
const currentChunkX = Math.floor(aircraftState.position.x / (worldState.chunkSize * worldState.tileSize));
|
137 |
+
const currentChunkZ = Math.floor(aircraftState.position.z / (worldState.chunkSize * worldState.tileSize));
|
138 |
+
|
139 |
+
if (currentChunkX !== worldState.currentChunk.x || currentChunkZ !== worldState.currentChunk.z) {
|
140 |
+
const world = document.querySelector('#world');
|
141 |
+
world.innerHTML = '';
|
142 |
+
|
143 |
+
for (let x = -1; x <= 1; x++) {
|
144 |
+
for (let z = -1; z <= 1; z++) {
|
145 |
+
const chunk = generateChunk(currentChunkX + x, currentChunkZ + z);
|
146 |
+
world.appendChild(chunk);
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
worldState.currentChunk = { x: currentChunkX, z: currentChunkZ };
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
// Controls
|
155 |
+
const aircraft = document.querySelector('#aircraft');
|
156 |
+
const camera = document.querySelector('#rig');
|
157 |
+
let keys = {};
|
158 |
+
|
159 |
+
document.addEventListener('keydown', (e) => {
|
160 |
+
keys[e.key.toLowerCase()] = true;
|
161 |
+
});
|
162 |
+
|
163 |
+
document.addEventListener('keyup', (e) => {
|
164 |
+
keys[e.key.toLowerCase()] = false;
|
165 |
+
});
|
166 |
+
|
167 |
+
// Game loop
|
168 |
+
function updateGame() {
|
169 |
+
// Aircraft controls
|
170 |
+
if (keys['s']) { // Forward (swapped)
|
171 |
+
aircraftState.velocity.z -= aircraftState.acceleration;
|
172 |
+
} else if (keys['w']) { // Backward (swapped)
|
173 |
+
aircraftState.velocity.z += aircraftState.acceleration;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Banking controls
|
177 |
+
if (keys['q']) {
|
178 |
+
aircraftState.bankAngle = Math.min(aircraftState.bankAngle + 2, aircraftState.maxBankAngle);
|
179 |
+
aircraftState.velocity.x -= aircraftState.acceleration * 0.5;
|
180 |
+
} else if (keys['e']) {
|
181 |
+
aircraftState.bankAngle = Math.max(aircraftState.bankAngle - 2, -aircraftState.maxBankAngle);
|
182 |
+
aircraftState.velocity.x += aircraftState.acceleration * 0.5;
|
183 |
+
} else {
|
184 |
+
aircraftState.bankAngle *= 0.95; // Return to level flight
|
185 |
+
}
|
186 |
+
|
187 |
+
// Turning
|
188 |
+
if (keys['a']) {
|
189 |
+
aircraftState.rotation.y += aircraftState.turnSpeed;
|
190 |
+
}
|
191 |
+
if (keys['d']) {
|
192 |
+
aircraftState.rotation.y -= aircraftState.turnSpeed;
|
193 |
+
}
|
194 |
+
|
195 |
+
// Apply physics
|
196 |
+
aircraftState.velocity.z *= 0.99; // Air resistance
|
197 |
+
aircraftState.velocity.x *= 0.99;
|
198 |
+
|
199 |
+
// Clamp velocity
|
200 |
+
aircraftState.velocity.z = Math.max(Math.min(aircraftState.velocity.z, aircraftState.maxSpeed), -aircraftState.maxSpeed);
|
201 |
+
aircraftState.velocity.x = Math.max(Math.min(aircraftState.velocity.x, aircraftState.maxSpeed), -aircraftState.maxSpeed);
|
202 |
+
|
203 |
+
// Update position
|
204 |
+
const rad = (aircraftState.rotation.y * Math.PI) / 180;
|
205 |
+
aircraftState.position.x += Math.sin(rad) * aircraftState.velocity.z + aircraftState.velocity.x;
|
206 |
+
aircraftState.position.z += Math.cos(rad) * aircraftState.velocity.z;
|
207 |
+
|
208 |
+
// Update aircraft position and rotation
|
209 |
+
aircraft.setAttribute('position', aircraftState.position);
|
210 |
+
aircraft.setAttribute('rotation', {
|
211 |
+
x: -aircraftState.velocity.z * 15, // Pitch based on speed
|
212 |
+
y: aircraftState.rotation.y,
|
213 |
+
z: aircraftState.bankAngle
|
214 |
+
});
|
215 |
+
|
216 |
+
// Camera follow
|
217 |
+
const cameraDistance = 12;
|
218 |
+
const cameraHeight = 2;
|
219 |
+
camera.setAttribute('position', {
|
220 |
+
x: aircraftState.position.x - Math.sin(rad) * cameraDistance,
|
221 |
+
y: aircraftState.position.y + cameraHeight,
|
222 |
+
z: aircraftState.position.z - Math.cos(rad) * cameraDistance
|
223 |
+
});
|
224 |
+
camera.setAttribute('rotation', {
|
225 |
+
x: 15,
|
226 |
+
y: aircraftState.rotation.y,
|
227 |
+
z: 0
|
228 |
+
});
|
229 |
+
|
230 |
+
// Update world chunks
|
231 |
+
updateWorld();
|
232 |
+
|
233 |
+
requestAnimationFrame(updateGame);
|
234 |
+
}
|
235 |
+
|
236 |
+
// Start the game loop
|
237 |
+
updateGame();
|
238 |
+
</script>
|
239 |
+
</body>
|
240 |
+
</html>
|