awacke1 commited on
Commit
a0c1b77
·
verified ·
1 Parent(s): 8e59c55

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +26 -645
index.html CHANGED
@@ -2,7 +2,7 @@
2
  <html>
3
  <head>
4
  <meta charset="utf-8">
5
- <title>A-Frame Space Shooter with Simple 3D Editor</title>
6
  <script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
7
  <style>
8
  .ui-panel {
@@ -40,7 +40,11 @@
40
  </head>
41
  <body>
42
  <div class="ui-panel">
43
- <button onclick="addPrimitive('box')">Add Box</button>
 
 
 
 
44
  <button onclick="toggleGameMode()">Toggle Game Mode</button>
45
  </div>
46
 
@@ -64,7 +68,7 @@
64
  <a-entity id="cursor" cursor="fuse: false;" position="0 0 -1"
65
  geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
66
  material="color: white; shader: flat"
67
- raycaster="objects: .enemy, .spawner, .editable"></a-entity>
68
  </a-entity>
69
  </a-entity>
70
  <a-entity id="scoreBar" position="0 3 -5">
@@ -74,658 +78,36 @@
74
  </a-entity>
75
  <a-entity id="healthDisplay" position="0 2.5 -5" scale="5 5 5"></a-entity>
76
  <a-entity id="unitCounters" position="-0.8 0.6 -1.5" scale="0.5 0.5 0.5"></a-entity>
 
 
 
77
  </a-scene>
78
 
79
  <script>
80
- const scene = document.querySelector('a-scene');
81
- const player = document.querySelector('#player');
82
- const scoreIndicator = document.querySelector('#scoreIndicator');
83
- const healthDisplay = document.querySelector('#healthDisplay');
84
- const unitCounters = document.querySelector('#unitCounters');
85
- let score = 0;
86
- let health = 100;
87
- let enemies = new Set();
88
- let spawners = new Set();
89
- let explosionCount = 0;
90
- const maxScore = 1000; // Maximum score for full bar
91
-
92
- function updateScoreDisplay() {
93
- const scale = Math.min(score / maxScore, 1);
94
- scoreIndicator.setAttribute('scale', `${scale} 1 1`);
95
- }
96
-
97
- function updateHealthDisplay() {
98
- healthDisplay.setAttribute('text', {
99
- value: `Health: ${health}`,
100
- color: 'white',
101
- align: 'center'
102
- });
103
- }
104
-
105
- function updateUnitCounters() {
106
- unitCounters.innerHTML = '';
107
- const counters = [
108
- {name: 'Enemies', count: enemies.size},
109
- {name: 'Spawners', count: spawners.size},
110
- {name: 'Explosions', count: explosionCount}
111
- ];
112
-
113
- counters.forEach((counter, index) => {
114
- const text = document.createElement('a-text');
115
- text.setAttribute('value', `${counter.name}: ${counter.count}`);
116
- text.setAttribute('color', 'white');
117
- text.setAttribute('position', `0 ${-index * 0.2} 0`);
118
- unitCounters.appendChild(text);
119
- });
120
- }
121
-
122
- function createSpawner() {
123
- const spawner = document.createElement('a-entity');
124
- spawner.setAttribute('class', 'spawner');
125
- spawner.setAttribute('geometry', {primitive: 'box', width: 2, height: 2, depth: 2});
126
- spawner.setAttribute('material', {color: '#00FF00', metalness: 0.7, roughness: 0.3});
127
-
128
- const angle = Math.random() * Math.PI * 2;
129
- const distance = 30;
130
- const position = new THREE.Vector3(
131
- Math.cos(angle) * distance,
132
- Math.random() * 10 - 5,
133
- Math.sin(angle) * distance
134
- );
135
- spawner.setAttribute('position', position);
136
-
137
- spawner.health = 100;
138
-
139
- scene.appendChild(spawner);
140
- spawners.add(spawner);
141
-
142
- // Spawner behavior
143
- setInterval(() => {
144
- if (spawner.parentNode && spawner.health > 0) {
145
- createEnemy(spawner.object3D.position);
146
- }
147
- }, 5000);
148
-
149
- updateUnitCounters();
150
- }
151
-
152
- function createEnemy(spawnPosition) {
153
- if (enemies.size >= 30) return; // Limit number of enemies
154
-
155
- const enemy = document.createElement('a-entity');
156
- enemy.setAttribute('class', 'enemy');
157
- enemy.setAttribute('geometry', {primitive: 'sphere', radius: 0.5});
158
- enemy.setAttribute('material', {color: '#FF0000', metalness: 0.7, roughness: 0.3});
159
-
160
- const position = new THREE.Vector3(
161
- spawnPosition.x + (Math.random() - 0.5) * 2,
162
- spawnPosition.y + (Math.random() - 0.5) * 2,
163
- spawnPosition.z + (Math.random() - 0.5) * 2
164
- );
165
- enemy.setAttribute('position', position);
166
-
167
- const particleSystem = document.createElement('a-entity');
168
- particleSystem.setAttribute('particle-system', {
169
- preset: 'dust',
170
- particleCount: 100,
171
- color: '#FF0000, #FF5500',
172
- size: 0.1,
173
- dur: 1000,
174
- accelerationValue: '0 -9.8 0'
175
- });
176
- enemy.appendChild(particleSystem);
177
-
178
- enemy.creationTime = Date.now();
179
-
180
- scene.appendChild(enemy);
181
- enemies.add(enemy);
182
-
183
- // Enemy firing behavior
184
- enemy.setAttribute('animation__movement', {
185
- property: 'position',
186
- to: '0 1.6 0',
187
- dur: 15000,
188
- easing: 'linear'
189
- });
190
-
191
- setInterval(() => {
192
- if (enemy.parentNode) {
193
- fireLaser(enemy, '#FF0000');
194
- }
195
- }, 2000);
196
-
197
- updateUnitCounters();
198
- }
199
-
200
- function fireLaser(source, color) {
201
- const laser = document.createElement('a-entity');
202
- laser.setAttribute('geometry', {primitive: 'cylinder', radius: 0.05, height: 100});
203
- laser.setAttribute('material', {color: color, opacity: 0.7});
204
-
205
- const sourcePosition = source.object3D.position;
206
- const targetPosition = player.object3D.position;
207
- const direction = new THREE.Vector3().subVectors(targetPosition, sourcePosition).normalize();
208
-
209
- laser.setAttribute('position', sourcePosition);
210
- laser.object3D.lookAt(targetPosition);
211
-
212
- scene.appendChild(laser);
213
-
214
- laser.setAttribute('animation', {
215
- property: 'scale',
216
- to: '1 0.01 1',
217
- dur: 1000,
218
- easing: 'linear'
219
- });
220
-
221
- setTimeout(() => {
222
- scene.removeChild(laser);
223
- }, 1000);
224
-
225
- // Check for enemy or spawner hit
226
- if (source === player) {
227
- const targets = document.querySelectorAll('.enemy, .spawner');
228
- targets.forEach(target => {
229
- const targetPos = target.object3D.position;
230
- const distance = sourcePosition.distanceTo(targetPos);
231
- if (distance < 2) {
232
- if (target.classList.contains('enemy')) {
233
- createExplosion(targetPos);
234
- scene.removeChild(target);
235
- enemies.delete(target);
236
- score += 10;
237
- } else if (target.classList.contains('spawner')) {
238
- target.health -= 20;
239
- if (target.health <= 0) {
240
- createExplosion(targetPos);
241
- scene.removeChild(target);
242
- spawners.delete(target);
243
- score += 50;
244
- }
245
- }
246
- updateScoreDisplay();
247
- updateUnitCounters();
248
- }
249
- });
250
- }
251
-
252
- // Check for player hit
253
- if (source !== player && Math.random() < 0.1) { // 10% chance to hit player
254
- health = Math.max(0, health - 10);
255
- updateHealthDisplay();
256
- }
257
- }
258
-
259
- function createExplosion(position) {
260
- const explosion = document.createElement('a-entity');
261
- explosion.setAttribute('position', position);
262
-
263
- for (let i = 0; i < 20; i++) {
264
- const particle = document.createElement('a-sphere');
265
- particle.setAttribute('radius', 0.1);
266
- particle.setAttribute('material', {color: '#FFA500'});
267
-
268
- const x = (Math.random() - 0.5) * 2;
269
- const y = (Math.random() - 0.5) * 2;
270
- const z = (Math.random() - 0.5) * 2;
271
-
272
- particle.setAttribute('animation', {
273
- property: 'position',
274
- to: `${x} ${y} ${z}`,
275
- dur: 1000,
276
- easing: 'easeOutQuad'
277
- });
278
-
279
- particle.setAttribute('animation__opacity', {
280
- property: 'material.opacity',
281
- from: 1,
282
- to: 0,
283
- dur: 1000,
284
- easing: 'easeOutQuad'
285
- });
286
-
287
- explosion.appendChild(particle);
288
- }
289
-
290
- scene.appendChild(explosion);
291
-
292
- setTimeout(() => {
293
- scene.removeChild(explosion);
294
- }, 1000);
295
-
296
- explosionCount++;
297
- updateUnitCounters();
298
- }
299
-
300
- function updateGame() {
301
- const now = Date.now();
302
- enemies.forEach(enemy => {
303
- if (now - enemy.creationTime > 20000) { // Remove after 20 seconds
304
- scene.removeChild(enemy);
305
- enemies.delete(enemy);
306
- updateUnitCounters();
307
- }
308
- });
309
-
310
- while (spawners.size < 5) {
311
- createSpawner();
312
- }
313
- }
314
 
315
  // Editor functionality
316
  let selectedObject = null;
317
  let isGameMode = true;
 
318
 
319
- function addPrimitive(type) {
320
- if (isGameMode) return; // Don't add primitives in game mode
321
-
322
- const scene = document.querySelector('a-scene');
323
- const newEntity = document.createElement('a-entity');
324
- newEntity.setAttribute('geometry', `primitive: ${type}`);
325
- newEntity.setAttribute('material', 'color: #4CC3D9');
326
- newEntity.setAttribute('position', '0 1.5 -3');
327
- newEntity.setAttribute('class', 'editable');
328
- newEntity.addEventListener('click', function() { selectObject(this); });
329
- scene.appendChild(newEntity);
330
- }
331
-
332
- function selectObject(obj) {
333
- if (selectedObject) {
334
- selectedObject.setAttribute('material', 'color', '#4CC3D9');
335
- }
336
- selectedObject = obj;
337
- selectedObject.setAttribute('material', 'color', '#FF0000');
338
- }
339
-
340
- function applyAnimation() {
341
- if (!selectedObject) {
342
- alert('Please select an object first');
343
- return;
344
- }
345
-
346
- const vx = parseFloat(document.getElementById('vx').value) || 0;
347
- const vy = parseFloat(document.getElementById('vy').value) || 0;
348
- const vz = parseFloat(document.getElementById('vz').value) || 0;
349
- const rx = parseFloat(document.getElementById('rx').value) || 0;
350
- const ry = parseFloat(document.getElementById('ry').value) || 0;
351
- const rz = parseFloat(document.getElementById('rz').value) || 0;
352
-
353
- let currentPosition = selectedObject.getAttribute('position');
354
-
355
- selectedObject.setAttribute('animation__position', {
356
- property: 'position',
357
- dur: 1000,
358
- dir: 'alternate',
359
- loop: true,
360
- to: `${currentPosition.x + vx} ${currentPosition.y + vy} ${currentPosition.z + vz}`,
361
- easing: 'linear'
362
- });
363
-
364
- selectedObject.setAttribute('animation__rotation', {
365
- property: 'rotation',
366
- dur: 1000,
367
- dir: 'alternate',
368
- loop: true,
369
- to: `${rx} ${ry} ${rz}`,
370
- easing: 'linear'
371
- });
372
- }
373
-
374
- function toggleGameMode() {
375
- isGameMode = !isGameMode;
376
  const cursor = document.querySelector('#cursor');
377
- if (isGameMode) {
378
- cursor.setAttribute('raycaster', 'objects', '.enemy, .spawner');
379
- } else {
380
- cursor.setAttribute('raycaster', 'objects', '.editable');
381
- }
382
  }
383
 
384
- // Modify the click event listener to work with both game and edit modes
385
- document.addEventListener('keydown', (event) => {
386
- if (event.code === 'Space') {
387
- fireLaser(player, '#00FF00');
388
- }
389
- });
390
-
391
- scene.addEventListener('click', (event) => {
392
- if (isGameMode) {
393
- fireLaser(player, '#00FF00');
394
- } else if (event.detail.intersectedEl && event.detail.intersectedEl.classList.contains('editable')) {
395
- selectObject(event.detail.intersectedEl);
396
- }
397
- });
398
-
399
- // Initialize the game
400
- update<!DOCTYPE html>
401
- <html>
402
- <head>
403
- <meta charset="utf-8">
404
- <title>A-Frame Space Shooter with Simple 3D Editor</title>
405
- <script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
406
- <style>
407
- .ui-panel {
408
- position: fixed;
409
- top: 20px;
410
- left: 20px;
411
- z-index: 9999;
412
- background: rgba(0,0,0,0.7);
413
- padding: 10px;
414
- border-radius: 5px;
415
- color: white;
416
- font-family: Arial, sans-serif;
417
- }
418
- .ui-panel button {
419
- display: block;
420
- margin: 5px 0;
421
- padding: 5px 10px;
422
- }
423
- .animation-panel {
424
- position: fixed;
425
- top: 20px;
426
- right: 20px;
427
- z-index: 9999;
428
- background: rgba(0,0,0,0.7);
429
- padding: 10px;
430
- border-radius: 5px;
431
- color: white;
432
- font-family: Arial, sans-serif;
433
- }
434
- .animation-panel input {
435
- width: 50px;
436
- margin-right: 5px;
437
- }
438
- </style>
439
- </head>
440
- <body>
441
- <div class="ui-panel">
442
- <button onclick="addPrimitive('box')">Add Box</button>
443
- <button onclick="toggleGameMode()">Toggle Game Mode</button>
444
- </div>
445
-
446
- <div class="animation-panel">
447
- <h3>Animation Controls</h3>
448
- <p>Velocity:</p>
449
- <input id="vx" type="number" placeholder="X">
450
- <input id="vy" type="number" placeholder="Y">
451
- <input id="vz" type="number" placeholder="Z">
452
- <p>Rotation (degrees):</p>
453
- <input id="rx" type="number" placeholder="X">
454
- <input id="ry" type="number" placeholder="Y">
455
- <input id="rz" type="number" placeholder="Z">
456
- <button onclick="applyAnimation()">Apply Animation</button>
457
- </div>
458
-
459
- <a-scene fog="type: linear; color: #87CEEB; near: 0; far: 50">
460
- <a-sky color="#87CEEB"></a-sky>
461
- <a-entity id="player" position="0 1.6 0">
462
- <a-entity camera look-controls wasd-controls>
463
- <a-entity id="cursor" cursor="fuse: false;" position="0 0 -1"
464
- geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
465
- material="color: white; shader: flat"
466
- raycaster="objects: .enemy, .spawner, .editable"></a-entity>
467
- </a-entity>
468
- </a-entity>
469
- <a-entity id="scoreBar" position="0 3 -5">
470
- <a-box width="1" height="0.1" depth="0.1" color="#444444"></a-box>
471
- <a-box id="scoreIndicator" width="1" height="0.1" depth="0.1" color="#FFA500" scale="0 1 1"></a-box>
472
- <a-text value="Score" position="0 0.1 0" align="center" color="white"></a-text>
473
- </a-entity>
474
- <a-entity id="healthDisplay" position="0 2.5 -5" scale="5 5 5"></a-entity>
475
- <a-entity id="unitCounters" position="-0.8 0.6 -1.5" scale="0.5 0.5 0.5"></a-entity>
476
- </a-scene>
477
-
478
- <script>
479
- const scene = document.querySelector('a-scene');
480
- const player = document.querySelector('#player');
481
- const scoreIndicator = document.querySelector('#scoreIndicator');
482
- const healthDisplay = document.querySelector('#healthDisplay');
483
- const unitCounters = document.querySelector('#unitCounters');
484
- let score = 0;
485
- let health = 100;
486
- let enemies = new Set();
487
- let spawners = new Set();
488
- let explosionCount = 0;
489
- const maxScore = 1000; // Maximum score for full bar
490
-
491
- function updateScoreDisplay() {
492
- const scale = Math.min(score / maxScore, 1);
493
- scoreIndicator.setAttribute('scale', `${scale} 1 1`);
494
- }
495
-
496
- function updateHealthDisplay() {
497
- healthDisplay.setAttribute('text', {
498
- value: `Health: ${health}`,
499
- color: 'white',
500
- align: 'center'
501
- });
502
- }
503
-
504
- function updateUnitCounters() {
505
- unitCounters.innerHTML = '';
506
- const counters = [
507
- {name: 'Enemies', count: enemies.size},
508
- {name: 'Spawners', count: spawners.size},
509
- {name: 'Explosions', count: explosionCount}
510
- ];
511
-
512
- counters.forEach((counter, index) => {
513
- const text = document.createElement('a-text');
514
- text.setAttribute('value', `${counter.name}: ${counter.count}`);
515
- text.setAttribute('color', 'white');
516
- text.setAttribute('position', `0 ${-index * 0.2} 0`);
517
- unitCounters.appendChild(text);
518
- });
519
- }
520
-
521
- function createSpawner() {
522
- const spawner = document.createElement('a-entity');
523
- spawner.setAttribute('class', 'spawner');
524
- spawner.setAttribute('geometry', {primitive: 'box', width: 2, height: 2, depth: 2});
525
- spawner.setAttribute('material', {color: '#00FF00', metalness: 0.7, roughness: 0.3});
526
-
527
- const angle = Math.random() * Math.PI * 2;
528
- const distance = 30;
529
- const position = new THREE.Vector3(
530
- Math.cos(angle) * distance,
531
- Math.random() * 10 - 5,
532
- Math.sin(angle) * distance
533
- );
534
- spawner.setAttribute('position', position);
535
-
536
- spawner.health = 100;
537
-
538
- scene.appendChild(spawner);
539
- spawners.add(spawner);
540
-
541
- // Spawner behavior
542
- setInterval(() => {
543
- if (spawner.parentNode && spawner.health > 0) {
544
- createEnemy(spawner.object3D.position);
545
- }
546
- }, 5000);
547
-
548
- updateUnitCounters();
549
- }
550
-
551
- function createEnemy(spawnPosition) {
552
- if (enemies.size >= 30) return; // Limit number of enemies
553
-
554
- const enemy = document.createElement('a-entity');
555
- enemy.setAttribute('class', 'enemy');
556
- enemy.setAttribute('geometry', {primitive: 'sphere', radius: 0.5});
557
- enemy.setAttribute('material', {color: '#FF0000', metalness: 0.7, roughness: 0.3});
558
-
559
- const position = new THREE.Vector3(
560
- spawnPosition.x + (Math.random() - 0.5) * 2,
561
- spawnPosition.y + (Math.random() - 0.5) * 2,
562
- spawnPosition.z + (Math.random() - 0.5) * 2
563
- );
564
- enemy.setAttribute('position', position);
565
-
566
- const particleSystem = document.createElement('a-entity');
567
- particleSystem.setAttribute('particle-system', {
568
- preset: 'dust',
569
- particleCount: 100,
570
- color: '#FF0000, #FF5500',
571
- size: 0.1,
572
- dur: 1000,
573
- accelerationValue: '0 -9.8 0'
574
- });
575
- enemy.appendChild(particleSystem);
576
-
577
- enemy.creationTime = Date.now();
578
-
579
- scene.appendChild(enemy);
580
- enemies.add(enemy);
581
-
582
- // Enemy firing behavior
583
- enemy.setAttribute('animation__movement', {
584
- property: 'position',
585
- to: '0 1.6 0',
586
- dur: 15000,
587
- easing: 'linear'
588
- });
589
-
590
- setInterval(() => {
591
- if (enemy.parentNode) {
592
- fireLaser(enemy, '#FF0000');
593
- }
594
- }, 2000);
595
-
596
- updateUnitCounters();
597
- }
598
-
599
- function fireLaser(source, color) {
600
- const laser = document.createElement('a-entity');
601
- laser.setAttribute('geometry', {primitive: 'cylinder', radius: 0.05, height: 100});
602
- laser.setAttribute('material', {color: color, opacity: 0.7});
603
-
604
- const sourcePosition = source.object3D.position;
605
- const targetPosition = player.object3D.position;
606
- const direction = new THREE.Vector3().subVectors(targetPosition, sourcePosition).normalize();
607
-
608
- laser.setAttribute('position', sourcePosition);
609
- laser.object3D.lookAt(targetPosition);
610
-
611
- scene.appendChild(laser);
612
-
613
- laser.setAttribute('animation', {
614
- property: 'scale',
615
- to: '1 0.01 1',
616
- dur: 1000,
617
- easing: 'linear'
618
- });
619
-
620
- setTimeout(() => {
621
- scene.removeChild(laser);
622
- }, 1000);
623
-
624
- // Check for enemy or spawner hit
625
- if (source === player) {
626
- const targets = document.querySelectorAll('.enemy, .spawner');
627
- targets.forEach(target => {
628
- const targetPos = target.object3D.position;
629
- const distance = sourcePosition.distanceTo(targetPos);
630
- if (distance < 2) {
631
- if (target.classList.contains('enemy')) {
632
- createExplosion(targetPos);
633
- scene.removeChild(target);
634
- enemies.delete(target);
635
- score += 10;
636
- } else if (target.classList.contains('spawner')) {
637
- target.health -= 20;
638
- if (target.health <= 0) {
639
- createExplosion(targetPos);
640
- scene.removeChild(target);
641
- spawners.delete(target);
642
- score += 50;
643
- }
644
- }
645
- updateScoreDisplay();
646
- updateUnitCounters();
647
- }
648
- });
649
- }
650
-
651
- // Check for player hit
652
- if (source !== player && Math.random() < 0.1) { // 10% chance to hit player
653
- health = Math.max(0, health - 10);
654
- updateHealthDisplay();
655
- }
656
- }
657
-
658
- function createExplosion(position) {
659
- const explosion = document.createElement('a-entity');
660
- explosion.setAttribute('position', position);
661
-
662
- for (let i = 0; i < 20; i++) {
663
- const particle = document.createElement('a-sphere');
664
- particle.setAttribute('radius', 0.1);
665
- particle.setAttribute('material', {color: '#FFA500'});
666
-
667
- const x = (Math.random() - 0.5) * 2;
668
- const y = (Math.random() - 0.5) * 2;
669
- const z = (Math.random() - 0.5) * 2;
670
-
671
- particle.setAttribute('animation', {
672
- property: 'position',
673
- to: `${x} ${y} ${z}`,
674
- dur: 1000,
675
- easing: 'easeOutQuad'
676
- });
677
-
678
- particle.setAttribute('animation__opacity', {
679
- property: 'material.opacity',
680
- from: 1,
681
- to: 0,
682
- dur: 1000,
683
- easing: 'easeOutQuad'
684
- });
685
-
686
- explosion.appendChild(particle);
687
- }
688
-
689
- scene.appendChild(explosion);
690
-
691
- setTimeout(() => {
692
- scene.removeChild(explosion);
693
- }, 1000);
694
-
695
- explosionCount++;
696
- updateUnitCounters();
697
- }
698
-
699
- function updateGame() {
700
- const now = Date.now();
701
- enemies.forEach(enemy => {
702
- if (now - enemy.creationTime > 20000) { // Remove after 20 seconds
703
- scene.removeChild(enemy);
704
- enemies.delete(enemy);
705
- updateUnitCounters();
706
- }
707
- });
708
-
709
- while (spawners.size < 5) {
710
- createSpawner();
711
- }
712
- }
713
-
714
- // Editor functionality
715
- let selectedObject = null;
716
- let isGameMode = true;
717
-
718
- function addPrimitive(type) {
719
- if (isGameMode) return; // Don't add primitives in game mode
720
-
721
  const scene = document.querySelector('a-scene');
722
  const newEntity = document.createElement('a-entity');
723
  newEntity.setAttribute('geometry', `primitive: ${type}`);
724
  newEntity.setAttribute('material', 'color: #4CC3D9');
725
- newEntity.setAttribute('position', '0 1.5 -3');
726
  newEntity.setAttribute('class', 'editable');
727
  newEntity.addEventListener('click', function() { selectObject(this); });
728
  scene.appendChild(newEntity);
 
729
  }
730
 
731
  function selectObject(obj) {
@@ -776,20 +158,19 @@
776
  if (isGameMode) {
777
  cursor.setAttribute('raycaster', 'objects', '.enemy, .spawner');
778
  } else {
779
- cursor.setAttribute('raycaster', 'objects', '.editable');
780
  }
781
  }
782
 
783
  // Modify the click event listener to work with both game and edit modes
784
- document.addEventListener('keydown', (event) => {
785
- if (event.code === 'Space') {
786
- fireLaser(player, '#00FF00');
787
- }
788
- });
789
-
790
- scene.addEventListener('click', (event) => {
791
  if (isGameMode) {
792
  fireLaser(player, '#00FF00');
 
 
 
 
 
793
  } else if (event.detail.intersectedEl && event.detail.intersectedEl.classList.contains('editable')) {
794
  selectObject(event.detail.intersectedEl);
795
  }
 
2
  <html>
3
  <head>
4
  <meta charset="utf-8">
5
+ <title>A-Frame Space Shooter with 3D Editor and Raycast Placement</title>
6
  <script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
7
  <style>
8
  .ui-panel {
 
40
  </head>
41
  <body>
42
  <div class="ui-panel">
43
+ <button onclick="setPlacementMode('box')">Add Box</button>
44
+ <button onclick="setPlacementMode('sphere')">Add Sphere</button>
45
+ <button onclick="setPlacementMode('cylinder')">Add Cylinder</button>
46
+ <button onclick="setPlacementMode('cone')">Add Cone</button>
47
+ <button onclick="setPlacementMode('torus')">Add Torus</button>
48
  <button onclick="toggleGameMode()">Toggle Game Mode</button>
49
  </div>
50
 
 
68
  <a-entity id="cursor" cursor="fuse: false;" position="0 0 -1"
69
  geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
70
  material="color: white; shader: flat"
71
+ raycaster="objects: .enemy, .spawner, .editable, [ground]"></a-entity>
72
  </a-entity>
73
  </a-entity>
74
  <a-entity id="scoreBar" position="0 3 -5">
 
78
  </a-entity>
79
  <a-entity id="healthDisplay" position="0 2.5 -5" scale="5 5 5"></a-entity>
80
  <a-entity id="unitCounters" position="-0.8 0.6 -1.5" scale="0.5 0.5 0.5"></a-entity>
81
+
82
+ <!-- Add a large ground plane for raycasting -->
83
+ <a-plane position="0 0 0" rotation="-90 0 0" width="1000" height="1000" color="#7BC8A4" ground></a-plane>
84
  </a-scene>
85
 
86
  <script>
87
+ // ... [All the game logic from the previous script goes here] ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  // Editor functionality
90
  let selectedObject = null;
91
  let isGameMode = true;
92
+ let placementMode = null;
93
 
94
+ function setPlacementMode(type) {
95
+ placementMode = type;
96
+ isGameMode = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  const cursor = document.querySelector('#cursor');
98
+ cursor.setAttribute('raycaster', 'objects', '.editable, [ground]');
 
 
 
 
99
  }
100
 
101
+ function addPrimitive(type, position) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  const scene = document.querySelector('a-scene');
103
  const newEntity = document.createElement('a-entity');
104
  newEntity.setAttribute('geometry', `primitive: ${type}`);
105
  newEntity.setAttribute('material', 'color: #4CC3D9');
106
+ newEntity.setAttribute('position', position);
107
  newEntity.setAttribute('class', 'editable');
108
  newEntity.addEventListener('click', function() { selectObject(this); });
109
  scene.appendChild(newEntity);
110
+ placementMode = null;
111
  }
112
 
113
  function selectObject(obj) {
 
158
  if (isGameMode) {
159
  cursor.setAttribute('raycaster', 'objects', '.enemy, .spawner');
160
  } else {
161
+ cursor.setAttribute('raycaster', 'objects', '.editable, [ground]');
162
  }
163
  }
164
 
165
  // Modify the click event listener to work with both game and edit modes
166
+ document.querySelector('a-scene').addEventListener('click', (event) => {
 
 
 
 
 
 
167
  if (isGameMode) {
168
  fireLaser(player, '#00FF00');
169
+ } else if (placementMode) {
170
+ const intersection = event.detail.intersection;
171
+ if (intersection) {
172
+ addPrimitive(placementMode, intersection.point);
173
+ }
174
  } else if (event.detail.intersectedEl && event.detail.intersectedEl.classList.contains('editable')) {
175
  selectObject(event.detail.intersectedEl);
176
  }