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 => {
|