Spaces:
Running
Running
Update game.js
Browse files
game.js
CHANGED
|
@@ -588,8 +588,8 @@ class Fighter {
|
|
| 588 |
|
| 589 |
this.ammo--;
|
| 590 |
|
| 591 |
-
// μ§μ λͺ¨μμ νν (
|
| 592 |
-
const bulletGeometry = new THREE.CylinderGeometry(0
|
| 593 |
const bulletMaterial = new THREE.MeshBasicMaterial({
|
| 594 |
color: 0xffff00,
|
| 595 |
emissive: 0xffff00,
|
|
@@ -691,7 +691,7 @@ class EnemyFighter {
|
|
| 691 |
this.velocity = new THREE.Vector3(0, 0, 120);
|
| 692 |
this.rotation = new THREE.Euler(0, 0, 0);
|
| 693 |
this.health = GAME_CONSTANTS.MAX_HEALTH; // 체λ ₯ 1000
|
| 694 |
-
this.speed =
|
| 695 |
this.bullets = [];
|
| 696 |
this.lastShootTime = 0;
|
| 697 |
|
|
@@ -710,6 +710,12 @@ class EnemyFighter {
|
|
| 710 |
// λ€λ₯Έ μ κΈ°λ€κ³Όμ μΆ©λ ννΌ
|
| 711 |
this.nearbyEnemies = [];
|
| 712 |
this.separationRadius = 300; // μ΅μ 거리 300m
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
}
|
| 714 |
|
| 715 |
generateRandomTarget() {
|
|
@@ -776,29 +782,74 @@ class EnemyFighter {
|
|
| 776 |
const currentTime = Date.now();
|
| 777 |
const distanceToPlayer = this.position.distanceTo(playerPosition);
|
| 778 |
|
| 779 |
-
// νλ μ΄μ΄ κ°μ§ λ°
|
| 780 |
-
let shouldAttack = false;
|
| 781 |
if (distanceToPlayer < 3000) {
|
|
|
|
|
|
|
|
|
|
| 782 |
// νλ μ΄μ΄κ° μμΌκ° λ΄μ μλμ§ νμΈ
|
| 783 |
const toPlayer = playerPosition.clone().sub(this.position).normalize();
|
| 784 |
const forward = new THREE.Vector3(0, 0, 1);
|
| 785 |
forward.applyEuler(this.rotation);
|
| 786 |
const angle = forward.dot(toPlayer);
|
| 787 |
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
this.shoot();
|
|
|
|
| 792 |
}
|
| 793 |
}
|
|
|
|
|
|
|
|
|
|
| 794 |
}
|
| 795 |
|
| 796 |
-
//
|
| 797 |
-
if (this.
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
}
|
| 803 |
|
| 804 |
// λͺ©ν λ°©ν₯ κ³μ°
|
|
@@ -810,45 +861,42 @@ class EnemyFighter {
|
|
| 810 |
while (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
|
| 811 |
while (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
|
| 812 |
|
|
|
|
|
|
|
|
|
|
| 813 |
// ν° κ°λ μ°¨μ΄κ° μμΌλ©΄ μν μ ν
|
| 814 |
-
if (Math.abs(angleDiff) > Math.PI / 6) {
|
| 815 |
this.isTurning = true;
|
| 816 |
this.turnDirection = angleDiff > 0 ? 1 : -1;
|
| 817 |
}
|
| 818 |
|
| 819 |
// μ ν μ€μΌ λ
|
| 820 |
if (this.isTurning) {
|
| 821 |
-
// μν μ ν ꡬν
|
| 822 |
-
const turnRate = (this.speed / this.turnRadius) * this.turnDirection;
|
| 823 |
this.targetRotation.y += turnRate * deltaTime;
|
| 824 |
-
this.targetRotation.z = this.turnDirection * 0.5; //
|
| 825 |
|
| 826 |
// λͺ©ν κ°λμ κ·Όμ νλ©΄ μ ν μ’
λ£
|
| 827 |
const newAngleDiff = targetAngle - this.targetRotation.y;
|
| 828 |
-
if (Math.abs(newAngleDiff) < Math.PI / 12) {
|
| 829 |
this.isTurning = false;
|
| 830 |
}
|
| 831 |
} else {
|
| 832 |
-
// μ§μ§ λΉν
|
| 833 |
-
|
|
|
|
| 834 |
this.targetRotation.z = THREE.MathUtils.lerp(this.targetRotation.z, 0, deltaTime * 2);
|
| 835 |
}
|
| 836 |
|
| 837 |
-
// κ³ λ μ‘°μ
|
| 838 |
-
const altitudeDiff = this.targetPosition.y - this.position.y;
|
| 839 |
-
if (Math.abs(altitudeDiff) > 100) {
|
| 840 |
-
this.targetRotation.x = Math.max(-0.3, Math.min(0.3, altitudeDiff * 0.0001));
|
| 841 |
-
} else {
|
| 842 |
-
this.targetRotation.x = 0;
|
| 843 |
-
}
|
| 844 |
-
|
| 845 |
// λ€λ₯Έ μ κΈ°μμ μΆ©λ ννΌ
|
| 846 |
this.avoidOtherEnemies(deltaTime);
|
| 847 |
|
| 848 |
-
// λΆλλ¬μ΄ νμ μ μ©
|
| 849 |
-
|
| 850 |
-
this.rotation.
|
| 851 |
-
this.rotation.
|
|
|
|
| 852 |
|
| 853 |
// μλ λ²‘ν° κ³μ°
|
| 854 |
const forward = new THREE.Vector3(0, 0, 1);
|
|
@@ -928,8 +976,8 @@ class EnemyFighter {
|
|
| 928 |
shoot() {
|
| 929 |
this.lastShootTime = Date.now();
|
| 930 |
|
| 931 |
-
// μ§μ λͺ¨μμ νν (
|
| 932 |
-
const bulletGeometry = new THREE.CylinderGeometry(0.
|
| 933 |
const bulletMaterial = new THREE.MeshBasicMaterial({
|
| 934 |
color: 0xff0000,
|
| 935 |
emissive: 0xff0000,
|
|
@@ -1762,7 +1810,7 @@ class Game {
|
|
| 1762 |
if (!enemy.mesh || !enemy.isLoaded) continue;
|
| 1763 |
|
| 1764 |
const distance = bullet.position.distanceTo(enemy.position);
|
| 1765 |
-
if (distance <
|
| 1766 |
this.scene.remove(bullet);
|
| 1767 |
this.fighter.bullets.splice(i, 1);
|
| 1768 |
|
|
@@ -1784,7 +1832,7 @@ class Game {
|
|
| 1784 |
this.enemies.forEach(enemy => {
|
| 1785 |
enemy.bullets.forEach((bullet, index) => {
|
| 1786 |
const distance = bullet.position.distanceTo(this.fighter.position);
|
| 1787 |
-
if (distance <
|
| 1788 |
this.scene.remove(bullet);
|
| 1789 |
enemy.bullets.splice(index, 1);
|
| 1790 |
|
|
|
|
| 588 |
|
| 589 |
this.ammo--;
|
| 590 |
|
| 591 |
+
// μ§μ λͺ¨μμ νν (100% λ ν¬κ²)
|
| 592 |
+
const bulletGeometry = new THREE.CylinderGeometry(1.0, 1.0, 16, 8); // λ°μ§λ¦ 0.75β1.0, κΈΈμ΄ 12β16
|
| 593 |
const bulletMaterial = new THREE.MeshBasicMaterial({
|
| 594 |
color: 0xffff00,
|
| 595 |
emissive: 0xffff00,
|
|
|
|
| 691 |
this.velocity = new THREE.Vector3(0, 0, 120);
|
| 692 |
this.rotation = new THREE.Euler(0, 0, 0);
|
| 693 |
this.health = GAME_CONSTANTS.MAX_HEALTH; // 체λ ₯ 1000
|
| 694 |
+
this.speed = 514; // 1000kt in m/s (1000 * 0.514444)
|
| 695 |
this.bullets = [];
|
| 696 |
this.lastShootTime = 0;
|
| 697 |
|
|
|
|
| 710 |
// λ€λ₯Έ μ κΈ°λ€κ³Όμ μΆ©λ ννΌ
|
| 711 |
this.nearbyEnemies = [];
|
| 712 |
this.separationRadius = 300; // μ΅μ 거리 300m
|
| 713 |
+
|
| 714 |
+
// μ ν¬ κ΄λ ¨ λ³μ
|
| 715 |
+
this.isEngaged = false; // μ ν¬ μ€ μν
|
| 716 |
+
this.burstCount = 0; // νμ¬ μ°λ° μ
|
| 717 |
+
this.lastBurstTime = 0; // λ§μ§λ§ μ°λ° μμ μκ°
|
| 718 |
+
this.predictedTargetPos = new THREE.Vector3(); // μμΈ‘ μ¬κ²© μμΉ
|
| 719 |
}
|
| 720 |
|
| 721 |
generateRandomTarget() {
|
|
|
|
| 782 |
const currentTime = Date.now();
|
| 783 |
const distanceToPlayer = this.position.distanceTo(playerPosition);
|
| 784 |
|
| 785 |
+
// νλ μ΄μ΄ κ°μ§ λ° μ ν¬ μν μ ν
|
|
|
|
| 786 |
if (distanceToPlayer < 3000) {
|
| 787 |
+
this.isEngaged = true;
|
| 788 |
+
this.aiState = 'combat';
|
| 789 |
+
|
| 790 |
// νλ μ΄μ΄κ° μμΌκ° λ΄μ μλμ§ νμΈ
|
| 791 |
const toPlayer = playerPosition.clone().sub(this.position).normalize();
|
| 792 |
const forward = new THREE.Vector3(0, 0, 1);
|
| 793 |
forward.applyEuler(this.rotation);
|
| 794 |
const angle = forward.dot(toPlayer);
|
| 795 |
|
| 796 |
+
// μμΈ‘ μ¬κ²©μ μν νλ μ΄μ΄ μλ κ³μ°
|
| 797 |
+
if (this.playerFighter) {
|
| 798 |
+
const bulletSpeed = 1200; // νν μλ
|
| 799 |
+
const timeToHit = distanceToPlayer / bulletSpeed;
|
| 800 |
+
|
| 801 |
+
// νλ μ΄μ΄μ μμ μμΉ κ³μ°
|
| 802 |
+
this.predictedTargetPos = playerPosition.clone().add(
|
| 803 |
+
this.playerFighter.velocity.clone().multiplyScalar(timeToHit)
|
| 804 |
+
);
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
// μ¬κ²© 쑰건: μμΌκ° λ΄μ μκ³ κ±°λ¦¬κ° 2000m μ΄λ΄
|
| 808 |
+
if (angle > 0.7 && distanceToPlayer < 2000) { // μμΌκ°μ μ’νμ μ νλ ν₯μ
|
| 809 |
+
// μ°λ° μ¬κ²© μμ€ν
|
| 810 |
+
const timeSinceLastBurst = currentTime - this.lastBurstTime;
|
| 811 |
+
|
| 812 |
+
// 2μ΄λ§λ€ μλ‘μ΄ μ°λ° μμ
|
| 813 |
+
if (timeSinceLastBurst >= 2000) {
|
| 814 |
+
this.burstCount = 0;
|
| 815 |
+
this.lastBurstTime = currentTime;
|
| 816 |
+
}
|
| 817 |
+
|
| 818 |
+
// 10λ° μ°λ° (0.1μ΄ κ°κ²©)
|
| 819 |
+
if (this.burstCount < 10 && currentTime - this.lastShootTime >= 100) {
|
| 820 |
this.shoot();
|
| 821 |
+
this.burstCount++;
|
| 822 |
}
|
| 823 |
}
|
| 824 |
+
} else {
|
| 825 |
+
this.isEngaged = false;
|
| 826 |
+
this.aiState = 'patrol';
|
| 827 |
}
|
| 828 |
|
| 829 |
+
// μ ν¬ μ€μΌ λ νλ μ΄μ΄ μΆμ
|
| 830 |
+
if (this.isEngaged && this.playerFighter) {
|
| 831 |
+
// νλ μ΄μ΄μ κΈ°λ ν¨ν΄ λͺ¨λ°©
|
| 832 |
+
const playerVelocity = this.playerFighter.velocity.clone().normalize();
|
| 833 |
+
const playerRoll = this.playerFighter.rotation.z;
|
| 834 |
+
const playerPitch = this.playerFighter.rotation.x;
|
| 835 |
+
|
| 836 |
+
// μμΈ‘λ μμΉλ‘ ν₯νλλ‘ μ€μ
|
| 837 |
+
this.targetPosition = this.predictedTargetPos.clone();
|
| 838 |
+
|
| 839 |
+
// νλ μ΄μ΄μ λΉμ·ν λ‘€ μ μ© (μ½κ°μ μ§μ°μΌλ‘)
|
| 840 |
+
this.targetRotation.z = playerRoll * 0.7;
|
| 841 |
+
|
| 842 |
+
// κ³ λ μ°¨μ΄μ λ°λ₯Έ νΌμΉ μ‘°μ (λ 곡격μ μΌλ‘)
|
| 843 |
+
const altitudeDiff = this.targetPosition.y - this.position.y;
|
| 844 |
+
this.targetRotation.x = Math.max(-0.5, Math.min(0.5, altitudeDiff * 0.0003));
|
| 845 |
+
} else {
|
| 846 |
+
// μμ°° λͺ¨λ
|
| 847 |
+
if (this.position.distanceTo(this.targetPosition) < 500 ||
|
| 848 |
+
currentTime - this.lastDirectionChange > 15000) {
|
| 849 |
+
this.targetPosition = this.generateRandomTarget();
|
| 850 |
+
this.lastDirectionChange = currentTime;
|
| 851 |
+
this.isTurning = false;
|
| 852 |
+
}
|
| 853 |
}
|
| 854 |
|
| 855 |
// λͺ©ν λ°©ν₯ κ³μ°
|
|
|
|
| 861 |
while (angleDiff > Math.PI) angleDiff -= Math.PI * 2;
|
| 862 |
while (angleDiff < -Math.PI) angleDiff += Math.PI * 2;
|
| 863 |
|
| 864 |
+
// μ ν¬ μ€μλ λ λΉ λ₯Έ μ ν
|
| 865 |
+
const turnRateMultiplier = this.isEngaged ? 2.0 : 1.0;
|
| 866 |
+
|
| 867 |
// ν° κ°λ μ°¨μ΄κ° μμΌλ©΄ μν μ ν
|
| 868 |
+
if (Math.abs(angleDiff) > Math.PI / 6) {
|
| 869 |
this.isTurning = true;
|
| 870 |
this.turnDirection = angleDiff > 0 ? 1 : -1;
|
| 871 |
}
|
| 872 |
|
| 873 |
// μ ν μ€μΌ λ
|
| 874 |
if (this.isTurning) {
|
| 875 |
+
// μν μ ν ꡬν (μ ν¬ μ€μλ λ λΉ λ₯΄κ²)
|
| 876 |
+
const turnRate = (this.speed / this.turnRadius) * this.turnDirection * turnRateMultiplier;
|
| 877 |
this.targetRotation.y += turnRate * deltaTime;
|
| 878 |
+
this.targetRotation.z = this.turnDirection * 0.5 * (this.isEngaged ? 1.5 : 1); // μ ν¬ μ€ λ ν° λ‘€
|
| 879 |
|
| 880 |
// λͺ©ν κ°λμ κ·Όμ νλ©΄ μ ν μ’
λ£
|
| 881 |
const newAngleDiff = targetAngle - this.targetRotation.y;
|
| 882 |
+
if (Math.abs(newAngleDiff) < Math.PI / 12) {
|
| 883 |
this.isTurning = false;
|
| 884 |
}
|
| 885 |
} else {
|
| 886 |
+
// μ§μ§ λΉν (μ ν¬ μ€μλ λ λΉ λ₯Έ λ°μ)
|
| 887 |
+
const lerpSpeed = this.isEngaged ? 1.0 : 0.5;
|
| 888 |
+
this.targetRotation.y = THREE.MathUtils.lerp(this.targetRotation.y, targetAngle, deltaTime * lerpSpeed);
|
| 889 |
this.targetRotation.z = THREE.MathUtils.lerp(this.targetRotation.z, 0, deltaTime * 2);
|
| 890 |
}
|
| 891 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 892 |
// λ€λ₯Έ μ κΈ°μμ μΆ©λ ννΌ
|
| 893 |
this.avoidOtherEnemies(deltaTime);
|
| 894 |
|
| 895 |
+
// λΆλλ¬μ΄ νμ μ μ© (μ ν¬ μ€μλ λ λΉ λ₯΄κ²)
|
| 896 |
+
const rotationSpeed = this.isEngaged ? 3.0 : 2.0;
|
| 897 |
+
this.rotation.x = THREE.MathUtils.lerp(this.rotation.x, this.targetRotation.x, deltaTime * rotationSpeed);
|
| 898 |
+
this.rotation.y = THREE.MathUtils.lerp(this.rotation.y, this.targetRotation.y, deltaTime * rotationSpeed);
|
| 899 |
+
this.rotation.z = THREE.MathUtils.lerp(this.rotation.z, this.targetRotation.z, deltaTime * rotationSpeed * 1.25);
|
| 900 |
|
| 901 |
// μλ λ²‘ν° κ³μ°
|
| 902 |
const forward = new THREE.Vector3(0, 0, 1);
|
|
|
|
| 976 |
shoot() {
|
| 977 |
this.lastShootTime = Date.now();
|
| 978 |
|
| 979 |
+
// μ§μ λͺ¨μμ νν (100% λ ν¬κ²)
|
| 980 |
+
const bulletGeometry = new THREE.CylinderGeometry(0.8, 0.8, 12, 8); // λ°μ§λ¦ 0.6β0.8, κΈΈμ΄ 9β12
|
| 981 |
const bulletMaterial = new THREE.MeshBasicMaterial({
|
| 982 |
color: 0xff0000,
|
| 983 |
emissive: 0xff0000,
|
|
|
|
| 1810 |
if (!enemy.mesh || !enemy.isLoaded) continue;
|
| 1811 |
|
| 1812 |
const distance = bullet.position.distanceTo(enemy.position);
|
| 1813 |
+
if (distance < 90) { // 60μμ 90μΌλ‘ μ¦κ° (100% νλ)
|
| 1814 |
this.scene.remove(bullet);
|
| 1815 |
this.fighter.bullets.splice(i, 1);
|
| 1816 |
|
|
|
|
| 1832 |
this.enemies.forEach(enemy => {
|
| 1833 |
enemy.bullets.forEach((bullet, index) => {
|
| 1834 |
const distance = bullet.position.distanceTo(this.fighter.position);
|
| 1835 |
+
if (distance < 100) { // 65μμ 100μΌλ‘ μ¦κ° (100% νλ)
|
| 1836 |
this.scene.remove(bullet);
|
| 1837 |
enemy.bullets.splice(index, 1);
|
| 1838 |
|