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;
|