Spaces:
Running
Running
gunship999
commited on
Commit
β’
48257cd
1
Parent(s):
d78b552
Update game.js
Browse files
game.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
import * as THREE from 'three';
|
|
|
2 |
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
|
3 |
|
4 |
// κ²μ μμ
|
@@ -117,7 +118,7 @@ async function init() {
|
|
117 |
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
118 |
dirLight.position.set(100, 100, 50);
|
119 |
dirLight.castShadow = true;
|
120 |
-
dirLight.shadow.mapSize.width = 1024;
|
121 |
dirLight.shadow.mapSize.height = 1024;
|
122 |
scene.add(dirLight);
|
123 |
|
@@ -127,6 +128,9 @@ async function init() {
|
|
127 |
// μ΄λ²€νΈ 리μ€λ
|
128 |
setupEventListeners();
|
129 |
|
|
|
|
|
|
|
130 |
// κ²μ μμ μ΄κΈ°ν
|
131 |
await Promise.all([
|
132 |
createTerrain(),
|
@@ -134,10 +138,15 @@ async function init() {
|
|
134 |
]);
|
135 |
|
136 |
document.getElementById('loading').style.display = 'none';
|
137 |
-
|
138 |
} catch (error) {
|
139 |
console.error('Initialization error:', error);
|
140 |
-
document.getElementById('loading').
|
|
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
}
|
143 |
|
@@ -148,10 +157,22 @@ function setupEventListeners() {
|
|
148 |
window.addEventListener('resize', onWindowResize);
|
149 |
}
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
function createTerrain() {
|
152 |
return new Promise((resolve) => {
|
153 |
-
|
154 |
-
const geometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100); // ν΄μλ κ°μ
|
155 |
const material = new THREE.MeshStandardMaterial({
|
156 |
color: 0xD2B48C,
|
157 |
roughness: 0.8,
|
@@ -171,7 +192,6 @@ function createTerrain() {
|
|
171 |
terrain.receiveShadow = true;
|
172 |
scene.add(terrain);
|
173 |
|
174 |
-
// μ΅μ νλ μ₯μ λ¬Ό μΆκ°
|
175 |
addObstacles();
|
176 |
resolve();
|
177 |
});
|
@@ -184,7 +204,6 @@ function addObstacles() {
|
|
184 |
roughness: 0.9
|
185 |
});
|
186 |
|
187 |
-
// μ₯μ λ¬Ό μ κ°μ
|
188 |
for (let i = 0; i < OBSTACLE_COUNT; i++) {
|
189 |
const rock = new THREE.Mesh(rockGeometry, rockMaterial);
|
190 |
rock.position.set(
|
@@ -203,7 +222,9 @@ function addObstacles() {
|
|
203 |
}
|
204 |
}
|
205 |
|
206 |
-
function createEnemies() {
|
|
|
|
|
207 |
const enemyCount = Math.min(3 + currentStage, ENEMY_COUNT_MAX);
|
208 |
|
209 |
for (let i = 0; i < enemyCount; i++) {
|
@@ -215,32 +236,59 @@ function createEnemies() {
|
|
215 |
Math.sin(angle) * radius
|
216 |
);
|
217 |
|
218 |
-
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
}
|
221 |
}
|
222 |
|
223 |
-
function
|
224 |
-
// κ°λ¨ν μ λͺ¨λΈ μμ±
|
225 |
const geometry = new THREE.BoxGeometry(5, 10, 5);
|
226 |
const material = new THREE.MeshPhongMaterial({
|
227 |
color: 0xff0000,
|
228 |
-
|
229 |
-
|
230 |
});
|
231 |
|
232 |
const model = new THREE.Mesh(geometry, material);
|
233 |
model.position.copy(position);
|
234 |
model.castShadow = true;
|
235 |
model.receiveShadow = true;
|
236 |
-
|
237 |
-
// μ μ£Όλ³μ λΉ μΆκ°
|
238 |
-
const light = new THREE.PointLight(0xff0000, 1, 10);
|
239 |
-
light.position.set(0, 5, 0);
|
240 |
-
model.add(light);
|
241 |
-
|
242 |
-
scene.add(model);
|
243 |
-
|
244 |
return {
|
245 |
model: model,
|
246 |
health: 100,
|
@@ -277,7 +325,6 @@ function createExplosion(position) {
|
|
277 |
explosionLight.position.copy(position);
|
278 |
scene.add(explosionLight);
|
279 |
|
280 |
-
// μ΅μ νλ μ λλ©μ΄μ
|
281 |
let opacity = 1;
|
282 |
const animate = () => {
|
283 |
opacity -= 0.05;
|
@@ -351,7 +398,7 @@ function shoot() {
|
|
351 |
|
352 |
gunSound.createGunshot();
|
353 |
|
354 |
-
//
|
355 |
const muzzleFlash = new THREE.PointLight(0xffff00, 3, 10);
|
356 |
muzzleFlash.position.copy(camera.position);
|
357 |
scene.add(muzzleFlash);
|
@@ -359,7 +406,6 @@ function shoot() {
|
|
359 |
}
|
360 |
|
361 |
function createBullet() {
|
362 |
-
// μ΅μ νλ μ΄μ μμ±
|
363 |
const bullet = new THREE.Mesh(
|
364 |
new THREE.SphereGeometry(0.5),
|
365 |
new THREE.MeshBasicMaterial({
|
@@ -457,7 +503,6 @@ function updateEnemyBullets() {
|
|
457 |
|
458 |
enemyBullets[i].position.add(enemyBullets[i].velocity);
|
459 |
|
460 |
-
// νλ μ΄μ΄μμ μΆ©λ κ²μ¬
|
461 |
if (enemyBullets[i].position.distanceTo(camera.position) < 3) {
|
462 |
playerHealth -= 10;
|
463 |
updateHealthBar();
|
@@ -471,7 +516,6 @@ function updateEnemyBullets() {
|
|
471 |
continue;
|
472 |
}
|
473 |
|
474 |
-
// λ²μ λ²μ΄λ μ΄μ μ κ±°
|
475 |
if (enemyBullets[i].position.distanceTo(camera.position) > 1000) {
|
476 |
scene.remove(enemyBullets[i]);
|
477 |
enemyBullets.splice(i, 1);
|
@@ -510,6 +554,12 @@ function updateEnemies() {
|
|
510 |
|
511 |
enemyBullets.push(createEnemyBullet(enemy));
|
512 |
enemy.lastAttackTime = currentTime;
|
|
|
|
|
|
|
|
|
|
|
|
|
513 |
}
|
514 |
});
|
515 |
}
|
@@ -588,7 +638,6 @@ function checkGameStatus() {
|
|
588 |
}
|
589 |
|
590 |
function cleanupResources() {
|
591 |
-
// 리μμ€ μ 리
|
592 |
bullets.forEach(bullet => scene.remove(bullet));
|
593 |
bullets = [];
|
594 |
|
@@ -634,32 +683,6 @@ function gameLoop(timestamp) {
|
|
634 |
renderer.render(scene, camera);
|
635 |
}
|
636 |
|
637 |
-
// λλ²κΉ
μ μν μ μ μ κ·Ό
|
638 |
-
window.debugGame = {
|
639 |
-
scene,
|
640 |
-
camera,
|
641 |
-
enemies,
|
642 |
-
gunSound,
|
643 |
-
reloadEnemies: createEnemies
|
644 |
-
};
|
645 |
-
|
646 |
-
// κ²μ μμ
|
647 |
-
window.addEventListener('load', async () => {
|
648 |
-
try {
|
649 |
-
await init();
|
650 |
-
console.log('Game started');
|
651 |
-
console.log('Active enemies:', enemies.length);
|
652 |
-
gameLoop(performance.now());
|
653 |
-
} catch (error) {
|
654 |
-
console.error('Game initialization error:', error);
|
655 |
-
document.getElementById('loading').innerHTML = `
|
656 |
-
<div class="loading-text" style="color: #ff0000;">
|
657 |
-
Error loading game. Please refresh.
|
658 |
-
</div>
|
659 |
-
`;
|
660 |
-
}
|
661 |
-
});
|
662 |
-
|
663 |
// μ±λ₯ λͺ¨λν°λ§
|
664 |
let lastFpsUpdate = 0;
|
665 |
let frameCount = 0;
|
@@ -678,4 +701,29 @@ function updateFPS(timestamp) {
|
|
678 |
requestAnimationFrame(updateFPS);
|
679 |
}
|
680 |
|
681 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import * as THREE from 'three';
|
2 |
+
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
|
3 |
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
|
4 |
|
5 |
// κ²μ μμ
|
|
|
118 |
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
119 |
dirLight.position.set(100, 100, 50);
|
120 |
dirLight.castShadow = true;
|
121 |
+
dirLight.shadow.mapSize.width = 1024;
|
122 |
dirLight.shadow.mapSize.height = 1024;
|
123 |
scene.add(dirLight);
|
124 |
|
|
|
128 |
// μ΄λ²€νΈ 리μ€λ
|
129 |
setupEventListeners();
|
130 |
|
131 |
+
// λͺ¨λΈ ν
μ€νΈ λ¨Όμ μ€ν
|
132 |
+
await testModelLoading();
|
133 |
+
|
134 |
// κ²μ μμ μ΄κΈ°ν
|
135 |
await Promise.all([
|
136 |
createTerrain(),
|
|
|
138 |
]);
|
139 |
|
140 |
document.getElementById('loading').style.display = 'none';
|
141 |
+
console.log('Game initialized successfully');
|
142 |
} catch (error) {
|
143 |
console.error('Initialization error:', error);
|
144 |
+
document.getElementById('loading').innerHTML = `
|
145 |
+
<div class="loading-text" style="color: #ff0000;">
|
146 |
+
Error loading models. Please check console and file paths.
|
147 |
+
</div>
|
148 |
+
`;
|
149 |
+
throw error;
|
150 |
}
|
151 |
}
|
152 |
|
|
|
157 |
window.addEventListener('resize', onWindowResize);
|
158 |
}
|
159 |
|
160 |
+
async function testModelLoading() {
|
161 |
+
const loader = new GLTFLoader();
|
162 |
+
try {
|
163 |
+
const modelPath = 'models/enemy1.glb';
|
164 |
+
console.log('Testing model loading:', modelPath);
|
165 |
+
const gltf = await loader.loadAsync(modelPath);
|
166 |
+
console.log('Test model loaded successfully:', gltf);
|
167 |
+
} catch (error) {
|
168 |
+
console.error('Test model loading failed:', error);
|
169 |
+
throw error;
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
function createTerrain() {
|
174 |
return new Promise((resolve) => {
|
175 |
+
const geometry = new THREE.PlaneGeometry(MAP_SIZE, MAP_SIZE, 100, 100);
|
|
|
176 |
const material = new THREE.MeshStandardMaterial({
|
177 |
color: 0xD2B48C,
|
178 |
roughness: 0.8,
|
|
|
192 |
terrain.receiveShadow = true;
|
193 |
scene.add(terrain);
|
194 |
|
|
|
195 |
addObstacles();
|
196 |
resolve();
|
197 |
});
|
|
|
204 |
roughness: 0.9
|
205 |
});
|
206 |
|
|
|
207 |
for (let i = 0; i < OBSTACLE_COUNT; i++) {
|
208 |
const rock = new THREE.Mesh(rockGeometry, rockMaterial);
|
209 |
rock.position.set(
|
|
|
222 |
}
|
223 |
}
|
224 |
|
225 |
+
async function createEnemies() {
|
226 |
+
console.log('Creating enemies...');
|
227 |
+
const loader = new GLTFLoader();
|
228 |
const enemyCount = Math.min(3 + currentStage, ENEMY_COUNT_MAX);
|
229 |
|
230 |
for (let i = 0; i < enemyCount; i++) {
|
|
|
236 |
Math.sin(angle) * radius
|
237 |
);
|
238 |
|
239 |
+
// μμ μ μμ±
|
240 |
+
const tempEnemy = createTemporaryEnemy(position);
|
241 |
+
scene.add(tempEnemy.model);
|
242 |
+
enemies.push(tempEnemy);
|
243 |
+
|
244 |
+
// GLB λͺ¨λΈ λ‘λ
|
245 |
+
try {
|
246 |
+
const modelIndex = i % 4 + 1;
|
247 |
+
const modelPath = `models/enemy${modelIndex}.glb`;
|
248 |
+
console.log(`Loading model: ${modelPath}`);
|
249 |
+
|
250 |
+
const gltf = await loader.loadAsync(modelPath);
|
251 |
+
const model = gltf.scene;
|
252 |
+
|
253 |
+
// λͺ¨λΈ μ€μ
|
254 |
+
model.scale.set(ENEMY_SCALE, ENEMY_SCALE, ENEMY_SCALE);
|
255 |
+
model.position.copy(position);
|
256 |
+
|
257 |
+
// λͺ¨λΈ μ¬μ§ λ° κ·Έλ¦Όμ μ€μ
|
258 |
+
model.traverse((node) => {
|
259 |
+
if (node.isMesh) {
|
260 |
+
node.castShadow = true;
|
261 |
+
node.receiveShadow = true;
|
262 |
+
node.material.metalness = 0.2;
|
263 |
+
node.material.roughness = 0.8;
|
264 |
+
}
|
265 |
+
});
|
266 |
+
|
267 |
+
// μμ λͺ¨λΈ κ΅μ²΄
|
268 |
+
scene.remove(tempEnemy.model);
|
269 |
+
scene.add(model);
|
270 |
+
enemies[enemies.indexOf(tempEnemy)].model = model;
|
271 |
+
|
272 |
+
console.log(`Successfully loaded enemy model ${modelIndex}`);
|
273 |
+
} catch (error) {
|
274 |
+
console.error(`Error loading enemy model:`, error);
|
275 |
+
}
|
276 |
}
|
277 |
}
|
278 |
|
279 |
+
function createTemporaryEnemy(position) {
|
|
|
280 |
const geometry = new THREE.BoxGeometry(5, 10, 5);
|
281 |
const material = new THREE.MeshPhongMaterial({
|
282 |
color: 0xff0000,
|
283 |
+
transparent: true,
|
284 |
+
opacity: 0.8
|
285 |
});
|
286 |
|
287 |
const model = new THREE.Mesh(geometry, material);
|
288 |
model.position.copy(position);
|
289 |
model.castShadow = true;
|
290 |
model.receiveShadow = true;
|
291 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
return {
|
293 |
model: model,
|
294 |
health: 100,
|
|
|
325 |
explosionLight.position.copy(position);
|
326 |
scene.add(explosionLight);
|
327 |
|
|
|
328 |
let opacity = 1;
|
329 |
const animate = () => {
|
330 |
opacity -= 0.05;
|
|
|
398 |
|
399 |
gunSound.createGunshot();
|
400 |
|
401 |
+
// μ΄κ΅¬ νμΌ ν¨κ³Ό
|
402 |
const muzzleFlash = new THREE.PointLight(0xffff00, 3, 10);
|
403 |
muzzleFlash.position.copy(camera.position);
|
404 |
scene.add(muzzleFlash);
|
|
|
406 |
}
|
407 |
|
408 |
function createBullet() {
|
|
|
409 |
const bullet = new THREE.Mesh(
|
410 |
new THREE.SphereGeometry(0.5),
|
411 |
new THREE.MeshBasicMaterial({
|
|
|
503 |
|
504 |
enemyBullets[i].position.add(enemyBullets[i].velocity);
|
505 |
|
|
|
506 |
if (enemyBullets[i].position.distanceTo(camera.position) < 3) {
|
507 |
playerHealth -= 10;
|
508 |
updateHealthBar();
|
|
|
516 |
continue;
|
517 |
}
|
518 |
|
|
|
519 |
if (enemyBullets[i].position.distanceTo(camera.position) > 1000) {
|
520 |
scene.remove(enemyBullets[i]);
|
521 |
enemyBullets.splice(i, 1);
|
|
|
554 |
|
555 |
enemyBullets.push(createEnemyBullet(enemy));
|
556 |
enemy.lastAttackTime = currentTime;
|
557 |
+
|
558 |
+
// 곡격 μ λ°κ΄ ν¨κ³Ό
|
559 |
+
const attackFlash = new THREE.PointLight(0xff0000, 2, 20);
|
560 |
+
attackFlash.position.copy(enemy.model.position);
|
561 |
+
scene.add(attackFlash);
|
562 |
+
setTimeout(() => scene.remove(attackFlash), 100);
|
563 |
}
|
564 |
});
|
565 |
}
|
|
|
638 |
}
|
639 |
|
640 |
function cleanupResources() {
|
|
|
641 |
bullets.forEach(bullet => scene.remove(bullet));
|
642 |
bullets = [];
|
643 |
|
|
|
683 |
renderer.render(scene, camera);
|
684 |
}
|
685 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
686 |
// μ±λ₯ λͺ¨λν°λ§
|
687 |
let lastFpsUpdate = 0;
|
688 |
let frameCount = 0;
|
|
|
701 |
requestAnimationFrame(updateFPS);
|
702 |
}
|
703 |
|
704 |
+
// κ²μ μμ
|
705 |
+
window.addEventListener('load', async () => {
|
706 |
+
try {
|
707 |
+
await init();
|
708 |
+
console.log('Game started');
|
709 |
+
console.log('Active enemies:', enemies.length);
|
710 |
+
gameLoop(performance.now());
|
711 |
+
updateFPS(performance.now());
|
712 |
+
} catch (error) {
|
713 |
+
console.error('Game initialization error:', error);
|
714 |
+
document.getElementById('loading').innerHTML = `
|
715 |
+
<div class="loading-text" style="color: #ff0000;">
|
716 |
+
Error loading game. Please check console and file paths.
|
717 |
+
</div>
|
718 |
+
`;
|
719 |
+
}
|
720 |
+
});
|
721 |
+
|
722 |
+
// λλ²κΉ
μ μν μ μ μ κ·Ό
|
723 |
+
window.debugGame = {
|
724 |
+
scene,
|
725 |
+
camera,
|
726 |
+
enemies,
|
727 |
+
gunSound,
|
728 |
+
reloadEnemies: createEnemies
|
729 |
+
};
|