Spaces:
Running
Running
Update game.js
Browse files
game.js
CHANGED
@@ -20,7 +20,6 @@ const GAME_CONSTANTS = {
|
|
20 |
MISSILE_COUNT: 6,
|
21 |
AMMO_COUNT: 940, // 940๋ฐ๋ก ๋ณ๊ฒฝ
|
22 |
BULLET_DAMAGE: 25, // ๋ฐ๋น 25 ๋ฐ๋ฏธ์ง
|
23 |
-
MISSILE_DAMAGE: 500, // ๋ฏธ์ฌ์ผ ๋ฐ๋ฏธ์ง
|
24 |
MAX_HEALTH: 1000 // ์ฒด๋ ฅ 1000
|
25 |
};
|
26 |
|
@@ -61,19 +60,10 @@ class Fighter {
|
|
61 |
this.missiles = GAME_CONSTANTS.MISSILE_COUNT;
|
62 |
this.ammo = GAME_CONSTANTS.AMMO_COUNT;
|
63 |
this.bullets = [];
|
64 |
-
this.activeMissiles = []; // ๋ฐ์ฌ๋ ๋ฏธ์ฌ์ผ
|
65 |
this.lastShootTime = 0;
|
66 |
this.isMouseDown = false; // ๋ง์ฐ์ค ๋๋ฆ ์ํ ์ถ์
|
67 |
this.gunfireAudios = []; // ๊ธฐ๊ด์ด ์๋ฆฌ ๋ฐฐ์ด (์ต๋ 5๊ฐ)
|
68 |
|
69 |
-
// ๋ฌด๊ธฐ ์์คํ
|
70 |
-
this.currentWeapon = 'mg'; // 'mg' or 'missile'
|
71 |
-
this.weaponCooldown = 0; // ๋ฌด๊ธฐ ์ฟจ๋ค์ด
|
72 |
-
this.missileTarget = null; // ๋ฏธ์ฌ์ผ ํ๊ฒ
|
73 |
-
this.missileLockTimer = 0; // ๋ฝ์จ ํ์ด๋จธ
|
74 |
-
this.missileLockCount = 0; // ๋ฝ์จ ์นด์ดํธ (3๋ฒ ํ์)
|
75 |
-
this.lastMissileFire = 0; // ๋ง์ง๋ง ๋ฏธ์ฌ์ผ ๋ฐ์ฌ ์๊ฐ
|
76 |
-
|
77 |
// ์คํจ ํ์ถ์ ์ํ Fํค ์ํ
|
78 |
this.escapeKeyPressed = false;
|
79 |
this.stallEscapeProgress = 0; // ์คํจ ํ์ถ ์งํ๋ (0~2์ด)
|
@@ -652,7 +642,6 @@ class Fighter {
|
|
652 |
}
|
653 |
|
654 |
updateBullets(scene, deltaTime) {
|
655 |
-
// ๊ธฐ๊ด์ด ํํ ์
๋ฐ์ดํธ
|
656 |
for (let i = this.bullets.length - 1; i >= 0; i--) {
|
657 |
const bullet = this.bullets[i];
|
658 |
bullet.position.add(bullet.velocity.clone().multiplyScalar(deltaTime));
|
@@ -670,204 +659,6 @@ class Fighter {
|
|
670 |
this.bullets.splice(i, 1);
|
671 |
}
|
672 |
}
|
673 |
-
|
674 |
-
// ๋ฏธ์ฌ์ผ ์
๋ฐ์ดํธ
|
675 |
-
for (let i = this.activeMissiles.length - 1; i >= 0; i--) {
|
676 |
-
const missile = this.activeMissiles[i];
|
677 |
-
|
678 |
-
if (missile.target && missile.target.mesh && missile.target.isLoaded) {
|
679 |
-
// ํ๊ฒ์ ํฅํด ์ ๋
|
680 |
-
const targetDirection = missile.target.position.clone().sub(missile.position).normalize();
|
681 |
-
|
682 |
-
// ๋ถ๋๋ฌ์ด ํ์ ์ ์ํ ๋ณด๊ฐ
|
683 |
-
missile.velocity.lerp(targetDirection.multiplyScalar(2000), deltaTime * 4); // ๋ฏธ์ฌ์ผ ์๋ 2000m/s
|
684 |
-
missile.velocity.normalize().multiplyScalar(2000);
|
685 |
-
|
686 |
-
// ๋ฏธ์ฌ์ผ ํ์
|
687 |
-
const missileDirection = missile.velocity.clone().normalize();
|
688 |
-
const angle = Math.atan2(missileDirection.x, missileDirection.z);
|
689 |
-
missile.rotation.y = angle;
|
690 |
-
missile.rotation.x = Math.asin(-missileDirection.y);
|
691 |
-
}
|
692 |
-
|
693 |
-
// ์์น ์
๋ฐ์ดํธ
|
694 |
-
missile.position.add(missile.velocity.clone().multiplyScalar(deltaTime));
|
695 |
-
|
696 |
-
// ์ฐ๊ธฐ ํจ๊ณผ ์ถ๊ฐ
|
697 |
-
if (Math.random() > 0.7) {
|
698 |
-
this.createMissileTrail(missile.position);
|
699 |
-
}
|
700 |
-
|
701 |
-
// 10km ์ด์ ๋ ์๊ฐ๊ฑฐ๋ ์ง๋ฉด ์ถฉ๋์ ์ ๊ฑฐ
|
702 |
-
if (missile.position.distanceTo(missile.startPosition) > 10000 ||
|
703 |
-
missile.position.y < 0 ||
|
704 |
-
missile.life > 10) { // 10์ด ํ ์๋ ํ๊ดด
|
705 |
-
scene.remove(missile);
|
706 |
-
this.activeMissiles.splice(i, 1);
|
707 |
-
} else {
|
708 |
-
missile.life += deltaTime;
|
709 |
-
}
|
710 |
-
}
|
711 |
-
}
|
712 |
-
|
713 |
-
createMissileTrail(position) {
|
714 |
-
const trailGeometry = new THREE.SphereGeometry(2, 4, 4);
|
715 |
-
const trailMaterial = new THREE.MeshBasicMaterial({
|
716 |
-
color: 0x888888,
|
717 |
-
transparent: true,
|
718 |
-
opacity: 0.6
|
719 |
-
});
|
720 |
-
|
721 |
-
const trail = new THREE.Mesh(trailGeometry, trailMaterial);
|
722 |
-
trail.position.copy(position);
|
723 |
-
|
724 |
-
this.mesh.parent.add(trail);
|
725 |
-
|
726 |
-
// ํ์ด๋ ์์ ์ ๋๋ฉ์ด์
|
727 |
-
const fadeOut = () => {
|
728 |
-
trail.material.opacity -= 0.02;
|
729 |
-
trail.scale.multiplyScalar(1.05);
|
730 |
-
|
731 |
-
if (trail.material.opacity > 0) {
|
732 |
-
requestAnimationFrame(fadeOut);
|
733 |
-
} else {
|
734 |
-
this.mesh.parent.remove(trail);
|
735 |
-
}
|
736 |
-
};
|
737 |
-
|
738 |
-
fadeOut();
|
739 |
-
}
|
740 |
-
|
741 |
-
shootMissile(scene, target) {
|
742 |
-
if (this.missiles <= 0 || !target || !target.mesh) return;
|
743 |
-
|
744 |
-
const currentTime = Date.now();
|
745 |
-
if (currentTime - this.lastMissileFire < 6000) return; // 6์ด ์ฟจ๋ค์ด
|
746 |
-
|
747 |
-
this.missiles--;
|
748 |
-
this.lastMissileFire = currentTime;
|
749 |
-
this.weaponCooldown = 6000; // 6์ด ์ฟจ๋ค์ด ์ค์
|
750 |
-
|
751 |
-
// ๋ฏธ์ฌ์ผ ๋ชจ๋ธ
|
752 |
-
const missileGeometry = new THREE.CylinderGeometry(0.3, 0.5, 4, 8);
|
753 |
-
const missileMaterial = new THREE.MeshBasicMaterial({
|
754 |
-
color: 0xcccccc,
|
755 |
-
emissive: 0xff6600,
|
756 |
-
emissiveIntensity: 0.5
|
757 |
-
});
|
758 |
-
const missile = new THREE.Mesh(missileGeometry, missileMaterial);
|
759 |
-
|
760 |
-
// ๋ ๊ฐ ์ถ๊ฐ
|
761 |
-
const wingGeometry = new THREE.BoxGeometry(2, 0.1, 0.5);
|
762 |
-
const wingMaterial = new THREE.MeshBasicMaterial({ color: 0x666666 });
|
763 |
-
const wing1 = new THREE.Mesh(wingGeometry, wingMaterial);
|
764 |
-
const wing2 = new THREE.Mesh(wingGeometry, wingMaterial);
|
765 |
-
wing1.position.z = -1;
|
766 |
-
wing2.position.z = -1;
|
767 |
-
wing2.rotation.z = Math.PI / 2;
|
768 |
-
missile.add(wing1);
|
769 |
-
missile.add(wing2);
|
770 |
-
|
771 |
-
// ๋ฏธ์ฌ์ผ ์ด๊ธฐ ์์น (๋ ๊ฐ ์๋์์ ๋ฐ์ฌ)
|
772 |
-
const launchOffset = new THREE.Vector3(0, -2, 5);
|
773 |
-
launchOffset.applyEuler(this.rotation);
|
774 |
-
missile.position.copy(this.position).add(launchOffset);
|
775 |
-
|
776 |
-
// ๋ฏธ์ฌ์ผ ์ด๊ธฐ ์๋
|
777 |
-
const direction = new THREE.Vector3(0, 0, 1);
|
778 |
-
direction.applyEuler(this.rotation);
|
779 |
-
missile.velocity = direction.multiplyScalar(1000); // ์ด๊ธฐ ์๋
|
780 |
-
|
781 |
-
missile.rotation.copy(this.rotation);
|
782 |
-
missile.rotateX(Math.PI / 2);
|
783 |
-
|
784 |
-
// ๋ฏธ์ฌ์ผ ์์ฑ
|
785 |
-
missile.target = target;
|
786 |
-
missile.startPosition = missile.position.clone();
|
787 |
-
missile.life = 0;
|
788 |
-
missile.type = 'missile';
|
789 |
-
|
790 |
-
scene.add(missile);
|
791 |
-
this.activeMissiles.push(missile);
|
792 |
-
|
793 |
-
// ๋ฐ์ฌ ์ฌ์ด๋
|
794 |
-
try {
|
795 |
-
const audio = new Audio('sounds/Towfirelaunch.ogg');
|
796 |
-
audio.volume = 0.6;
|
797 |
-
audio.play().catch(e => console.log('Missile launch sound not found'));
|
798 |
-
} catch (e) {
|
799 |
-
console.log('Audio error:', e);
|
800 |
-
}
|
801 |
-
|
802 |
-
// ๋ฝ์จ ์ด๊ธฐํ
|
803 |
-
this.missileTarget = null;
|
804 |
-
this.missileLockCount = 0;
|
805 |
-
this.missileLockTimer = 0;
|
806 |
-
}
|
807 |
-
|
808 |
-
updateMissileLock(enemies, deltaTime) {
|
809 |
-
if (this.currentWeapon !== 'missile' || this.missiles <= 0) {
|
810 |
-
this.missileTarget = null;
|
811 |
-
this.missileLockCount = 0;
|
812 |
-
return;
|
813 |
-
}
|
814 |
-
|
815 |
-
// ์ฟจ๋ค์ด ์
๋ฐ์ดํธ
|
816 |
-
if (this.weaponCooldown > 0) {
|
817 |
-
this.weaponCooldown -= deltaTime * 1000;
|
818 |
-
return;
|
819 |
-
}
|
820 |
-
|
821 |
-
// ๊ฐ์ฅ ๊ฐ๊น์ด ์ ์ฐพ๊ธฐ
|
822 |
-
let closestEnemy = null;
|
823 |
-
let closestDistance = Infinity;
|
824 |
-
|
825 |
-
enemies.forEach(enemy => {
|
826 |
-
if (!enemy.mesh || !enemy.isLoaded) return;
|
827 |
-
|
828 |
-
const distance = this.position.distanceTo(enemy.position);
|
829 |
-
if (distance < closestDistance && distance < 5000) { // 5km ์ด๋ด
|
830 |
-
// ์์ผ๊ฐ ํ์ธ
|
831 |
-
const toEnemy = enemy.position.clone().sub(this.position).normalize();
|
832 |
-
const forward = new THREE.Vector3(0, 0, 1);
|
833 |
-
forward.applyEuler(this.rotation);
|
834 |
-
const angle = forward.dot(toEnemy);
|
835 |
-
|
836 |
-
if (angle > 0.5) { // ์์ผ๊ฐ 60๋ ์ด๋ด
|
837 |
-
closestEnemy = enemy;
|
838 |
-
closestDistance = distance;
|
839 |
-
}
|
840 |
-
}
|
841 |
-
});
|
842 |
-
|
843 |
-
// ํ๊ฒ ๋ณ๊ฒฝ์ ๋ฝ์จ ์ด๊ธฐํ
|
844 |
-
if (closestEnemy !== this.missileTarget) {
|
845 |
-
this.missileTarget = closestEnemy;
|
846 |
-
this.missileLockCount = 0;
|
847 |
-
this.missileLockTimer = 0;
|
848 |
-
}
|
849 |
-
|
850 |
-
// ๋ฝ์จ ํ๋ก์ธ์ค
|
851 |
-
if (this.missileTarget) {
|
852 |
-
this.missileLockTimer += deltaTime;
|
853 |
-
|
854 |
-
// 0.5์ด๋ง๋ค ๋ฝ์จ ์นด์ดํธ ์ฆ๊ฐ
|
855 |
-
if (this.missileLockTimer >= 0.5) {
|
856 |
-
this.missileLockTimer = 0;
|
857 |
-
this.missileLockCount++;
|
858 |
-
|
859 |
-
// ๋ฝ์จ ์ฌ์ด๋ (lock.ogg๊ฐ ์์ผ๋ฉด ๋ฌด์)
|
860 |
-
try {
|
861 |
-
// const lockSound = new Audio('sounds/lock.ogg');
|
862 |
-
// lockSound.volume = 0.3;
|
863 |
-
// lockSound.play().catch(e => {});
|
864 |
-
} catch (e) {}
|
865 |
-
|
866 |
-
if (this.missileLockCount >= 3) {
|
867 |
-
this.missileLockCount = 3; // ์ต๋ 3
|
868 |
-
}
|
869 |
-
}
|
870 |
-
}
|
871 |
}
|
872 |
|
873 |
takeDamage(damage) {
|
@@ -1296,7 +1087,7 @@ class Game {
|
|
1296 |
this.bgm = null;
|
1297 |
this.bgmPlaying = false;
|
1298 |
|
1299 |
-
this.keys = { w: false, a: false, s: false, d: false, f: false
|
1300 |
this.isStarted = false;
|
1301 |
|
1302 |
this.setupScene();
|
@@ -1537,12 +1328,6 @@ class Game {
|
|
1537 |
case 'KeyS': this.keys.s = true; break;
|
1538 |
case 'KeyD': this.keys.d = true; break;
|
1539 |
case 'KeyF': this.keys.f = true; break;
|
1540 |
-
case 'KeyR':
|
1541 |
-
if (!this.keys.r) {
|
1542 |
-
this.keys.r = true;
|
1543 |
-
this.switchWeapon();
|
1544 |
-
}
|
1545 |
-
break;
|
1546 |
}
|
1547 |
});
|
1548 |
|
@@ -1555,7 +1340,6 @@ class Game {
|
|
1555 |
case 'KeyS': this.keys.s = false; break;
|
1556 |
case 'KeyD': this.keys.d = false; break;
|
1557 |
case 'KeyF': this.keys.f = false; break;
|
1558 |
-
case 'KeyR': this.keys.r = false; break;
|
1559 |
}
|
1560 |
});
|
1561 |
|
@@ -1573,15 +1357,8 @@ class Game {
|
|
1573 |
if (!document.pointerLockElement || this.isGameOver || !gameStarted) return;
|
1574 |
|
1575 |
if (event.button === 0) { // ์ผ์ชฝ ๋ง์ฐ์ค ๋ฒํผ
|
1576 |
-
|
1577 |
-
|
1578 |
-
this.lastShootTime = 0; // ์ฆ์ ๋ฐ์ฌ
|
1579 |
-
} else if (this.fighter.currentWeapon === 'missile') {
|
1580 |
-
// ๋ฏธ์ฌ์ผ ๋ฐ์ฌ
|
1581 |
-
if (this.fighter.missileTarget && this.fighter.missileLockCount >= 3) {
|
1582 |
-
this.fighter.shootMissile(this.scene, this.fighter.missileTarget);
|
1583 |
-
}
|
1584 |
-
}
|
1585 |
}
|
1586 |
});
|
1587 |
|
@@ -1598,24 +1375,19 @@ class Game {
|
|
1598 |
});
|
1599 |
}
|
1600 |
|
1601 |
-
|
1602 |
-
if (this.
|
1603 |
-
|
1604 |
-
|
1605 |
-
this.fighter.currentWeapon = 'mg';
|
1606 |
}
|
1607 |
|
1608 |
-
|
1609 |
-
this.
|
1610 |
-
this.fighter.missileLockCount = 0;
|
1611 |
-
this.fighter.missileLockTimer = 0;
|
1612 |
|
1613 |
-
//
|
1614 |
-
|
1615 |
-
|
1616 |
-
|
1617 |
-
// switchSound.play().catch(e => {});
|
1618 |
-
} catch (e) {}
|
1619 |
}
|
1620 |
|
1621 |
startBGM() {
|
@@ -1688,47 +1460,7 @@ class Game {
|
|
1688 |
|
1689 |
if (scoreElement) scoreElement.textContent = `Score: ${this.score}`;
|
1690 |
if (timeElement) timeElement.textContent = `Time: ${this.gameTime}s`;
|
1691 |
-
|
1692 |
-
// ๋ฌด๊ธฐ ํ์ ์
๋ฐ์ดํธ
|
1693 |
-
if (ammoElement) {
|
1694 |
-
let weaponDisplay = '';
|
1695 |
-
if (this.fighter.currentWeapon === 'mg') {
|
1696 |
-
weaponDisplay = `
|
1697 |
-
<div style="font-size: 12px; margin-bottom: 5px;">R: WEAPON CHANGE</div>
|
1698 |
-
<div style="font-size: 16px; color: #00ff00;">20MM MG</div>
|
1699 |
-
<div>AMMO: ${this.fighter.ammo}</div>
|
1700 |
-
`;
|
1701 |
-
} else {
|
1702 |
-
const cooldownSeconds = Math.ceil(this.fighter.weaponCooldown / 1000);
|
1703 |
-
weaponDisplay = `
|
1704 |
-
<div style="font-size: 12px; margin-bottom: 5px;">R: WEAPON CHANGE</div>
|
1705 |
-
<div style="font-size: 16px; color: #ff8800;">AIM-9 MISSILE</div>
|
1706 |
-
<div>COUNT: ${this.fighter.missiles}</div>
|
1707 |
-
`;
|
1708 |
-
|
1709 |
-
// ์ฟจ๋ค์ด ์ค์ด๋ฉด ๋ชจ๋์๊ณ ํ์
|
1710 |
-
if (this.fighter.weaponCooldown > 0) {
|
1711 |
-
weaponDisplay += `<div style="font-size: 20px; margin-top: 5px;">โณ ${cooldownSeconds}s</div>`;
|
1712 |
-
} else if (this.fighter.missileTarget) {
|
1713 |
-
// ๋ฝ์จ ์งํ ์ํ ํ์
|
1714 |
-
const lockSymbols = ['โฏ', 'โ', 'โ'];
|
1715 |
-
let lockDisplay = '';
|
1716 |
-
for (let i = 0; i < 3; i++) {
|
1717 |
-
if (i < this.fighter.missileLockCount) {
|
1718 |
-
lockDisplay += `<span style="color: #ff0000;">${lockSymbols[i]}</span> `;
|
1719 |
-
} else {
|
1720 |
-
lockDisplay += `<span style="color: #666;">${lockSymbols[0]}</span> `;
|
1721 |
-
}
|
1722 |
-
}
|
1723 |
-
weaponDisplay += `<div style="margin-top: 5px;">LOCK: ${lockDisplay}</div>`;
|
1724 |
-
|
1725 |
-
if (this.fighter.missileLockCount >= 3) {
|
1726 |
-
weaponDisplay += `<div style="color: #ff0000; animation: blink 0.5s infinite;">READY TO FIRE</div>`;
|
1727 |
-
}
|
1728 |
-
}
|
1729 |
-
}
|
1730 |
-
ammoElement.innerHTML = weaponDisplay;
|
1731 |
-
}
|
1732 |
|
1733 |
if (gameStatsElement) {
|
1734 |
gameStatsElement.innerHTML = `
|
@@ -2163,32 +1895,6 @@ class Game {
|
|
2163 |
}
|
2164 |
}
|
2165 |
|
2166 |
-
// ํ๋ ์ด์ด ๋ฏธ์ฌ์ผ vs ์ ๊ธฐ ์ถฉ๋
|
2167 |
-
for (let i = this.fighter.activeMissiles.length - 1; i >= 0; i--) {
|
2168 |
-
const missile = this.fighter.activeMissiles[i];
|
2169 |
-
|
2170 |
-
if (missile.target && missile.target.mesh && missile.target.isLoaded) {
|
2171 |
-
const distance = missile.position.distanceTo(missile.target.position);
|
2172 |
-
if (distance < 50) { // ๋ฏธ์ฌ์ผ ์ถฉ๋ ๊ฑฐ๋ฆฌ
|
2173 |
-
this.scene.remove(missile);
|
2174 |
-
this.fighter.activeMissiles.splice(i, 1);
|
2175 |
-
|
2176 |
-
// ํฐ ํญ๋ฐ ์ดํํธ
|
2177 |
-
this.createMissileExplosion(missile.target.position);
|
2178 |
-
|
2179 |
-
// ๋ฏธ์ฌ์ผ ๋ฐ๋ฏธ์ง (500)
|
2180 |
-
if (missile.target.takeDamage(GAME_CONSTANTS.MISSILE_DAMAGE)) {
|
2181 |
-
const enemyIndex = this.enemies.indexOf(missile.target);
|
2182 |
-
if (enemyIndex !== -1) {
|
2183 |
-
missile.target.destroy();
|
2184 |
-
this.enemies.splice(enemyIndex, 1);
|
2185 |
-
this.score += 250; // ๋ฏธ์ฌ์ผ ๊ฒฉ์ถ๋ ๋ ๋ง์ ์ ์
|
2186 |
-
}
|
2187 |
-
}
|
2188 |
-
}
|
2189 |
-
}
|
2190 |
-
}
|
2191 |
-
|
2192 |
// ์ ํํ vs ํ๋ ์ด์ด ์ถฉ๋
|
2193 |
this.enemies.forEach(enemy => {
|
2194 |
enemy.bullets.forEach((bullet, index) => {
|
@@ -2207,107 +1913,6 @@ class Game {
|
|
2207 |
});
|
2208 |
});
|
2209 |
}
|
2210 |
-
|
2211 |
-
createMissileExplosion(position) {
|
2212 |
-
// ๋ํ ํญ๋ฐ ํจ๊ณผ
|
2213 |
-
const explosionGroup = new THREE.Group();
|
2214 |
-
explosionGroup.position.copy(position);
|
2215 |
-
|
2216 |
-
// ์ค์ ํญ๋ฐ
|
2217 |
-
const coreGeometry = new THREE.SphereGeometry(10, 16, 16);
|
2218 |
-
const coreMaterial = new THREE.MeshBasicMaterial({
|
2219 |
-
color: 0xffff00,
|
2220 |
-
emissive: 0xffaa00,
|
2221 |
-
emissiveIntensity: 2.0,
|
2222 |
-
transparent: true,
|
2223 |
-
opacity: 1.0
|
2224 |
-
});
|
2225 |
-
const core = new THREE.Mesh(coreGeometry, coreMaterial);
|
2226 |
-
explosionGroup.add(core);
|
2227 |
-
|
2228 |
-
// ์ธ๋ถ ํญ๋ฐ ๋ง
|
2229 |
-
const ringGeometry = new THREE.TorusGeometry(15, 5, 8, 16);
|
2230 |
-
const ringMaterial = new THREE.MeshBasicMaterial({
|
2231 |
-
color: 0xff6600,
|
2232 |
-
emissive: 0xff3300,
|
2233 |
-
emissiveIntensity: 1.5,
|
2234 |
-
transparent: true,
|
2235 |
-
opacity: 0.8
|
2236 |
-
});
|
2237 |
-
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
|
2238 |
-
explosionGroup.add(ring);
|
2239 |
-
|
2240 |
-
// ํํธ ํํฐํด
|
2241 |
-
const particleCount = 30;
|
2242 |
-
const particles = [];
|
2243 |
-
|
2244 |
-
for (let i = 0; i < particleCount; i++) {
|
2245 |
-
const particleGeometry = new THREE.SphereGeometry(Math.random() * 2 + 0.5, 4, 4);
|
2246 |
-
const particleMaterial = new THREE.MeshBasicMaterial({
|
2247 |
-
color: Math.random() > 0.5 ? 0xffaa00 : 0xff6600,
|
2248 |
-
emissive: 0xffaa00,
|
2249 |
-
emissiveIntensity: 1.0,
|
2250 |
-
transparent: true,
|
2251 |
-
opacity: 1.0
|
2252 |
-
});
|
2253 |
-
|
2254 |
-
const particle = new THREE.Mesh(particleGeometry, particleMaterial);
|
2255 |
-
particle.position.set(
|
2256 |
-
(Math.random() - 0.5) * 10,
|
2257 |
-
(Math.random() - 0.5) * 10,
|
2258 |
-
(Math.random() - 0.5) * 10
|
2259 |
-
);
|
2260 |
-
|
2261 |
-
particle.velocity = new THREE.Vector3(
|
2262 |
-
(Math.random() - 0.5) * 200,
|
2263 |
-
(Math.random() - 0.5) * 200,
|
2264 |
-
(Math.random() - 0.5) * 200
|
2265 |
-
);
|
2266 |
-
|
2267 |
-
particle.life = 1.5;
|
2268 |
-
explosionGroup.add(particle);
|
2269 |
-
particles.push(particle);
|
2270 |
-
}
|
2271 |
-
|
2272 |
-
this.scene.add(explosionGroup);
|
2273 |
-
|
2274 |
-
// ํญ๋ฐ ์ ๋๋ฉ์ด์
|
2275 |
-
const animateExplosion = () => {
|
2276 |
-
// ์ค์ ํญ๋ฐ ํ์ฅ
|
2277 |
-
core.scale.multiplyScalar(1.15);
|
2278 |
-
core.material.opacity *= 0.92;
|
2279 |
-
|
2280 |
-
// ๋ง ํ์ฅ ๋ฐ ํ์
|
2281 |
-
ring.scale.multiplyScalar(1.1);
|
2282 |
-
ring.rotation.x += 0.1;
|
2283 |
-
ring.rotation.y += 0.15;
|
2284 |
-
ring.material.opacity *= 0.94;
|
2285 |
-
|
2286 |
-
// ํํฐํด ์ ๋๋ฉ์ด์
|
2287 |
-
particles.forEach(particle => {
|
2288 |
-
particle.life -= 0.02;
|
2289 |
-
particle.position.add(particle.velocity.clone().multiplyScalar(0.02));
|
2290 |
-
particle.velocity.y -= 3; // ์ค๋ ฅ
|
2291 |
-
particle.material.opacity = particle.life / 1.5;
|
2292 |
-
particle.scale.multiplyScalar(0.98);
|
2293 |
-
});
|
2294 |
-
|
2295 |
-
if (core.material.opacity > 0.01) {
|
2296 |
-
requestAnimationFrame(animateExplosion);
|
2297 |
-
} else {
|
2298 |
-
this.scene.remove(explosionGroup);
|
2299 |
-
}
|
2300 |
-
};
|
2301 |
-
|
2302 |
-
animateExplosion();
|
2303 |
-
|
2304 |
-
// ํญ๋ฐ ์ฌ์ด๋
|
2305 |
-
try {
|
2306 |
-
const explosionSound = new Audio('sounds/explosion.ogg');
|
2307 |
-
explosionSound.volume = 0.6;
|
2308 |
-
explosionSound.play().catch(e => console.log('Explosion sound not found'));
|
2309 |
-
} catch (e) {}
|
2310 |
-
}
|
2311 |
|
2312 |
createHitEffect(position) {
|
2313 |
// ํผ๊ฒฉ ํํฐํด ํจ๊ณผ ์์ฑ
|
@@ -2399,7 +2004,7 @@ class Game {
|
|
2399 |
try {
|
2400 |
const hitSound = new Audio('sounds/hit.ogg');
|
2401 |
hitSound.volume = 0.3;
|
2402 |
-
hitSound.play().catch(e =>
|
2403 |
} catch (e) {}
|
2404 |
}
|
2405 |
|
@@ -2470,10 +2075,8 @@ class Game {
|
|
2470 |
this.fighter.updatePhysics(deltaTime);
|
2471 |
this.fighter.updateBullets(this.scene, deltaTime);
|
2472 |
|
2473 |
-
// ์ค๋ณต๋ ๋ฏธ์ฌ์ผ ๋ฝ์จ ์
๋ฐ์ดํธ ๋ผ์ธ ์ ๊ฑฐ (์ด๋ฏธ ์์ ์์)
|
2474 |
-
|
2475 |
// ๋ง์ฐ์ค ๋๋ฆ ์ํ์ผ ๋ ์ฐ์ ๋ฐ์ฌ
|
2476 |
-
if (this.fighter.isMouseDown && this.isStarted
|
2477 |
const currentShootTime = Date.now();
|
2478 |
if (!this.lastShootTime || currentShootTime - this.lastShootTime >= 100) { // 0.1์ด๋ง๋ค
|
2479 |
this.fighter.shoot(this.scene);
|
@@ -2481,11 +2084,6 @@ class Game {
|
|
2481 |
}
|
2482 |
}
|
2483 |
|
2484 |
-
// ๋ฏธ์ฌ์ผ ๋ฝ์จ ์
๋ฐ์ดํธ
|
2485 |
-
if (this.fighter.currentWeapon === 'missile') {
|
2486 |
-
this.fighter.updateMissileLock(this.enemies, deltaTime);
|
2487 |
-
}
|
2488 |
-
|
2489 |
if (this.isStarted) {
|
2490 |
// ์ ๊ธฐ๋ค์๊ฒ ์๋ก์ ์ฐธ์กฐ ์ ๋ฌ (์ถฉ๋ ํํผ์ฉ)
|
2491 |
this.enemies.forEach(enemy => {
|
|
|
20 |
MISSILE_COUNT: 6,
|
21 |
AMMO_COUNT: 940, // 940๋ฐ๋ก ๋ณ๊ฒฝ
|
22 |
BULLET_DAMAGE: 25, // ๋ฐ๋น 25 ๋ฐ๋ฏธ์ง
|
|
|
23 |
MAX_HEALTH: 1000 // ์ฒด๋ ฅ 1000
|
24 |
};
|
25 |
|
|
|
60 |
this.missiles = GAME_CONSTANTS.MISSILE_COUNT;
|
61 |
this.ammo = GAME_CONSTANTS.AMMO_COUNT;
|
62 |
this.bullets = [];
|
|
|
63 |
this.lastShootTime = 0;
|
64 |
this.isMouseDown = false; // ๋ง์ฐ์ค ๋๋ฆ ์ํ ์ถ์
|
65 |
this.gunfireAudios = []; // ๊ธฐ๊ด์ด ์๋ฆฌ ๋ฐฐ์ด (์ต๋ 5๊ฐ)
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
// ์คํจ ํ์ถ์ ์ํ Fํค ์ํ
|
68 |
this.escapeKeyPressed = false;
|
69 |
this.stallEscapeProgress = 0; // ์คํจ ํ์ถ ์งํ๋ (0~2์ด)
|
|
|
642 |
}
|
643 |
|
644 |
updateBullets(scene, deltaTime) {
|
|
|
645 |
for (let i = this.bullets.length - 1; i >= 0; i--) {
|
646 |
const bullet = this.bullets[i];
|
647 |
bullet.position.add(bullet.velocity.clone().multiplyScalar(deltaTime));
|
|
|
659 |
this.bullets.splice(i, 1);
|
660 |
}
|
661 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
662 |
}
|
663 |
|
664 |
takeDamage(damage) {
|
|
|
1087 |
this.bgm = null;
|
1088 |
this.bgmPlaying = false;
|
1089 |
|
1090 |
+
this.keys = { w: false, a: false, s: false, d: false, f: false };
|
1091 |
this.isStarted = false;
|
1092 |
|
1093 |
this.setupScene();
|
|
|
1328 |
case 'KeyS': this.keys.s = true; break;
|
1329 |
case 'KeyD': this.keys.d = true; break;
|
1330 |
case 'KeyF': this.keys.f = true; break;
|
|
|
|
|
|
|
|
|
|
|
|
|
1331 |
}
|
1332 |
});
|
1333 |
|
|
|
1340 |
case 'KeyS': this.keys.s = false; break;
|
1341 |
case 'KeyD': this.keys.d = false; break;
|
1342 |
case 'KeyF': this.keys.f = false; break;
|
|
|
1343 |
}
|
1344 |
});
|
1345 |
|
|
|
1357 |
if (!document.pointerLockElement || this.isGameOver || !gameStarted) return;
|
1358 |
|
1359 |
if (event.button === 0) { // ์ผ์ชฝ ๋ง์ฐ์ค ๋ฒํผ
|
1360 |
+
this.fighter.isMouseDown = true;
|
1361 |
+
this.lastShootTime = 0; // ์ฆ์ ๋ฐ์ฌ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1362 |
}
|
1363 |
});
|
1364 |
|
|
|
1375 |
});
|
1376 |
}
|
1377 |
|
1378 |
+
startGame() {
|
1379 |
+
if (!this.isLoaded) {
|
1380 |
+
console.log('๊ฒ์์ด ์์ง ๋ก๋ฉ ์ค์
๋๋ค...');
|
1381 |
+
return;
|
|
|
1382 |
}
|
1383 |
|
1384 |
+
this.isStarted = true;
|
1385 |
+
this.startGameTimer();
|
|
|
|
|
1386 |
|
1387 |
+
// ์์ง ์๋ฆฌ ์์
|
1388 |
+
this.fighter.startEngineSound();
|
1389 |
+
|
1390 |
+
console.log('๊ฒ์ ์์!');
|
|
|
|
|
1391 |
}
|
1392 |
|
1393 |
startBGM() {
|
|
|
1460 |
|
1461 |
if (scoreElement) scoreElement.textContent = `Score: ${this.score}`;
|
1462 |
if (timeElement) timeElement.textContent = `Time: ${this.gameTime}s`;
|
1463 |
+
if (ammoElement) ammoElement.textContent = `AMMO: ${this.fighter.ammo}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1464 |
|
1465 |
if (gameStatsElement) {
|
1466 |
gameStatsElement.innerHTML = `
|
|
|
1895 |
}
|
1896 |
}
|
1897 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1898 |
// ์ ํํ vs ํ๋ ์ด์ด ์ถฉ๋
|
1899 |
this.enemies.forEach(enemy => {
|
1900 |
enemy.bullets.forEach((bullet, index) => {
|
|
|
1913 |
});
|
1914 |
});
|
1915 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1916 |
|
1917 |
createHitEffect(position) {
|
1918 |
// ํผ๊ฒฉ ํํฐํด ํจ๊ณผ ์์ฑ
|
|
|
2004 |
try {
|
2005 |
const hitSound = new Audio('sounds/hit.ogg');
|
2006 |
hitSound.volume = 0.3;
|
2007 |
+
hitSound.play().catch(e => {});
|
2008 |
} catch (e) {}
|
2009 |
}
|
2010 |
|
|
|
2075 |
this.fighter.updatePhysics(deltaTime);
|
2076 |
this.fighter.updateBullets(this.scene, deltaTime);
|
2077 |
|
|
|
|
|
2078 |
// ๋ง์ฐ์ค ๋๋ฆ ์ํ์ผ ๋ ์ฐ์ ๋ฐ์ฌ
|
2079 |
+
if (this.fighter.isMouseDown && this.isStarted) {
|
2080 |
const currentShootTime = Date.now();
|
2081 |
if (!this.lastShootTime || currentShootTime - this.lastShootTime >= 100) { // 0.1์ด๋ง๋ค
|
2082 |
this.fighter.shoot(this.scene);
|
|
|
2084 |
}
|
2085 |
}
|
2086 |
|
|
|
|
|
|
|
|
|
|
|
2087 |
if (this.isStarted) {
|
2088 |
// ์ ๊ธฐ๋ค์๊ฒ ์๋ก์ ์ฐธ์กฐ ์ ๋ฌ (์ถฉ๋ ํํผ์ฉ)
|
2089 |
this.enemies.forEach(enemy => {
|