Spaces:
Running
Running
Update game.js
Browse files
game.js
CHANGED
@@ -1779,82 +1779,78 @@ class Game {
|
|
1779 |
}
|
1780 |
|
1781 |
setupEventListeners() {
|
1782 |
-
|
1783 |
-
|
1784 |
-
|
1785 |
-
|
1786 |
-
|
1787 |
-
|
1788 |
-
|
1789 |
-
|
1790 |
-
|
1791 |
-
|
1792 |
-
|
1793 |
-
|
1794 |
-
|
1795 |
-
|
1796 |
-
|
1797 |
-
|
1798 |
-
|
1799 |
-
|
1800 |
-
|
1801 |
-
|
1802 |
-
|
1803 |
-
|
1804 |
-
|
1805 |
-
|
1806 |
-
|
1807 |
-
|
1808 |
-
}
|
1809 |
-
});
|
1810 |
|
1811 |
-
|
1812 |
-
|
1813 |
-
|
1814 |
-
|
1815 |
-
|
1816 |
-
|
1817 |
-
|
1818 |
-
|
1819 |
-
|
1820 |
-
|
1821 |
-
|
1822 |
-
|
1823 |
-
}
|
1824 |
-
});
|
1825 |
|
1826 |
-
|
1827 |
-
|
1828 |
-
|
1829 |
-
|
1830 |
-
|
1831 |
-
|
1832 |
-
|
1833 |
-
|
1834 |
-
});
|
1835 |
|
1836 |
-
|
1837 |
-
|
1838 |
-
|
1839 |
-
|
1840 |
-
|
1841 |
-
|
1842 |
-
|
1843 |
-
}
|
1844 |
-
});
|
1845 |
|
1846 |
-
|
1847 |
-
|
1848 |
-
|
1849 |
-
|
1850 |
-
|
1851 |
|
1852 |
-
|
1853 |
-
|
1854 |
-
|
1855 |
-
|
1856 |
-
|
1857 |
-
}
|
1858 |
|
1859 |
startGame() {
|
1860 |
if (!this.isLoaded) {
|
@@ -2519,72 +2515,88 @@ class Game {
|
|
2519 |
animateImpact();
|
2520 |
|
2521 |
// ์์ ์ถฉ๋์
|
2522 |
-
|
2523 |
-
|
2524 |
-
|
2525 |
-
|
2526 |
-
|
2527 |
-
|
2528 |
-
|
2529 |
-
|
|
|
2530 |
}
|
2531 |
-
|
2532 |
checkCollisions() {
|
2533 |
-
|
2534 |
-
|
2535 |
-
|
2536 |
-
|
2537 |
-
|
2538 |
-
|
2539 |
-
|
2540 |
-
|
2541 |
-
const distance = bullet.position.distanceTo(enemy.position);
|
2542 |
-
if (distance < 90) {
|
2543 |
-
// ํํธ ํ์ ์ถ๊ฐ
|
2544 |
-
this.showHitMarker(enemy.position);
|
2545 |
-
// ํผ๊ฒฉ ์ดํํธ ์ถ๊ฐ
|
2546 |
-
this.createHitEffect(enemy.position);
|
2547 |
-
|
2548 |
-
// ํํ ์ ๊ฑฐ๋ ์ดํํธ ์์ฑ ํ์
|
2549 |
-
this.scene.remove(bullet);
|
2550 |
-
this.fighter.bullets.splice(i, 1);
|
2551 |
|
2552 |
-
|
2553 |
-
|
2554 |
-
|
|
|
|
|
|
|
|
|
|
|
2555 |
|
2556 |
-
|
2557 |
-
this.
|
2558 |
-
this.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2559 |
}
|
2560 |
-
break;
|
2561 |
}
|
2562 |
}
|
2563 |
-
|
2564 |
-
|
2565 |
-
|
2566 |
-
|
2567 |
-
|
2568 |
-
|
2569 |
-
|
2570 |
-
|
2571 |
-
|
2572 |
-
this.createHitEffect(this.fighter.position);
|
2573 |
-
|
2574 |
-
// ํํ ์ ๊ฑฐ
|
2575 |
-
this.scene.remove(bullet);
|
2576 |
-
enemy.bullets.splice(index, 1);
|
2577 |
-
|
2578 |
-
if (this.fighter.takeDamage(GAME_CONSTANTS.BULLET_DAMAGE)) {
|
2579 |
-
// ํ๋ ์ด์ด ํ๊ดด ์ ํญ๋ฐ ํจ๊ณผ ์ถ๊ฐ
|
2580 |
-
this.createExplosionEffect(this.fighter.position);
|
2581 |
|
2582 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2583 |
}
|
2584 |
}
|
2585 |
-
}
|
2586 |
-
}
|
2587 |
-
}
|
2588 |
|
2589 |
createHitEffect(position) {
|
2590 |
// ํผ๊ฒฉ ํํฐํด ํจ๊ณผ ์์ฑ
|
@@ -2685,169 +2697,192 @@ class Game {
|
|
2685 |
}
|
2686 |
|
2687 |
createExplosionEffect(position) {
|
2688 |
-
|
2689 |
-
try {
|
2690 |
-
const explosionSound = new Audio('sounds/bang.ogg');
|
2691 |
-
explosionSound.volume = 1.0; // ์ต๋ ์๋
|
2692 |
|
2693 |
-
//
|
2694 |
-
|
2695 |
-
|
2696 |
-
|
2697 |
}
|
2698 |
-
|
2699 |
-
|
2700 |
-
|
2701 |
-
|
2702 |
-
|
2703 |
-
|
2704 |
-
|
2705 |
-
|
2706 |
-
|
2707 |
-
|
2708 |
-
|
2709 |
-
|
2710 |
-
|
2711 |
-
|
2712 |
-
|
2713 |
-
|
2714 |
-
|
2715 |
-
|
2716 |
-
|
2717 |
-
|
2718 |
-
|
2719 |
-
|
2720 |
-
|
2721 |
-
|
2722 |
-
|
2723 |
-
|
2724 |
-
|
2725 |
-
|
2726 |
-
const
|
2727 |
-
|
|
|
|
|
|
|
2728 |
transparent: true,
|
2729 |
opacity: 1.0
|
2730 |
});
|
2731 |
|
2732 |
-
const
|
2733 |
-
|
|
|
|
|
2734 |
|
2735 |
-
//
|
2736 |
-
|
2737 |
-
|
2738 |
-
(Math.random() - 0.5) * 200,
|
2739 |
-
(Math.random() - 0.5) * 200
|
2740 |
-
);
|
2741 |
-
debrisPiece.rotationSpeed = new THREE.Vector3(
|
2742 |
-
Math.random() * 10,
|
2743 |
-
Math.random() * 10,
|
2744 |
-
Math.random() * 10
|
2745 |
-
);
|
2746 |
-
debrisPiece.life = 2.0;
|
2747 |
|
2748 |
-
|
2749 |
-
|
2750 |
-
|
2751 |
-
|
2752 |
-
|
2753 |
-
|
2754 |
-
|
2755 |
-
|
2756 |
-
|
2757 |
-
|
2758 |
-
|
2759 |
-
|
2760 |
-
|
2761 |
-
|
2762 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2763 |
|
2764 |
-
|
2765 |
-
|
2766 |
-
|
2767 |
-
(Math.random() - 0.5) * 20,
|
2768 |
-
(Math.random() - 0.5) * 20,
|
2769 |
-
(Math.random() - 0.5) * 20
|
2770 |
-
));
|
2771 |
-
|
2772 |
-
smokePuff.velocity = new THREE.Vector3(
|
2773 |
-
(Math.random() - 0.5) * 50,
|
2774 |
-
Math.random() * 50 + 20,
|
2775 |
-
(Math.random() - 0.5) * 50
|
2776 |
-
);
|
2777 |
-
smokePuff.life = 3.0;
|
2778 |
|
2779 |
-
|
2780 |
-
|
2781 |
-
|
2782 |
-
|
2783 |
-
|
2784 |
-
|
2785 |
-
|
2786 |
-
|
2787 |
-
|
2788 |
-
|
2789 |
-
|
2790 |
-
|
2791 |
-
|
2792 |
-
|
2793 |
-
|
2794 |
-
|
2795 |
-
|
2796 |
-
|
2797 |
-
|
2798 |
-
|
2799 |
-
|
2800 |
-
|
2801 |
-
|
2802 |
-
|
2803 |
-
|
2804 |
-
|
2805 |
-
|
2806 |
-
|
2807 |
-
|
2808 |
-
// ํ์
|
2809 |
-
piece.rotation.x += piece.rotationSpeed.x * 0.02;
|
2810 |
-
piece.rotation.y += piece.rotationSpeed.y * 0.02;
|
2811 |
-
piece.rotation.z += piece.rotationSpeed.z * 0.02;
|
2812 |
-
|
2813 |
-
// ํ์ด๋ ์์
|
2814 |
-
piece.material.opacity = piece.life / 2;
|
2815 |
-
} else if (piece.parent) {
|
2816 |
-
this.scene.remove(piece);
|
2817 |
-
}
|
2818 |
-
});
|
2819 |
|
2820 |
-
//
|
2821 |
-
|
2822 |
-
|
|
|
|
|
|
|
|
|
|
|
2823 |
allDead = false;
|
2824 |
-
|
2825 |
-
|
2826 |
-
// ์์น ์
๋ฐ์ดํธ
|
2827 |
-
puff.position.add(puff.velocity.clone().multiplyScalar(0.02));
|
2828 |
-
|
2829 |
-
// ์์น ๊ฐ์
|
2830 |
-
puff.velocity.y *= 0.98;
|
2831 |
-
puff.velocity.x *= 0.98;
|
2832 |
-
puff.velocity.z *= 0.98;
|
2833 |
-
|
2834 |
-
// ํ์ฐ
|
2835 |
-
puff.scale.multiplyScalar(1.02);
|
2836 |
-
|
2837 |
-
// ํ์ด๋ ์์
|
2838 |
-
puff.material.opacity = (puff.life / 3) * 0.8;
|
2839 |
-
} else if (puff.parent) {
|
2840 |
-
this.scene.remove(puff);
|
2841 |
}
|
2842 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2843 |
|
2844 |
-
|
2845 |
-
|
2846 |
-
}
|
2847 |
-
};
|
2848 |
-
|
2849 |
-
animateExplosion();
|
2850 |
-
}
|
2851 |
|
2852 |
showHitMarker(position) {
|
2853 |
// ํํธ ๋ง์ปค div ์์ฑ
|
@@ -2900,101 +2935,101 @@ class Game {
|
|
2900 |
}
|
2901 |
|
2902 |
animate() {
|
2903 |
-
|
2904 |
-
|
2905 |
-
this.animationFrameId = requestAnimationFrame(() => this.animate());
|
2906 |
-
|
2907 |
-
const currentTime = performance.now();
|
2908 |
-
const deltaTime = Math.min((currentTime - this.lastTime) / 1000, 0.1);
|
2909 |
-
this.lastTime = currentTime;
|
2910 |
-
|
2911 |
-
if (this.isLoaded && this.fighter.isLoaded && this.isStarted) {
|
2912 |
-
// ํค ์ํ ๋๋ฒ๊น
|
2913 |
-
if (this.keys.w || this.keys.s || this.keys.a || this.keys.d) {
|
2914 |
-
console.log('animate() - Keys state:', this.keys);
|
2915 |
-
}
|
2916 |
-
|
2917 |
-
// Fํค ์ํ๋ฅผ Fighter์ ์ ๋ฌ
|
2918 |
-
this.fighter.escapeKeyPressed = this.keys.f;
|
2919 |
|
2920 |
-
|
2921 |
-
this.fighter.updateControls(this.keys, deltaTime);
|
2922 |
|
2923 |
-
|
2924 |
-
this.
|
|
|
2925 |
|
2926 |
-
|
2927 |
-
|
2928 |
-
|
2929 |
-
|
2930 |
-
if (this.fighter.isMouseDown) {
|
2931 |
-
const currentShootTime = Date.now();
|
2932 |
-
if (!this.lastShootTime || currentShootTime - this.lastShootTime >= 100) {
|
2933 |
-
this.fighter.shoot(this.scene);
|
2934 |
-
this.lastShootTime = currentShootTime;
|
2935 |
}
|
2936 |
-
|
2937 |
-
|
2938 |
-
|
2939 |
-
|
2940 |
-
|
2941 |
-
|
2942 |
-
|
2943 |
-
|
2944 |
-
|
2945 |
-
|
2946 |
-
|
2947 |
-
|
2948 |
-
|
2949 |
-
|
2950 |
-
|
2951 |
-
|
2952 |
-
|
2953 |
-
|
2954 |
-
|
2955 |
-
|
2956 |
}
|
2957 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2958 |
}
|
2959 |
|
2960 |
-
//
|
2961 |
-
this.
|
2962 |
-
|
2963 |
-
|
2964 |
-
|
2965 |
-
|
2966 |
-
this.
|
2967 |
}
|
2968 |
-
} else if (this.isLoaded && this.fighter.isLoaded) {
|
2969 |
-
// ๊ฒ์์ด ์์๋์ง ์์์ ๋๋ ๋ฌผ๋ฆฌ๋ ์
๋ฐ์ดํธ (์นด๋ฉ๋ผ ์์ง์์ ์ํด)
|
2970 |
-
this.fighter.updatePhysics(deltaTime);
|
2971 |
-
}
|
2972 |
-
|
2973 |
-
// ๊ตฌ๋ฆ ์ ๋๋ฉ์ด์
|
2974 |
-
if (this.clouds) {
|
2975 |
-
this.clouds.forEach(cloud => {
|
2976 |
-
cloud.userData.time += deltaTime;
|
2977 |
-
cloud.position.x += cloud.userData.driftSpeed;
|
2978 |
-
cloud.position.y = cloud.userData.initialY +
|
2979 |
-
Math.sin(cloud.userData.time * cloud.userData.floatSpeed) * 20;
|
2980 |
-
|
2981 |
-
const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
|
2982 |
-
if (cloud.position.x > mapLimit) cloud.position.x = -mapLimit;
|
2983 |
-
if (cloud.position.x < -mapLimit) cloud.position.x = mapLimit;
|
2984 |
-
});
|
2985 |
-
}
|
2986 |
-
|
2987 |
-
// ์นด๋ฉ๋ผ ์
๋ฐ์ดํธ
|
2988 |
-
if (this.fighter.isLoaded) {
|
2989 |
-
const targetCameraPos = this.fighter.getCameraPosition();
|
2990 |
-
const targetCameraTarget = this.fighter.getCameraTarget();
|
2991 |
|
2992 |
-
this.
|
2993 |
-
this.camera.lookAt(targetCameraTarget);
|
2994 |
}
|
2995 |
-
|
2996 |
-
this.renderer.render(this.scene, this.camera);
|
2997 |
-
}
|
2998 |
|
2999 |
endGame(victory = false, reason = "") {
|
3000 |
this.isGameOver = true;
|
|
|
1779 |
}
|
1780 |
|
1781 |
setupEventListeners() {
|
1782 |
+
document.addEventListener('keydown', (event) => {
|
1783 |
+
if (this.isGameOver) return;
|
1784 |
+
|
1785 |
+
if (!this.isStarted) return;
|
1786 |
+
|
1787 |
+
switch(event.code) {
|
1788 |
+
case 'KeyW':
|
1789 |
+
this.keys.w = true;
|
1790 |
+
console.log('W key pressed - Accelerating');
|
1791 |
+
break;
|
1792 |
+
case 'KeyA':
|
1793 |
+
this.keys.a = true;
|
1794 |
+
console.log('A key pressed - Turning left');
|
1795 |
+
break;
|
1796 |
+
case 'KeyS':
|
1797 |
+
this.keys.s = true;
|
1798 |
+
console.log('S key pressed - Decelerating');
|
1799 |
+
break;
|
1800 |
+
case 'KeyD':
|
1801 |
+
this.keys.d = true;
|
1802 |
+
console.log('D key pressed - Turning right');
|
1803 |
+
break;
|
1804 |
+
case 'KeyF':
|
1805 |
+
this.keys.f = true;
|
1806 |
+
break;
|
1807 |
+
}
|
1808 |
+
});
|
|
|
1809 |
|
1810 |
+
document.addEventListener('keyup', (event) => {
|
1811 |
+
if (this.isGameOver) return;
|
1812 |
+
|
1813 |
+
if (!this.isStarted) return;
|
1814 |
+
|
1815 |
+
switch(event.code) {
|
1816 |
+
case 'KeyW': this.keys.w = false; break;
|
1817 |
+
case 'KeyA': this.keys.a = false; break;
|
1818 |
+
case 'KeyS': this.keys.s = false; break;
|
1819 |
+
case 'KeyD': this.keys.d = false; break;
|
1820 |
+
case 'KeyF': this.keys.f = false; break;
|
1821 |
+
}
|
1822 |
+
});
|
|
|
1823 |
|
1824 |
+
document.addEventListener('mousemove', (event) => {
|
1825 |
+
if (!document.pointerLockElement || this.isGameOver || !this.isStarted) return;
|
1826 |
+
|
1827 |
+
const deltaX = event.movementX || 0;
|
1828 |
+
const deltaY = event.movementY || 0;
|
1829 |
+
|
1830 |
+
this.fighter.updateMouseInput(deltaX, deltaY);
|
1831 |
+
});
|
|
|
1832 |
|
1833 |
+
document.addEventListener('mousedown', (event) => {
|
1834 |
+
if (!document.pointerLockElement || this.isGameOver || !this.isStarted) return;
|
1835 |
+
|
1836 |
+
if (event.button === 0) {
|
1837 |
+
this.fighter.isMouseDown = true;
|
1838 |
+
this.lastShootTime = 0;
|
1839 |
+
}
|
1840 |
+
});
|
|
|
1841 |
|
1842 |
+
document.addEventListener('mouseup', (event) => {
|
1843 |
+
if (event.button === 0) {
|
1844 |
+
this.fighter.isMouseDown = false;
|
1845 |
+
}
|
1846 |
+
});
|
1847 |
|
1848 |
+
window.addEventListener('resize', () => {
|
1849 |
+
this.camera.aspect = window.innerWidth / window.innerHeight;
|
1850 |
+
this.camera.updateProjectionMatrix();
|
1851 |
+
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
1852 |
+
});
|
1853 |
+
}
|
1854 |
|
1855 |
startGame() {
|
1856 |
if (!this.isLoaded) {
|
|
|
2515 |
animateImpact();
|
2516 |
|
2517 |
// ์์ ์ถฉ๋์
|
2518 |
+
try {
|
2519 |
+
const impactSound = new Audio('sounds/hit.ogg');
|
2520 |
+
impactSound.volume = 0.2;
|
2521 |
+
impactSound.play().catch(e => {
|
2522 |
+
console.log('Impact sound not found or failed to play');
|
2523 |
+
});
|
2524 |
+
} catch (e) {
|
2525 |
+
console.log('Impact sound error:', e);
|
2526 |
+
}
|
2527 |
}
|
2528 |
+
|
2529 |
checkCollisions() {
|
2530 |
+
// ํ๋ ์ด์ด ํํ vs ์ ๊ธฐ ์ถฉ๋
|
2531 |
+
for (let i = this.fighter.bullets.length - 1; i >= 0; i--) {
|
2532 |
+
const bullet = this.fighter.bullets[i];
|
2533 |
+
|
2534 |
+
for (let j = this.enemies.length - 1; j >= 0; j--) {
|
2535 |
+
const enemy = this.enemies[j];
|
2536 |
+
if (!enemy.mesh || !enemy.isLoaded) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2537 |
|
2538 |
+
const distance = bullet.position.distanceTo(enemy.position);
|
2539 |
+
if (distance < 90) {
|
2540 |
+
console.log(`Hit detected! Distance: ${distance}, Enemy health: ${enemy.health}`);
|
2541 |
+
|
2542 |
+
// ํํธ ํ์ ์ถ๊ฐ
|
2543 |
+
this.showHitMarker(enemy.position);
|
2544 |
+
// ํผ๊ฒฉ ์ดํํธ ์ถ๊ฐ
|
2545 |
+
this.createHitEffect(enemy.position);
|
2546 |
|
2547 |
+
// ํํ ์ ๊ฑฐ
|
2548 |
+
this.scene.remove(bullet);
|
2549 |
+
this.fighter.bullets.splice(i, 1);
|
2550 |
+
|
2551 |
+
// ์ ๊ธฐ์ ๋ฐ๋ฏธ์ง ์
ํ๊ธฐ
|
2552 |
+
const isDestroyed = enemy.takeDamage(GAME_CONSTANTS.BULLET_DAMAGE);
|
2553 |
+
console.log(`Enemy damaged. New health: ${enemy.health}, Destroyed: ${isDestroyed}`);
|
2554 |
+
|
2555 |
+
if (isDestroyed) {
|
2556 |
+
console.log('Enemy destroyed! Creating explosion effect...');
|
2557 |
+
|
2558 |
+
// ํญ๋ฐ ํจ๊ณผ ์์ฑ - ์์น๋ฅผ ๋ณต์ฌํด์ ์ ๋ฌ
|
2559 |
+
const explosionPosition = enemy.position.clone();
|
2560 |
+
console.log('Explosion position:', explosionPosition);
|
2561 |
+
|
2562 |
+
// ํญ๋ฐ ํจ๊ณผ ์ฆ์ ์์ฑ
|
2563 |
+
this.createExplosionEffect(explosionPosition);
|
2564 |
+
|
2565 |
+
// ์ ๊ธฐ ์ ๊ฑฐ
|
2566 |
+
enemy.destroy();
|
2567 |
+
this.enemies.splice(j, 1);
|
2568 |
+
this.score += 100;
|
2569 |
+
|
2570 |
+
console.log(`Enemy removed. Remaining enemies: ${this.enemies.length}`);
|
2571 |
+
}
|
2572 |
+
break;
|
2573 |
}
|
|
|
2574 |
}
|
2575 |
}
|
2576 |
+
|
2577 |
+
// ์ ํํ vs ํ๋ ์ด์ด ์ถฉ๋
|
2578 |
+
this.enemies.forEach(enemy => {
|
2579 |
+
for (let index = enemy.bullets.length - 1; index >= 0; index--) {
|
2580 |
+
const bullet = enemy.bullets[index];
|
2581 |
+
const distance = bullet.position.distanceTo(this.fighter.position);
|
2582 |
+
if (distance < 100) {
|
2583 |
+
// ํ๋ ์ด์ด ํผ๊ฒฉ ์ดํํธ
|
2584 |
+
this.createHitEffect(this.fighter.position);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2585 |
|
2586 |
+
// ํํ ์ ๊ฑฐ
|
2587 |
+
this.scene.remove(bullet);
|
2588 |
+
enemy.bullets.splice(index, 1);
|
2589 |
+
|
2590 |
+
if (this.fighter.takeDamage(GAME_CONSTANTS.BULLET_DAMAGE)) {
|
2591 |
+
// ํ๋ ์ด์ด ํ๊ดด ์ ํญ๋ฐ ํจ๊ณผ ์ถ๊ฐ
|
2592 |
+
this.createExplosionEffect(this.fighter.position);
|
2593 |
+
|
2594 |
+
this.endGame(false);
|
2595 |
+
}
|
2596 |
}
|
2597 |
}
|
2598 |
+
});
|
2599 |
+
}
|
|
|
2600 |
|
2601 |
createHitEffect(position) {
|
2602 |
// ํผ๊ฒฉ ํํฐํด ํจ๊ณผ ์์ฑ
|
|
|
2697 |
}
|
2698 |
|
2699 |
createExplosionEffect(position) {
|
2700 |
+
console.log('createExplosionEffect called with position:', position);
|
|
|
|
|
|
|
2701 |
|
2702 |
+
// ์์น๊ฐ ์ ํจํ์ง ํ์ธ
|
2703 |
+
if (!position || typeof position.x === 'undefined') {
|
2704 |
+
console.error('Invalid position for explosion effect');
|
2705 |
+
return;
|
2706 |
}
|
2707 |
+
|
2708 |
+
// ํญ๋ฐ์์ ๊ฐ์ฅ ๋จผ์ ์ฌ์ (์๊ฐํจ๊ณผ๋ณด๋ค ์ฐ์ )
|
2709 |
+
try {
|
2710 |
+
const explosionSound = new Audio('sounds/bang.ogg');
|
2711 |
+
explosionSound.volume = 1.0; // ์ต๋ ์๋
|
2712 |
+
|
2713 |
+
// ํ๋ ์ด์ด์์ ๊ฑฐ๋ฆฌ์ ๋ฐ๋ฅธ ๋ณผ๋ฅจ ์กฐ์
|
2714 |
+
if (this.fighter && this.fighter.position) {
|
2715 |
+
const distanceToPlayer = position.distanceTo(this.fighter.position);
|
2716 |
+
const maxAudibleDistance = 5000;
|
2717 |
+
if (distanceToPlayer < maxAudibleDistance) {
|
2718 |
+
explosionSound.volume = Math.max(0.3, 1.0 - (distanceToPlayer / maxAudibleDistance));
|
2719 |
+
console.log(`Explosion sound volume: ${explosionSound.volume} (distance: ${distanceToPlayer})`);
|
2720 |
+
}
|
2721 |
+
}
|
2722 |
+
|
2723 |
+
// ์ฆ์ ์ฌ์ ์๋
|
2724 |
+
const playPromise = explosionSound.play();
|
2725 |
+
if (playPromise !== undefined) {
|
2726 |
+
playPromise
|
2727 |
+
.then(() => console.log('Explosion sound played successfully'))
|
2728 |
+
.catch(e => console.error('Explosion sound failed:', e));
|
2729 |
+
}
|
2730 |
+
} catch (e) {
|
2731 |
+
console.error('Explosion sound error:', e);
|
2732 |
+
}
|
2733 |
+
|
2734 |
+
// ๋ฉ์ธ ํญ๋ฐ ํ๋์
|
2735 |
+
const explosionGeometry = new THREE.SphereGeometry(50, 16, 16);
|
2736 |
+
const explosionMaterial = new THREE.MeshBasicMaterial({
|
2737 |
+
color: 0xffaa00,
|
2738 |
+
emissive: 0xffaa00,
|
2739 |
+
emissiveIntensity: 3.0,
|
2740 |
transparent: true,
|
2741 |
opacity: 1.0
|
2742 |
});
|
2743 |
|
2744 |
+
const explosion = new THREE.Mesh(explosionGeometry, explosionMaterial);
|
2745 |
+
explosion.position.copy(position);
|
2746 |
+
this.scene.add(explosion);
|
2747 |
+
console.log('Explosion mesh added to scene');
|
2748 |
|
2749 |
+
// ํญ๋ฐ ํํธ๋ค
|
2750 |
+
const debrisCount = 30;
|
2751 |
+
const debris = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2752 |
|
2753 |
+
for (let i = 0; i < debrisCount; i++) {
|
2754 |
+
const debrisGeometry = new THREE.BoxGeometry(
|
2755 |
+
2 + Math.random() * 4,
|
2756 |
+
2 + Math.random() * 4,
|
2757 |
+
2 + Math.random() * 4
|
2758 |
+
);
|
2759 |
+
const debrisMaterial = new THREE.MeshBasicMaterial({
|
2760 |
+
color: Math.random() > 0.5 ? 0xff6600 : 0x333333,
|
2761 |
+
transparent: true,
|
2762 |
+
opacity: 1.0
|
2763 |
+
});
|
2764 |
+
|
2765 |
+
const debrisPiece = new THREE.Mesh(debrisGeometry, debrisMaterial);
|
2766 |
+
debrisPiece.position.copy(position);
|
2767 |
+
|
2768 |
+
// ๋๋ค ์๋์ ํ์
|
2769 |
+
debrisPiece.velocity = new THREE.Vector3(
|
2770 |
+
(Math.random() - 0.5) * 200,
|
2771 |
+
(Math.random() - 0.5) * 200,
|
2772 |
+
(Math.random() - 0.5) * 200
|
2773 |
+
);
|
2774 |
+
debrisPiece.rotationSpeed = new THREE.Vector3(
|
2775 |
+
Math.random() * 10,
|
2776 |
+
Math.random() * 10,
|
2777 |
+
Math.random() * 10
|
2778 |
+
);
|
2779 |
+
debrisPiece.life = 2.0;
|
2780 |
+
|
2781 |
+
this.scene.add(debrisPiece);
|
2782 |
+
debris.push(debrisPiece);
|
2783 |
+
}
|
2784 |
|
2785 |
+
// ์ฐ๊ธฐ ํจ๊ณผ
|
2786 |
+
const smokeCount = 10;
|
2787 |
+
const smoke = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2788 |
|
2789 |
+
for (let i = 0; i < smokeCount; i++) {
|
2790 |
+
const smokeGeometry = new THREE.SphereGeometry(10 + Math.random() * 20, 8, 8);
|
2791 |
+
const smokeMaterial = new THREE.MeshBasicMaterial({
|
2792 |
+
color: 0x222222,
|
2793 |
+
transparent: true,
|
2794 |
+
opacity: 0.8
|
2795 |
+
});
|
2796 |
+
|
2797 |
+
const smokePuff = new THREE.Mesh(smokeGeometry, smokeMaterial);
|
2798 |
+
smokePuff.position.copy(position);
|
2799 |
+
smokePuff.position.add(new THREE.Vector3(
|
2800 |
+
(Math.random() - 0.5) * 20,
|
2801 |
+
(Math.random() - 0.5) * 20,
|
2802 |
+
(Math.random() - 0.5) * 20
|
2803 |
+
));
|
2804 |
+
|
2805 |
+
smokePuff.velocity = new THREE.Vector3(
|
2806 |
+
(Math.random() - 0.5) * 50,
|
2807 |
+
Math.random() * 50 + 20,
|
2808 |
+
(Math.random() - 0.5) * 50
|
2809 |
+
);
|
2810 |
+
smokePuff.life = 3.0;
|
2811 |
+
|
2812 |
+
this.scene.add(smokePuff);
|
2813 |
+
smoke.push(smokePuff);
|
2814 |
+
}
|
2815 |
+
|
2816 |
+
console.log(`Explosion effect created with ${debrisCount} debris and ${smokeCount} smoke particles`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2817 |
|
2818 |
+
// ์ ๋๋ฉ์ด์
|
2819 |
+
const animateExplosion = () => {
|
2820 |
+
let allDead = true;
|
2821 |
+
|
2822 |
+
// ๋ฉ์ธ ํญ๋ฐ ์ ๋๋ฉ์ด์
|
2823 |
+
if (explosion.material.opacity > 0) {
|
2824 |
+
explosion.material.opacity -= 0.02;
|
2825 |
+
explosion.scale.multiplyScalar(1.08);
|
2826 |
allDead = false;
|
2827 |
+
} else if (explosion.parent) {
|
2828 |
+
this.scene.remove(explosion);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2829 |
}
|
2830 |
+
|
2831 |
+
// ํํธ ์ ๋๋ฉ์ด์
|
2832 |
+
debris.forEach(piece => {
|
2833 |
+
if (piece.life > 0) {
|
2834 |
+
allDead = false;
|
2835 |
+
piece.life -= 0.02;
|
2836 |
+
|
2837 |
+
// ์์น ์
๋ฐ์ดํธ
|
2838 |
+
piece.position.add(piece.velocity.clone().multiplyScalar(0.02));
|
2839 |
+
|
2840 |
+
// ์ค๋ ฅ
|
2841 |
+
piece.velocity.y -= 3;
|
2842 |
+
|
2843 |
+
// ํ์
|
2844 |
+
piece.rotation.x += piece.rotationSpeed.x * 0.02;
|
2845 |
+
piece.rotation.y += piece.rotationSpeed.y * 0.02;
|
2846 |
+
piece.rotation.z += piece.rotationSpeed.z * 0.02;
|
2847 |
+
|
2848 |
+
// ํ์ด๋ ์์
|
2849 |
+
piece.material.opacity = piece.life / 2;
|
2850 |
+
} else if (piece.parent) {
|
2851 |
+
this.scene.remove(piece);
|
2852 |
+
}
|
2853 |
+
});
|
2854 |
+
|
2855 |
+
// ์ฐ๊ธฐ ์ ๋๋ฉ์ด์
|
2856 |
+
smoke.forEach(puff => {
|
2857 |
+
if (puff.life > 0) {
|
2858 |
+
allDead = false;
|
2859 |
+
puff.life -= 0.02;
|
2860 |
+
|
2861 |
+
// ์์น ์
๋ฐ์ดํธ
|
2862 |
+
puff.position.add(puff.velocity.clone().multiplyScalar(0.02));
|
2863 |
+
|
2864 |
+
// ์์น ๊ฐ์
|
2865 |
+
puff.velocity.y *= 0.98;
|
2866 |
+
puff.velocity.x *= 0.98;
|
2867 |
+
puff.velocity.z *= 0.98;
|
2868 |
+
|
2869 |
+
// ํ์ฐ
|
2870 |
+
puff.scale.multiplyScalar(1.02);
|
2871 |
+
|
2872 |
+
// ํ์ด๋ ์์
|
2873 |
+
puff.material.opacity = (puff.life / 3) * 0.8;
|
2874 |
+
} else if (puff.parent) {
|
2875 |
+
this.scene.remove(puff);
|
2876 |
+
}
|
2877 |
+
});
|
2878 |
+
|
2879 |
+
if (!allDead) {
|
2880 |
+
requestAnimationFrame(animateExplosion);
|
2881 |
+
}
|
2882 |
+
};
|
2883 |
|
2884 |
+
animateExplosion();
|
2885 |
+
}
|
|
|
|
|
|
|
|
|
|
|
2886 |
|
2887 |
showHitMarker(position) {
|
2888 |
// ํํธ ๋ง์ปค div ์์ฑ
|
|
|
2935 |
}
|
2936 |
|
2937 |
animate() {
|
2938 |
+
if (this.isGameOver) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2939 |
|
2940 |
+
this.animationFrameId = requestAnimationFrame(() => this.animate());
|
|
|
2941 |
|
2942 |
+
const currentTime = performance.now();
|
2943 |
+
const deltaTime = Math.min((currentTime - this.lastTime) / 1000, 0.1);
|
2944 |
+
this.lastTime = currentTime;
|
2945 |
|
2946 |
+
if (this.isLoaded && this.fighter.isLoaded && this.isStarted) {
|
2947 |
+
// ํค ์ํ ๋๋ฒ๊น
|
2948 |
+
if (this.keys.w || this.keys.s || this.keys.a || this.keys.d) {
|
2949 |
+
console.log('animate() - Keys state:', this.keys);
|
|
|
|
|
|
|
|
|
|
|
2950 |
}
|
2951 |
+
|
2952 |
+
// Fํค ์ํ๋ฅผ Fighter์ ์ ๋ฌ
|
2953 |
+
this.fighter.escapeKeyPressed = this.keys.f;
|
2954 |
+
|
2955 |
+
// ์ปจํธ๋กค ์
๋ฐ์ดํธ - ๋ฐ๋์ ๋ฌผ๋ฆฌ ์
๋ฐ์ดํธ ์ ์ ํธ์ถ
|
2956 |
+
this.fighter.updateControls(this.keys, deltaTime);
|
2957 |
+
|
2958 |
+
// ๋ฌผ๋ฆฌ ์
๋ฐ์ดํธ
|
2959 |
+
this.fighter.updatePhysics(deltaTime);
|
2960 |
+
|
2961 |
+
// ํํ ์
๋ฐ์ดํธ
|
2962 |
+
this.fighter.updateBullets(this.scene, deltaTime, this);
|
2963 |
+
|
2964 |
+
// ๋ง์ฐ์ค ๋๋ฆ ์ํ์ผ ๋ ์ฐ์ ๋ฐ์ฌ
|
2965 |
+
if (this.fighter.isMouseDown) {
|
2966 |
+
const currentShootTime = Date.now();
|
2967 |
+
if (!this.lastShootTime || currentShootTime - this.lastShootTime >= 100) {
|
2968 |
+
this.fighter.shoot(this.scene);
|
2969 |
+
this.lastShootTime = currentShootTime;
|
2970 |
+
}
|
2971 |
}
|
2972 |
+
|
2973 |
+
// ์ ๊ธฐ ์
๋ฐ์ดํธ
|
2974 |
+
this.enemies.forEach(enemy => {
|
2975 |
+
enemy.nearbyEnemies = this.enemies;
|
2976 |
+
});
|
2977 |
+
|
2978 |
+
this.enemies.forEach(enemy => {
|
2979 |
+
enemy.update(this.fighter.position, deltaTime);
|
2980 |
+
});
|
2981 |
+
|
2982 |
+
// ์ถฉ๋ ์ฒดํฌ
|
2983 |
+
this.checkCollisions();
|
2984 |
+
|
2985 |
+
// ๊ฒ์ ์ข
๋ฃ ์กฐ๊ฑด ์ฒดํฌ
|
2986 |
+
if (this.fighter.health <= 0) {
|
2987 |
+
if (this.fighter.position.y <= 0) {
|
2988 |
+
this.endGame(false, "GROUND COLLISION");
|
2989 |
+
} else {
|
2990 |
+
this.endGame(false);
|
2991 |
+
}
|
2992 |
+
return;
|
2993 |
+
}
|
2994 |
+
|
2995 |
+
// UI ์
๋ฐ์ดํธ
|
2996 |
+
this.updateUI();
|
2997 |
+
this.updateRadar();
|
2998 |
+
|
2999 |
+
// ์ ์ด ๋ชจ๋ ์ ๊ฑฐ๋์๋์ง ์ฒดํฌ
|
3000 |
+
if (this.enemies.length === 0) {
|
3001 |
+
this.endGame(true);
|
3002 |
+
}
|
3003 |
+
} else if (this.isLoaded && this.fighter.isLoaded) {
|
3004 |
+
// ๊ฒ์์ด ์์๋์ง ์์์ ๋๋ ๋ฌผ๋ฆฌ๋ ์
๋ฐ์ดํธ (์นด๋ฉ๋ผ ์์ง์์ ์ํด)
|
3005 |
+
this.fighter.updatePhysics(deltaTime);
|
3006 |
+
}
|
3007 |
+
|
3008 |
+
// ๊ตฌ๋ฆ ์ ๋๋ฉ์ด์
|
3009 |
+
if (this.clouds) {
|
3010 |
+
this.clouds.forEach(cloud => {
|
3011 |
+
cloud.userData.time += deltaTime;
|
3012 |
+
cloud.position.x += cloud.userData.driftSpeed;
|
3013 |
+
cloud.position.y = cloud.userData.initialY +
|
3014 |
+
Math.sin(cloud.userData.time * cloud.userData.floatSpeed) * 20;
|
3015 |
+
|
3016 |
+
const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
|
3017 |
+
if (cloud.position.x > mapLimit) cloud.position.x = -mapLimit;
|
3018 |
+
if (cloud.position.x < -mapLimit) cloud.position.x = mapLimit;
|
3019 |
+
});
|
3020 |
}
|
3021 |
|
3022 |
+
// ์นด๋ฉ๋ผ ์
๋ฐ์ดํธ
|
3023 |
+
if (this.fighter.isLoaded) {
|
3024 |
+
const targetCameraPos = this.fighter.getCameraPosition();
|
3025 |
+
const targetCameraTarget = this.fighter.getCameraTarget();
|
3026 |
+
|
3027 |
+
this.camera.position.lerp(targetCameraPos, this.fighter.cameraLag);
|
3028 |
+
this.camera.lookAt(targetCameraTarget);
|
3029 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3030 |
|
3031 |
+
this.renderer.render(this.scene, this.camera);
|
|
|
3032 |
}
|
|
|
|
|
|
|
3033 |
|
3034 |
endGame(victory = false, reason = "") {
|
3035 |
this.isGameOver = true;
|