File size: 12,564 Bytes
a1053b7
a579c53
a1053b7
 
fc6e612
a1053b7
 
 
 
3a0edc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1053b7
 
 
b699375
3a0edc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b699375
1f71a34
f149649
208d931
d244154
208d931
 
d244154
b699375
fc6e612
1f71a34
 
3a0edc7
1f71a34
 
 
 
3a0edc7
1f71a34
3a0edc7
1f71a34
208d931
a1053b7
fc6e612
208d931
f149649
d244154
5e53152
 
 
208d931
5e53152
 
 
 
 
208d931
5e53152
 
208d931
 
 
 
 
 
 
a1053b7
 
3a0edc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e53152
208d931
 
1f71a34
5e53152
 
a1053b7
 
fc6e612
 
a1053b7
b699375
a1053b7
 
fc6e612
 
 
0999d43
fc6e612
 
 
 
 
 
5e53152
208d931
1f71a34
5e53152
fc6e612
 
 
3a0edc7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fc6e612
 
3a0edc7
 
 
 
 
b699375
a1053b7
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Advanced A-Frame 3D Space Shooter Game</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/aframe/1.2.0/aframe.min.js"></script>
</head>
<body>
    <a-scene fog="type: linear; color: #87CEEB; near: 0; far: 50">
        <a-assets>
            <a-asset-item id="model1" src="1.obj"></a-asset-item>
            <a-asset-item id="model2" src="2.obj"></a-asset-item>
            <a-asset-item id="model3" src="3.obj"></a-asset-item>
            <a-asset-item id="model4" src="4.obj"></a-asset-item>
            <a-asset-item id="model5" src="5.obj"></a-asset-item>
            <a-asset-item id="model6" src="6.obj"></a-asset-item>
            <a-asset-item id="model7" src="7.obj"></a-asset-item>
            <a-asset-item id="model8" src="8.obj"></a-asset-item>
            <a-asset-item id="model9" src="9.obj"></a-asset-item>
            <a-asset-item id="model10" src="10.obj"></a-asset-item>
        </a-assets>
        <a-sky color="#87CEEB"></a-sky>
        <a-entity id="player" position="0 1.6 0">
            <a-entity camera look-controls wasd-controls>
                <a-entity id="cursor" cursor="fuse: false;" position="0 0 -1"
                          geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
                          material="color: white; shader: flat"
                          raycaster="objects: .enemy, .spawner"></a-entity>
            </a-entity>
        </a-entity>
        <a-entity id="scoreBar" position="-2 3 -5">
            <a-box width="2" height="0.2" depth="0.1" color="#444444"></a-box>
            <a-box id="scoreIndicator" width="2" height="0.2" depth="0.1" color="#FFA500" scale="0 1 1"></a-box>
            <a-text value="Score" position="0 -0.3 0" align="center" color="white"></a-text>
        </a-entity>
        <a-entity id="healthBar" position="2 3 -5">
            <a-box width="2" height="0.2" depth="0.1" color="#444444"></a-box>
            <a-box id="healthIndicator" width="2" height="0.2" depth="0.1" color="#00FF00" scale="1 1 1"></a-box>
            <a-text value="Health" position="0 -0.3 0" align="center" color="white"></a-text>
        </a-entity>
        <a-entity id="spawnCounter" position="0 3 -5">
            <a-text value="Spawn Points: 0" align="center" color="white"></a-text>
        </a-entity>
    </a-scene>

    <script>
    (function() {
        const scene = document.querySelector('a-scene');
        const player = document.querySelector('#player');
        const camera = document.querySelector('[camera]');
        const cursor = document.querySelector('#cursor');
        const scoreIndicator = document.querySelector('#scoreIndicator');
        const healthIndicator = document.querySelector('#healthIndicator');
        const spawnCounter = document.querySelector('#spawnCounter');
        let score = 0, health = 10000, enemies = new Set(), spawners = new Set(), explosionCount = 0;
        const maxScore = 1000;

        function updateDisplays() {
            scoreIndicator.setAttribute('scale', `${Math.min(score / maxScore, 1)} 1 1`);
            healthIndicator.setAttribute('scale', `${Math.max(health / 10000, 0)} 1 1`);
            spawnCounter.setAttribute('text', `value: Spawn Points: ${spawners.size}`);
        }

        function createEntity(type, attributes) {
            const entity = document.createElement('a-entity');
            Object.entries(attributes).forEach(([key, value]) => entity.setAttribute(key, value));
            scene.appendChild(entity);
            return entity;
        }

        function generateSpawnerPosition() {
            const angle = Math.random() * Math.PI * 2;
            const distance = 10 + Math.random() * 10; // Spawn between 10 and 20 units away
            return new THREE.Vector3(
                Math.cos(angle) * distance,
                1.6, // Keep at player's eye level
                Math.sin(angle) * distance - 5 // Offset by -5 to spawn in front of scoreboard
            );
        }

        function createSpawner(position = null) {
            const modelNumber = Math.floor(Math.random() * 10) + 1;
            const spawner = createEntity('spawner', {
                class: 'spawner',
                'obj-model': `obj: #model${modelNumber}`,
                material: {color: '#00FF00', metalness: 0.7, roughness: 0.3},
                position: position || generateSpawnerPosition()
            });
            spawner.health = 100;
            spawners.add(spawner);
            updateDisplays();
        }

        function createEnemy(spawnPosition) {
            if (enemies.size >= 30) return;
            const enemy = createEntity('enemy', {
                class: 'enemy',
                geometry: {primitive: 'sphere', radius: 0.5},
                material: {color: '#FF0000', metalness: 0.7, roughness: 0.3, opacity: 0.5, transparent: true},
                position: new THREE.Vector3(
                    spawnPosition.x + (Math.random() - 0.5) * 2,
                    1.6, // Keep at player's eye level
                    spawnPosition.z + (Math.random() - 0.5) * 2
                )
            });
            enemy.appendChild(createEntity('particles', {
                'particle-system': {preset: 'dust', particleCount: 100, color: '#FF0000, #FF5500', size: 0.1, dur: 1000, accelerationValue: '0 -9.8 0'}
            }));
            enemy.creationTime = Date.now();
            enemies.add(enemy);
            updateDisplays();
        }

        function fireLaser(source, color, direction, isPlayer = false) {
            const sourcePosition = source.object3D.position.clone();
            sourcePosition.y = 1.6; // Ensure laser starts at eye level
            
            const laserLength = 100;
            const endPosition = sourcePosition.clone().add(direction.multiplyScalar(laserLength));
            
            const laser = createEntity('laser', {
                class: 'laser',
                geometry: {
                    primitive: 'cylinder', 
                    radius: isPlayer ? 0.2 : 0.1, // Player lasers are wider
                    height: laserLength
                },
                material: {
                    color: color, 
                    opacity: isPlayer ? 0.5 : 1, // Player lasers are semi-transparent
                    transparent: isPlayer,
                    shader: 'flat' // Ensures the laser color is not affected by lighting
                },
                position: sourcePosition.clone().add(direction.multiplyScalar(laserLength / 2))
            });
            
            laser.object3D.lookAt(endPosition);
            laser.object3D.rotateX(Math.PI / 2);
            
            laser.setAttribute('animation', {
                property: 'scale',
                to: '1 0.01 1',
                dur: 1000,
                easing: 'linear'
            });

            setTimeout(() => {
                scene.removeChild(laser);
            }, 1000);

            // Check for collisions
            const targets = document.querySelectorAll('.enemy, .spawner');
            targets.forEach(target => {
                const targetPos = target.object3D.position;
                if (isPointNearLine(sourcePosition, endPosition, targetPos, 0.5)) {
                    handleHit(target, targetPos);
                }
            });
        }

        function isPointNearLine(lineStart, lineEnd, point, threshold) {
            const lineVec = new THREE.Vector3().subVectors(lineEnd, lineStart);
            const pointVec = new THREE.Vector3().subVectors(point, lineStart);
            const lineLengthSq = lineVec.lengthSq();
            const dotProduct = pointVec.dot(lineVec);
            const t = Math.max(0, Math.min(1, dotProduct / lineLengthSq));
            const projection = lineStart.clone().add(lineVec.multiplyScalar(t));
            return point.distanceTo(projection) < threshold;
        }

        function handleHit(target, position) {
            if (target.classList.contains('enemy')) {
                createExplosion(position);
                scene.removeChild(target);
                enemies.delete(target);
                score += 10;
                health = Math.min(10000, health + 20);
            } else if (target.classList.contains('spawner')) {
                target.health -= 20;
                createExplosion(position);
                if (target.health <= 0) {
                    scene.removeChild(target);
                    spawners.delete(target);
                    score += 50;
                    createSpawner(generateSpawnerPosition());
                }
            }
            updateDisplays();
        }

        function createExplosion(position) {
            const explosion = createEntity('explosion', {position: position});
            for (let i = 0; i < 20; i++) {
                const particle = createEntity('particle', {
                    geometry: {primitive: 'sphere', radius: 0.1},
                    material: {color: '#FFA500'},
                    position: `${(Math.random() - 0.5) * 2} ${(Math.random() - 0.5) * 2} ${(Math.random() - 0.5) * 2}`
                });
                particle.setAttribute('animation', {property: 'position', to: `${(Math.random() - 0.5) * 2} ${(Math.random() - 0.5) * 2} ${(Math.random() - 0.5) * 2}`, dur: 1000, easing: 'easeOutQuad'});
                particle.setAttribute('animation__opacity', {property: 'material.opacity', from: 1, to: 0, dur: 1000, easing: 'easeOutQuad'});
                explosion.appendChild(particle);
            }
            setTimeout(() => scene.removeChild(explosion), 1000);
            explosionCount++;
            updateDisplays();
        }

        function shootFromCamera() {
            const direction = new THREE.Vector3(0, 0, -1);
            direction.applyQuaternion(camera.object3D.quaternion);
            fireLaser(camera, '#FFFF00', direction, true); // Yellow color for player laser
        }

        function updateGame() {
            const now = Date.now();
            const cameraPosition = camera.object3D.position;

            enemies.forEach(enemy => {
                if (now - enemy.creationTime > 20000) {
                    scene.removeChild(enemy);
                    enemies.delete(enemy);
                } else {
                    const direction = new THREE.Vector3().subVectors(cameraPosition, enemy.object3D.position).normalize();
                    enemy.object3D.position.add(direction.multiplyScalar(0.05));
                    enemy.object3D.position.y = 1.6; // Keep at player's eye level
                    if (enemy.object3D.position.distanceTo(cameraPosition) < 2) {
                        createExplosion(enemy.object3D.position);
                        scene.removeChild(enemy);
                        enemies.delete(enemy);
                        health = Math.max(0, health - 50);
                    }
                    if (Math.random() < 0.01) {
                        const enemyDirection = new THREE.Vector3().subVectors(cameraPosition, enemy.object3D.position).normalize();
                        fireLaser(enemy, '#000000', enemyDirection); // Black color for enemy laser
                    }
                }
            });

            spawners.forEach(spawner => {
                const direction = new THREE.Vector3().subVectors(cameraPosition, spawner.object3D.position).normalize();
                spawner.object3D.position.add(direction.multiplyScalar(0.02));
                spawner.object3D.position.y = 1.6; // Keep at player's eye level
                spawner.object3D.lookAt(cameraPosition);
                if (spawner.object3D.position.distanceTo(cameraPosition) < 3) {
                    createExplosion(spawner.object3D.position);
                    scene.removeChild(spawner);
                    spawners.delete(spawner);
                    health = Math.max(0, health - 100);
                }
                if (Math.random() < 0.005 && enemies.size < 30) {
                    createEnemy(spawner.object3D.position);
                }
            });

            while (spawners.size < 5) createSpawner();
            updateDisplays();
        }

        document.addEventListener('keydown', (event) => { if (event.code === 'Space') shootFromCamera(); });
        scene.addEventListener('click', shootFromCamera);

        updateDisplays();
        setInterval(updateGame, 1000 / 60);  // 60 FPS update
    })();
    </script>
</body>
</html>