Update index.html
Browse files- index.html +222 -29
index.html
CHANGED
@@ -83,9 +83,13 @@
|
|
83 |
</a-scene>
|
84 |
|
85 |
<script>
|
86 |
-
//
|
|
|
|
|
|
|
|
|
87 |
|
88 |
-
// Editor
|
89 |
let selectedObject = null;
|
90 |
let isGameMode = true;
|
91 |
const simplex = new SimplexNoise();
|
@@ -166,10 +170,15 @@
|
|
166 |
const bumpMapUrl = generateBumpMap();
|
167 |
|
168 |
newEntity.setAttribute('material', `src: ${textureUrl}; normalMap: ${bumpMapUrl}`);
|
169 |
-
newEntity.setAttribute('position', '0 1.5 -3');
|
170 |
newEntity.setAttribute('class', 'editable');
|
171 |
newEntity.addEventListener('click', function() { selectObject(this); });
|
172 |
scene.appendChild(newEntity);
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
}
|
174 |
|
175 |
function selectObject(obj) {
|
@@ -179,17 +188,19 @@
|
|
179 |
selectedObject = obj;
|
180 |
selectedObject.setAttribute('material', 'emissive', '#FF0000');
|
181 |
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
|
|
|
|
|
|
187 |
|
188 |
-
|
189 |
-
|
190 |
-
document.getElementById('
|
191 |
-
document.getElementById('
|
192 |
-
document.getElementById('rz').value = rotation.z;
|
193 |
}
|
194 |
|
195 |
function applyTransform() {
|
@@ -209,8 +220,9 @@
|
|
209 |
selectedObject.setAttribute('rotation', `${rx} ${ry} ${rz}`);
|
210 |
}
|
211 |
|
212 |
-
function placeInFrontOfCamera() {
|
213 |
-
|
|
|
214 |
alert('Please select an object first');
|
215 |
return;
|
216 |
}
|
@@ -224,12 +236,12 @@
|
|
224 |
const x = cameraPosition.x - Math.sin(radians) * 3;
|
225 |
const z = cameraPosition.z - Math.cos(radians) * 3;
|
226 |
|
227 |
-
|
228 |
|
229 |
-
// Update position inputs
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
}
|
234 |
|
235 |
function toggleGameMode() {
|
@@ -242,25 +254,206 @@
|
|
242 |
}
|
243 |
}
|
244 |
|
245 |
-
//
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
}
|
253 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
// Initialize the game
|
256 |
updateHealthDisplay();
|
257 |
updateUnitCounters();
|
258 |
|
|
|
259 |
setInterval(() => {
|
260 |
updateGame();
|
261 |
score++;
|
262 |
updateScoreDisplay();
|
263 |
-
}, 1000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
</script>
|
265 |
</body>
|
266 |
</html>
|
|
|
83 |
</a-scene>
|
84 |
|
85 |
<script>
|
86 |
+
// Game variables
|
87 |
+
let score = 0;
|
88 |
+
let health = 100;
|
89 |
+
let enemyCount = 0;
|
90 |
+
let spawnerCount = 0;
|
91 |
|
92 |
+
// Editor variables
|
93 |
let selectedObject = null;
|
94 |
let isGameMode = true;
|
95 |
const simplex = new SimplexNoise();
|
|
|
170 |
const bumpMapUrl = generateBumpMap();
|
171 |
|
172 |
newEntity.setAttribute('material', `src: ${textureUrl}; normalMap: ${bumpMapUrl}`);
|
|
|
173 |
newEntity.setAttribute('class', 'editable');
|
174 |
newEntity.addEventListener('click', function() { selectObject(this); });
|
175 |
scene.appendChild(newEntity);
|
176 |
+
|
177 |
+
// Place the new object in front of the camera
|
178 |
+
placeInFrontOfCamera(newEntity);
|
179 |
+
|
180 |
+
// Select the newly added object
|
181 |
+
selectObject(newEntity);
|
182 |
}
|
183 |
|
184 |
function selectObject(obj) {
|
|
|
188 |
selectedObject = obj;
|
189 |
selectedObject.setAttribute('material', 'emissive', '#FF0000');
|
190 |
|
191 |
+
updateTransformInputs(selectedObject);
|
192 |
+
}
|
193 |
+
|
194 |
+
function updateTransformInputs(obj) {
|
195 |
+
const position = obj.getAttribute('position');
|
196 |
+
document.getElementById('px').value = position.x.toFixed(2);
|
197 |
+
document.getElementById('py').value = position.y.toFixed(2);
|
198 |
+
document.getElementById('pz').value = position.z.toFixed(2);
|
199 |
|
200 |
+
const rotation = obj.getAttribute('rotation');
|
201 |
+
document.getElementById('rx').value = rotation.x.toFixed(2);
|
202 |
+
document.getElementById('ry').value = rotation.y.toFixed(2);
|
203 |
+
document.getElementById('rz').value = rotation.z.toFixed(2);
|
|
|
204 |
}
|
205 |
|
206 |
function applyTransform() {
|
|
|
220 |
selectedObject.setAttribute('rotation', `${rx} ${ry} ${rz}`);
|
221 |
}
|
222 |
|
223 |
+
function placeInFrontOfCamera(obj = null) {
|
224 |
+
const targetObject = obj || selectedObject;
|
225 |
+
if (!targetObject) {
|
226 |
alert('Please select an object first');
|
227 |
return;
|
228 |
}
|
|
|
236 |
const x = cameraPosition.x - Math.sin(radians) * 3;
|
237 |
const z = cameraPosition.z - Math.cos(radians) * 3;
|
238 |
|
239 |
+
targetObject.setAttribute('position', `${x} ${cameraPosition.y} ${z}`);
|
240 |
|
241 |
+
// Update position inputs if the object is selected
|
242 |
+
if (targetObject === selectedObject) {
|
243 |
+
updateTransformInputs(targetObject);
|
244 |
+
}
|
245 |
}
|
246 |
|
247 |
function toggleGameMode() {
|
|
|
254 |
}
|
255 |
}
|
256 |
|
257 |
+
// Game logic functions
|
258 |
+
function fireLaser(shooter, color) {
|
259 |
+
const laser = document.createElement('a-entity');
|
260 |
+
const start = new THREE.Vector3();
|
261 |
+
const direction = new THREE.Vector3();
|
262 |
+
shooter.object3D.getWorldPosition(start);
|
263 |
+
shooter.object3D.getWorldDirection(direction);
|
264 |
+
laser.setAttribute('position', start);
|
265 |
+
laser.setAttribute('geometry', 'primitive: sphere; radius: 0.1');
|
266 |
+
laser.setAttribute('material', `color: ${color}; shader: flat`);
|
267 |
+
document.querySelector('a-scene').appendChild(laser);
|
268 |
+
|
269 |
+
const animateShot = () => {
|
270 |
+
const position = laser.getAttribute('position');
|
271 |
+
const newPosition = {
|
272 |
+
x: position.x + direction.x * 0.5,
|
273 |
+
y: position.y + direction.y * 0.5,
|
274 |
+
z: position.z + direction.z * 0.5
|
275 |
+
};
|
276 |
+
laser.setAttribute('position', newPosition);
|
277 |
+
|
278 |
+
// Check for collisions
|
279 |
+
const enemies = document.querySelectorAll('.enemy');
|
280 |
+
enemies.forEach(enemy => {
|
281 |
+
const enemyPos = enemy.getAttribute('position');
|
282 |
+
const distance = calculateDistance(newPosition, enemyPos);
|
283 |
+
if (distance < 1) {
|
284 |
+
enemy.parentNode.removeChild(enemy);
|
285 |
+
laser.parentNode.removeChild(laser);
|
286 |
+
enemyCount--;
|
287 |
+
score += 10;
|
288 |
+
updateScoreDisplay();
|
289 |
+
updateUnitCounters();
|
290 |
+
return;
|
291 |
+
}
|
292 |
+
});
|
293 |
+
|
294 |
+
const spawners = document.querySelectorAll('.spawner');
|
295 |
+
spawners.forEach(spawner => {
|
296 |
+
const spawnerPos = spawner.getAttribute('position');
|
297 |
+
const distance = calculateDistance(newPosition, spawnerPos);
|
298 |
+
if (distance < 1.5) {
|
299 |
+
spawner.parentNode.removeChild(spawner);
|
300 |
+
laser.parentNode.removeChild(laser);
|
301 |
+
spawnerCount--;
|
302 |
+
score += 50;
|
303 |
+
updateScoreDisplay();
|
304 |
+
updateUnitCounters();
|
305 |
+
return;
|
306 |
+
}
|
307 |
+
});
|
308 |
+
|
309 |
+
if (laser.parentNode) {
|
310 |
+
requestAnimationFrame(animateShot);
|
311 |
+
}
|
312 |
+
};
|
313 |
+
|
314 |
+
requestAnimationFrame(animateShot);
|
315 |
+
}
|
316 |
+
|
317 |
+
function calculateDistance(pos1, pos2) {
|
318 |
+
const dx = pos1.x - pos2.x;
|
319 |
+
const dy = pos1.y - pos2.y;
|
320 |
+
const dz = pos1.z - pos2.z;
|
321 |
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
322 |
+
}
|
323 |
+
|
324 |
+
function spawnEnemy() {
|
325 |
+
const enemy = document.createElement('a-entity');
|
326 |
+
enemy.setAttribute('geometry', 'primitive: box');
|
327 |
+
enemy.setAttribute('material', 'color: red');
|
328 |
+
enemy.setAttribute('class', 'enemy');
|
329 |
+
const angle = Math.random() * Math.PI * 2;
|
330 |
+
const radius = 10 + Math.random() * 10;
|
331 |
+
const x = Math.cos(angle) * radius;
|
332 |
+
const z = Math.sin(angle) * radius;
|
333 |
+
enemy.setAttribute('position', `${x} 1.6 ${z}`);
|
334 |
+
document.querySelector('a-scene').appendChild(enemy);
|
335 |
+
enemyCount++;
|
336 |
+
updateUnitCounters();
|
337 |
+
}
|
338 |
+
|
339 |
+
function spawnSpawner() {
|
340 |
+
const spawner = document.createElement('a-entity');
|
341 |
+
spawner.setAttribute('geometry', 'primitive: box; width: 2; height: 2; depth: 2');
|
342 |
+
spawner.setAttribute('material', 'color: purple');
|
343 |
+
spawner.setAttribute('class', 'spawner');
|
344 |
+
const angle = Math.random() * Math.spawner.setAttribute('class', 'spawner');
|
345 |
+
const angle = Math.random() * Math.PI * 2;
|
346 |
+
const radius = 15 + Math.random() * 10;
|
347 |
+
const x = Math.cos(angle) * radius;
|
348 |
+
const z = Math.sin(angle) * radius;
|
349 |
+
spawner.setAttribute('position', `${x} 1.6 ${z}`);
|
350 |
+
document.querySelector('a-scene').appendChild(spawner);
|
351 |
+
spawnerCount++;
|
352 |
+
updateUnitCounters();
|
353 |
+
}
|
354 |
+
|
355 |
+
function updateGame() {
|
356 |
+
// Spawn enemies from spawners
|
357 |
+
const spawners = document.querySelectorAll('.spawner');
|
358 |
+
spawners.forEach(spawner => {
|
359 |
+
if (Math.random() < 0.1) {
|
360 |
+
const enemy = document.createElement('a-entity');
|
361 |
+
enemy.setAttribute('geometry', 'primitive: box');
|
362 |
+
enemy.setAttribute('material', 'color: red');
|
363 |
+
enemy.setAttribute('class', 'enemy');
|
364 |
+
const spawnerPos = spawner.getAttribute('position');
|
365 |
+
enemy.setAttribute('position', `${spawnerPos.x} ${spawnerPos.y} ${spawnerPos.z}`);
|
366 |
+
document.querySelector('a-scene').appendChild(enemy);
|
367 |
+
enemyCount++;
|
368 |
+
}
|
369 |
+
});
|
370 |
+
|
371 |
+
// Move enemies towards player
|
372 |
+
const player = document.querySelector('#player');
|
373 |
+
const playerPos = player.getAttribute('position');
|
374 |
+
const enemies = document.querySelectorAll('.enemy');
|
375 |
+
enemies.forEach(enemy => {
|
376 |
+
const enemyPos = enemy.getAttribute('position');
|
377 |
+
const direction = {
|
378 |
+
x: playerPos.x - enemyPos.x,
|
379 |
+
y: 0,
|
380 |
+
z: playerPos.z - enemyPos.z
|
381 |
+
};
|
382 |
+
const length = Math.sqrt(direction.x * direction.x + direction.z * direction.z);
|
383 |
+
direction.x /= length;
|
384 |
+
direction.z /= length;
|
385 |
+
enemy.setAttribute('position', {
|
386 |
+
x: enemyPos.x + direction.x * 0.05,
|
387 |
+
y: enemyPos.y,
|
388 |
+
z: enemyPos.z + direction.z * 0.05
|
389 |
+
});
|
390 |
+
|
391 |
+
// Check for collision with player
|
392 |
+
if (calculateDistance(playerPos, enemy.getAttribute('position')) < 1) {
|
393 |
+
enemy.parentNode.removeChild(enemy);
|
394 |
+
enemyCount--;
|
395 |
+
health -= 10;
|
396 |
+
updateHealthDisplay();
|
397 |
+
updateUnitCounters();
|
398 |
+
}
|
399 |
+
});
|
400 |
+
|
401 |
+
// Randomly spawn new enemies and spawners
|
402 |
+
if (Math.random() < 0.02) spawnEnemy();
|
403 |
+
if (Math.random() < 0.005) spawnSpawner();
|
404 |
+
}
|
405 |
+
|
406 |
+
function updateScoreDisplay() {
|
407 |
+
const scoreIndicator = document.querySelector('#scoreIndicator');
|
408 |
+
scoreIndicator.setAttribute('scale', `${score / 1000} 1 1`);
|
409 |
+
}
|
410 |
+
|
411 |
+
function updateHealthDisplay() {
|
412 |
+
const healthDisplay = document.querySelector('#healthDisplay');
|
413 |
+
healthDisplay.innerHTML = '';
|
414 |
+
for (let i = 0; i < health / 10; i++) {
|
415 |
+
const heart = document.createElement('a-text');
|
416 |
+
heart.setAttribute('value', '❤');
|
417 |
+
heart.setAttribute('position', `${i * 0.2} 0 0`);
|
418 |
+
heart.setAttribute('color', 'red');
|
419 |
+
healthDisplay.appendChild(heart);
|
420 |
}
|
421 |
+
}
|
422 |
+
|
423 |
+
function updateUnitCounters() {
|
424 |
+
const unitCounters = document.querySelector('#unitCounters');
|
425 |
+
unitCounters.innerHTML = '';
|
426 |
+
const enemyCounter = document.createElement('a-text');
|
427 |
+
enemyCounter.setAttribute('value', `Enemies: ${enemyCount}`);
|
428 |
+
enemyCounter.setAttribute('position', '0 0 0');
|
429 |
+
unitCounters.appendChild(enemyCounter);
|
430 |
+
const spawnerCounter = document.createElement('a-text');
|
431 |
+
spawnerCounter.setAttribute('value', `Spawners: ${spawnerCount}`);
|
432 |
+
spawnerCounter.setAttribute('position', '0 -0.3 0');
|
433 |
+
unitCounters.appendChild(spawnerCounter);
|
434 |
+
}
|
435 |
|
436 |
// Initialize the game
|
437 |
updateHealthDisplay();
|
438 |
updateUnitCounters();
|
439 |
|
440 |
+
// Main game loop
|
441 |
setInterval(() => {
|
442 |
updateGame();
|
443 |
score++;
|
444 |
updateScoreDisplay();
|
445 |
+
}, 1000 / 60); // 60 FPS
|
446 |
+
|
447 |
+
// Event listeners
|
448 |
+
const scene = document.querySelector('a-scene');
|
449 |
+
scene.addEventListener('click', (event) => {
|
450 |
+
if (isGameMode) {
|
451 |
+
const player = document.querySelector('#player');
|
452 |
+
fireLaser(player, '#00FF00');
|
453 |
+
} else if (event.detail.intersectedEl && event.detail.intersectedEl.classList.contains('editable')) {
|
454 |
+
selectObject(event.detail.intersectedEl);
|
455 |
+
}
|
456 |
+
});
|
457 |
</script>
|
458 |
</body>
|
459 |
</html>
|