Update game.js
Browse files
game.js
CHANGED
|
@@ -441,11 +441,11 @@ class Fighter {
|
|
| 441 |
|
| 442 |
// 1.5์ด ์ด์ Over-G ์ํ์ผ ๊ฒฝ์ฐ ์์ผ ํ๋ฆผ ์์
|
| 443 |
if (this.overGTimer > 1.5) {
|
| 444 |
-
// ์๋ ๊ธ๊ฒฉํ ๊ฐ์ (
|
| 445 |
-
if (this.overGTimer >
|
| 446 |
-
targetSpeed *= Math.max(0, 1 - (this.overGTimer -
|
| 447 |
}
|
| 448 |
-
// ์์ผ ํ๋ฆผ ํจ๊ณผ๋ UI์์ ์ฒ๋ฆฌ (1์ด๋ถํฐ)
|
| 449 |
}
|
| 450 |
} else {
|
| 451 |
this.overGTimer = 0; // Over-G ์ํ๊ฐ ์๋๋ฉด ํ์ด๋จธ ๋ฆฌ์
|
|
@@ -697,31 +697,29 @@ class EnemyFighter {
|
|
| 697 |
|
| 698 |
// ๊ฐ์ ๋ AI ์ํ
|
| 699 |
this.aiState = 'patrol';
|
| 700 |
-
this.targetPosition =
|
| 701 |
-
this.
|
| 702 |
-
this.patrolRadius = 3000;
|
| 703 |
-
this.lastStateChange = 0;
|
| 704 |
this.playerFighter = null; // ํ๋ ์ด์ด ์ฐธ์กฐ ์ ์ฅ์ฉ
|
| 705 |
|
| 706 |
-
//
|
| 707 |
-
this.targetRotation = new THREE.Euler(0,
|
| 708 |
-
this.
|
| 709 |
-
this.
|
| 710 |
-
this.
|
| 711 |
-
this.throttle = 0.75; // ๊ธฐ๋ณธ ์ค๋กํ 75%
|
| 712 |
-
|
| 713 |
-
// ํํผ ๊ธฐ๋
|
| 714 |
-
this.evasionTimer = 0;
|
| 715 |
-
this.evasionPattern = 0;
|
| 716 |
|
| 717 |
// ๋ค๋ฅธ ์ ๊ธฐ๋ค๊ณผ์ ์ถฉ๋ ํํผ
|
| 718 |
this.nearbyEnemies = [];
|
| 719 |
this.separationRadius = 300; // ์ต์ ๊ฑฐ๋ฆฌ 300m
|
| 720 |
-
|
| 721 |
-
|
| 722 |
-
|
| 723 |
-
|
| 724 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 725 |
}
|
| 726 |
|
| 727 |
async initialize(loader) {
|
|
@@ -778,62 +776,84 @@ class EnemyFighter {
|
|
| 778 |
const currentTime = Date.now();
|
| 779 |
const distanceToPlayer = this.position.distanceTo(playerPosition);
|
| 780 |
|
| 781 |
-
//
|
|
|
|
| 782 |
if (distanceToPlayer < 3000) {
|
| 783 |
-
|
| 784 |
-
|
| 785 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
}
|
| 787 |
-
}
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
}
|
| 792 |
} else {
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
}
|
| 797 |
}
|
| 798 |
|
| 799 |
-
//
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
this.updateApproachBehavior(playerPosition, deltaTime);
|
| 806 |
-
break;
|
| 807 |
-
case 'patrol':
|
| 808 |
-
this.updatePatrolBehavior(deltaTime);
|
| 809 |
-
break;
|
| 810 |
}
|
| 811 |
|
| 812 |
// ๋ค๋ฅธ ์ ๊ธฐ์์ ์ถฉ๋ ํํผ
|
| 813 |
this.avoidOtherEnemies(deltaTime);
|
| 814 |
|
| 815 |
-
// ๋ถ๋๋ฌ์ด ํ์
|
| 816 |
this.rotation.x = THREE.MathUtils.lerp(this.rotation.x, this.targetRotation.x, deltaTime * 2.0);
|
| 817 |
-
this.rotation.y = THREE.MathUtils.lerp(this.rotation.y, this.targetRotation.y, deltaTime *
|
| 818 |
this.rotation.z = THREE.MathUtils.lerp(this.rotation.z, this.targetRotation.z, deltaTime * 2.5);
|
| 819 |
|
| 820 |
-
// ์๋ ๊ณ์ฐ
|
| 821 |
-
const targetSpeed = this.speed * this.throttle;
|
| 822 |
-
const currentSpeed = this.velocity.length();
|
| 823 |
-
const newSpeed = THREE.MathUtils.lerp(currentSpeed, targetSpeed, deltaTime * 0.5);
|
| 824 |
-
|
| 825 |
-
// ๋ฐฉํฅ ๋ฒกํฐ ๊ณ์ฐ
|
| 826 |
const forward = new THREE.Vector3(0, 0, 1);
|
| 827 |
forward.applyEuler(this.rotation);
|
| 828 |
-
|
| 829 |
-
// ์ค๋ ฅ๊ณผ ์๋ ฅ ํจ๊ณผ
|
| 830 |
-
const liftFactor = Math.min(1.0, newSpeed / this.speed);
|
| 831 |
-
const gravityEffect = GAME_CONSTANTS.GRAVITY * deltaTime * 0.15;
|
| 832 |
-
const lift = gravityEffect * liftFactor * 0.8;
|
| 833 |
-
|
| 834 |
-
// ์๋ ๋ฒกํฐ ์
๋ฐ์ดํธ
|
| 835 |
-
this.velocity = forward.multiplyScalar(newSpeed);
|
| 836 |
-
this.velocity.y += (lift - gravityEffect);
|
| 837 |
|
| 838 |
// ์์น ์
๋ฐ์ดํธ
|
| 839 |
this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
|
|
@@ -841,20 +861,23 @@ class EnemyFighter {
|
|
| 841 |
// ๊ณ ๋ ์ ํ
|
| 842 |
if (this.position.y < 500) {
|
| 843 |
this.position.y = 500;
|
| 844 |
-
this.targetRotation.x =
|
| 845 |
}
|
| 846 |
if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE - 500) {
|
| 847 |
this.position.y = GAME_CONSTANTS.MAX_ALTITUDE - 500;
|
| 848 |
-
this.targetRotation.x =
|
| 849 |
}
|
| 850 |
|
| 851 |
// ๋งต ๊ฒฝ๊ณ ์ฒ๋ฆฌ
|
| 852 |
const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
|
| 853 |
-
if (Math.abs(this.position.x) > mapLimit * 0.
|
| 854 |
-
// ๋งต ๊ฒฝ๊ณ์ ๊ฐ๊น์์ง๋ฉด ์ค์์ผ๋ก
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
|
|
|
|
|
|
|
|
|
| 858 |
}
|
| 859 |
|
| 860 |
// ๋ฉ์ ์
๋ฐ์ดํธ
|
|
@@ -866,132 +889,37 @@ class EnemyFighter {
|
|
| 866 |
this.updateBullets(deltaTime);
|
| 867 |
}
|
| 868 |
|
| 869 |
-
updateCombatBehavior(playerPosition, deltaTime, currentTime) {
|
| 870 |
-
const toPlayer = playerPosition.clone().sub(this.position);
|
| 871 |
-
const distance = toPlayer.length();
|
| 872 |
-
toPlayer.normalize();
|
| 873 |
-
|
| 874 |
-
// ๊ณต๊ฒฉ ๊ฐ๋ ๊ณ์ฐ
|
| 875 |
-
const angle = Math.atan2(toPlayer.x, toPlayer.z);
|
| 876 |
-
const pitchAngle = Math.atan2(-toPlayer.y, Math.sqrt(toPlayer.x * toPlayer.x + toPlayer.z * toPlayer.z));
|
| 877 |
-
|
| 878 |
-
// BFM (Basic Fighter Maneuvers) ๊ตฌํ
|
| 879 |
-
if (distance < 1000) {
|
| 880 |
-
// ๋๋ฌด ๊ฐ๊น์ฐ๋ฉด ํํผ ๊ธฐ๋
|
| 881 |
-
this.evasionTimer += deltaTime;
|
| 882 |
-
if (this.evasionTimer > 2.0) {
|
| 883 |
-
this.evasionTimer = 0;
|
| 884 |
-
this.evasionPattern = Math.floor(Math.random() * 3);
|
| 885 |
-
}
|
| 886 |
-
|
| 887 |
-
switch(this.evasionPattern) {
|
| 888 |
-
case 0: // ๋ฐฐ๋ด ๋กค
|
| 889 |
-
this.targetRotation.z = Math.sin(this.evasionTimer * Math.PI) * 1.5;
|
| 890 |
-
this.targetRotation.x = pitchAngle + Math.sin(this.evasionTimer * Math.PI * 2) * 0.3;
|
| 891 |
-
break;
|
| 892 |
-
case 1: // ์ด๋ฉ๋ง ํด
|
| 893 |
-
this.targetRotation.x = -0.5 + this.evasionTimer * 0.5;
|
| 894 |
-
this.targetRotation.z = this.evasionTimer * Math.PI;
|
| 895 |
-
break;
|
| 896 |
-
case 2: // ์คํ๋ฆฟ S
|
| 897 |
-
this.targetRotation.x = 0.5 - this.evasionTimer * 0.5;
|
| 898 |
-
this.targetRotation.z = Math.PI;
|
| 899 |
-
break;
|
| 900 |
-
}
|
| 901 |
-
this.throttle = 1.0; // ์ต๋ ์๋๋ก ํํผ
|
| 902 |
-
} else if (distance < 2000) {
|
| 903 |
-
// ๊ณต๊ฒฉ ์์น ์ ์
|
| 904 |
-
this.targetRotation.y = angle;
|
| 905 |
-
this.targetRotation.x = pitchAngle;
|
| 906 |
-
this.targetRotation.z = 0;
|
| 907 |
-
|
| 908 |
-
// ๋ฆฌ๋ ์ต๊ธ ๊ณ์ฐ (์์ธก ์ฌ๊ฒฉ)
|
| 909 |
-
const playerVelocity = this.playerFighter ? this.playerFighter.velocity : new THREE.Vector3();
|
| 910 |
-
const bulletTime = distance / 1200; // ํํ ์๋
|
| 911 |
-
const leadPosition = playerPosition.clone().add(playerVelocity.clone().multiplyScalar(bulletTime));
|
| 912 |
-
const leadDirection = leadPosition.sub(this.position).normalize();
|
| 913 |
-
const leadAngle = Math.atan2(leadDirection.x, leadDirection.z);
|
| 914 |
-
|
| 915 |
-
this.targetRotation.y = leadAngle;
|
| 916 |
-
|
| 917 |
-
// ์ฌ๊ฒฉ
|
| 918 |
-
if (currentTime - this.lastShootTime > 800) {
|
| 919 |
-
this.shoot();
|
| 920 |
-
}
|
| 921 |
-
|
| 922 |
-
this.throttle = 0.9;
|
| 923 |
-
} else {
|
| 924 |
-
// ์ถ์
|
| 925 |
-
this.targetRotation.y = angle;
|
| 926 |
-
this.targetRotation.x = pitchAngle * 0.5; // ๋ถ๋๋ฌ์ด ํผ์น ์กฐ์
|
| 927 |
-
this.targetRotation.z = 0;
|
| 928 |
-
this.throttle = 0.85;
|
| 929 |
-
}
|
| 930 |
-
}
|
| 931 |
-
|
| 932 |
-
updateApproachBehavior(playerPosition, deltaTime) {
|
| 933 |
-
const toPlayer = playerPosition.clone().sub(this.position);
|
| 934 |
-
const angle = Math.atan2(toPlayer.x, toPlayer.z);
|
| 935 |
-
|
| 936 |
-
// ๋ถ๋๋ฌ์ด ์ ๊ทผ
|
| 937 |
-
this.targetRotation.y = angle;
|
| 938 |
-
this.targetRotation.x = 0;
|
| 939 |
-
this.targetRotation.z = Math.sin(Date.now() * 0.001) * 0.3; // ์ฝ๊ฐ์ ๋กค๋ง
|
| 940 |
-
this.throttle = 0.8;
|
| 941 |
-
}
|
| 942 |
-
|
| 943 |
-
updatePatrolBehavior(deltaTime) {
|
| 944 |
-
// ์์ฐฐ ํจํด
|
| 945 |
-
if (this.position.distanceTo(this.targetPosition) < 500) {
|
| 946 |
-
// ์๋ก์ด ์์ฐฐ ์ง์ ์ค์
|
| 947 |
-
const angle = Math.random() * Math.PI * 2;
|
| 948 |
-
const distance = this.patrolRadius * (0.5 + Math.random() * 0.5);
|
| 949 |
-
this.targetPosition = this.patrolCenter.clone().add(
|
| 950 |
-
new THREE.Vector3(
|
| 951 |
-
Math.cos(angle) * distance,
|
| 952 |
-
(Math.random() - 0.5) * 1000,
|
| 953 |
-
Math.sin(angle) * distance
|
| 954 |
-
)
|
| 955 |
-
);
|
| 956 |
-
}
|
| 957 |
-
|
| 958 |
-
const toTarget = this.targetPosition.clone().sub(this.position);
|
| 959 |
-
const angle = Math.atan2(toTarget.x, toTarget.z);
|
| 960 |
-
|
| 961 |
-
this.targetRotation.y = angle;
|
| 962 |
-
this.targetRotation.x = 0;
|
| 963 |
-
this.targetRotation.z = Math.sin(Date.now() * 0.0005) * 0.2; // ์๋งํ ๋กค๋ง
|
| 964 |
-
this.throttle = 0.7;
|
| 965 |
-
}
|
| 966 |
-
|
| 967 |
avoidOtherEnemies(deltaTime) {
|
| 968 |
if (!this.nearbyEnemies) return;
|
| 969 |
|
| 970 |
-
let
|
| 971 |
-
let
|
|
|
|
| 972 |
|
| 973 |
this.nearbyEnemies.forEach(enemy => {
|
| 974 |
if (enemy === this || !enemy.position) return;
|
| 975 |
|
| 976 |
const distance = this.position.distanceTo(enemy.position);
|
| 977 |
if (distance < this.separationRadius && distance > 0) {
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
|
|
|
| 983 |
}
|
| 984 |
});
|
| 985 |
|
| 986 |
-
if (
|
| 987 |
-
//
|
| 988 |
-
const avoidAngle = Math.atan2(
|
| 989 |
-
this.targetRotation.y =
|
|
|
|
| 990 |
|
| 991 |
-
//
|
| 992 |
-
if (
|
| 993 |
this.targetRotation.x = -0.3; // ์์น
|
| 994 |
-
} else
|
| 995 |
this.targetRotation.x = 0.3; // ํ๊ฐ
|
| 996 |
}
|
| 997 |
}
|
|
@@ -1734,7 +1662,7 @@ class Game {
|
|
| 1734 |
}
|
| 1735 |
|
| 1736 |
// Over-G ์์ผ ํจ๊ณผ - ์์ ๋ ๋ถ๋ถ
|
| 1737 |
-
if (this.fighter.overG && this.fighter.overGTimer >
|
| 1738 |
let blurEffect = document.getElementById('overGBlurEffect');
|
| 1739 |
if (!blurEffect) {
|
| 1740 |
blurEffect = document.createElement('div');
|
|
@@ -1743,19 +1671,17 @@ class Game {
|
|
| 1743 |
}
|
| 1744 |
|
| 1745 |
// Over-G ์ง์ ์๊ฐ์ ๋ฐ๋ผ ์ ์ง์ ์ผ๋ก ์ด๋์์ง
|
| 1746 |
-
//
|
| 1747 |
-
// 1
|
| 1748 |
-
const darknessFactor = Math.min(
|
| 1749 |
|
| 1750 |
// ์์ผ ๊ฐ์ฅ์๋ฆฌ๋ถํฐ ์ด๋์์ง๋ ํจ๊ณผ
|
| 1751 |
// ์ค์์ ์๋์ ์ผ๋ก ๋ฆ๊ฒ ์ด๋์์ง
|
| 1752 |
-
const centerTransparency = Math.max(0, 1 - darknessFactor *
|
| 1753 |
-
const midTransparency = Math.max(0, 1 - darknessFactor * 0.
|
| 1754 |
-
const edgeOpacity = Math.min(0.
|
| 1755 |
-
|
| 1756 |
-
// ๋ถ์ ์์กฐ ์ถ๊ฐ (ํ์ก ์ํ ๋ฌธ์ ๋ฅผ ์๊ฐํ) - ์ฝํ๋ ๋ฒ์
|
| 1757 |
-
const redTint = Math.min(darknessFactor * 0.1, 0.1); // 0.3์์ 0.1๋ก ๊ฐ์
|
| 1758 |
|
|
|
|
| 1759 |
blurEffect.style.cssText = `
|
| 1760 |
position: fixed;
|
| 1761 |
top: 0;
|
|
@@ -1763,24 +1689,21 @@ class Game {
|
|
| 1763 |
width: 100%;
|
| 1764 |
height: 100%;
|
| 1765 |
background: radial-gradient(ellipse at center,
|
| 1766 |
-
rgba(
|
| 1767 |
-
rgba(
|
| 1768 |
-
rgba(0, 0, 0, ${edgeOpacity})
|
| 1769 |
-
rgba(0, 0, 0, ${Math.min(0.
|
| 1770 |
pointer-events: none;
|
| 1771 |
z-index: 1400;
|
| 1772 |
-
transition: background 0.
|
| 1773 |
`;
|
| 1774 |
|
| 1775 |
-
// ์ฌํ Over-G ์ํ์์ ํ๋ฉด ํ๋ค๋ฆผ ํจ๊ณผ
|
| 1776 |
-
if (darknessFactor > 0.
|
| 1777 |
-
const shake = (1 - Math.random() * 2) *
|
| 1778 |
blurEffect.style.transform = `translate(${shake}px, ${shake}px)`;
|
| 1779 |
}
|
| 1780 |
|
| 1781 |
-
// ๋๋ฒ๊ทธ ์ ๋ณด (์ ํ์ฌํญ)
|
| 1782 |
-
// console.log(`Over-G Timer: ${this.fighter.overGTimer.toFixed(2)}s, Darkness: ${(darknessFactor * 100).toFixed(0)}%`);
|
| 1783 |
-
|
| 1784 |
} else {
|
| 1785 |
// Over-G ์ํ๊ฐ ์๋๋ฉด ํจ๊ณผ ์ ๊ฑฐ
|
| 1786 |
const blurEffect = document.getElementById('overGBlurEffect');
|
|
|
|
| 441 |
|
| 442 |
// 1.5์ด ์ด์ Over-G ์ํ์ผ ๊ฒฝ์ฐ ์์ผ ํ๋ฆผ ์์
|
| 443 |
if (this.overGTimer > 1.5) {
|
| 444 |
+
// ์๋ ๊ธ๊ฒฉํ ๊ฐ์ (2.5์ด๋ถํฐ)
|
| 445 |
+
if (this.overGTimer > 2.5) {
|
| 446 |
+
targetSpeed *= Math.max(0.3, 1 - (this.overGTimer - 2.5) * 0.3);
|
| 447 |
}
|
| 448 |
+
// ์์ผ ํ๋ฆผ ํจ๊ณผ๋ UI์์ ์ฒ๋ฆฌ (1.5์ด๋ถํฐ)
|
| 449 |
}
|
| 450 |
} else {
|
| 451 |
this.overGTimer = 0; // Over-G ์ํ๊ฐ ์๋๋ฉด ํ์ด๋จธ ๋ฆฌ์
|
|
|
|
| 697 |
|
| 698 |
// ๊ฐ์ ๋ AI ์ํ
|
| 699 |
this.aiState = 'patrol';
|
| 700 |
+
this.targetPosition = this.generateRandomTarget();
|
| 701 |
+
this.lastDirectionChange = Date.now();
|
|
|
|
|
|
|
| 702 |
this.playerFighter = null; // ํ๋ ์ด์ด ์ฐธ์กฐ ์ ์ฅ์ฉ
|
| 703 |
|
| 704 |
+
// ๋ถ๋๋ฌ์ด ์ ํ๋ฅผ ์ํ ๋ณ์
|
| 705 |
+
this.targetRotation = new THREE.Euler(0, Math.random() * Math.PI * 2, 0);
|
| 706 |
+
this.turnRadius = 1500; // ์ ํ ๋ฐ๊ฒฝ
|
| 707 |
+
this.isTurning = false;
|
| 708 |
+
this.turnDirection = 1; // 1: ์ฐํ์ , -1: ์ขํ์
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 709 |
|
| 710 |
// ๋ค๋ฅธ ์ ๊ธฐ๋ค๊ณผ์ ์ถฉ๋ ํํผ
|
| 711 |
this.nearbyEnemies = [];
|
| 712 |
this.separationRadius = 300; // ์ต์ ๊ฑฐ๋ฆฌ 300m
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
generateRandomTarget() {
|
| 716 |
+
// ๋งต ๋ฒ์ ๋ด ๋๋ค ๋ชฉํ ์ง์ ์์ฑ
|
| 717 |
+
const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2 * 0.8;
|
| 718 |
+
return new THREE.Vector3(
|
| 719 |
+
(Math.random() - 0.5) * 2 * mapLimit,
|
| 720 |
+
1000 + Math.random() * 3000, // 1000m ~ 4000m ๊ณ ๋
|
| 721 |
+
(Math.random() - 0.5) * 2 * mapLimit
|
| 722 |
+
);
|
| 723 |
}
|
| 724 |
|
| 725 |
async initialize(loader) {
|
|
|
|
| 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 |
+
if (angle > 0.5) { // 120๋ ์์ผ๊ฐ
|
| 789 |
+
shouldAttack = true;
|
| 790 |
+
if (distanceToPlayer < 2000 && currentTime - this.lastShootTime > 800) {
|
| 791 |
+
this.shoot();
|
| 792 |
+
}
|
| 793 |
}
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
// ๋ชฉํ ์ง์ ๋๋ฌ ๋๋ ์ผ์ ์๊ฐ๋ง๋ค ์๋ก์ด ๋ชฉํ ์ค์
|
| 797 |
+
if (this.position.distanceTo(this.targetPosition) < 500 ||
|
| 798 |
+
currentTime - this.lastDirectionChange > 15000) { // 15์ด๋ง๋ค ๋ฐฉํฅ ๋ณ๊ฒฝ
|
| 799 |
+
this.targetPosition = this.generateRandomTarget();
|
| 800 |
+
this.lastDirectionChange = currentTime;
|
| 801 |
+
this.isTurning = false;
|
| 802 |
+
}
|
| 803 |
+
|
| 804 |
+
// ๋ชฉํ ๋ฐฉํฅ ๊ณ์ฐ
|
| 805 |
+
const toTarget = this.targetPosition.clone().sub(this.position);
|
| 806 |
+
const targetAngle = Math.atan2(toTarget.x, toTarget.z);
|
| 807 |
+
let angleDiff = targetAngle - this.rotation.y;
|
| 808 |
+
|
| 809 |
+
// ๊ฐ๋ ์ฐจ์ด๋ฅผ -PI ~ PI ๋ฒ์๋ก ์ ๊ทํ
|
| 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) { // 30๋ ์ด์
|
| 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) { // 15๋ ์ด๋ด
|
| 829 |
+
this.isTurning = false;
|
| 830 |
}
|
| 831 |
} else {
|
| 832 |
+
// ์ง์ง ๋นํ
|
| 833 |
+
this.targetRotation.y = THREE.MathUtils.lerp(this.targetRotation.y, targetAngle, deltaTime * 0.5);
|
| 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 |
this.rotation.x = THREE.MathUtils.lerp(this.rotation.x, this.targetRotation.x, deltaTime * 2.0);
|
| 850 |
+
this.rotation.y = THREE.MathUtils.lerp(this.rotation.y, this.targetRotation.y, deltaTime * 2.0);
|
| 851 |
this.rotation.z = THREE.MathUtils.lerp(this.rotation.z, this.targetRotation.z, deltaTime * 2.5);
|
| 852 |
|
| 853 |
+
// ์๋ ๋ฒกํฐ ๊ณ์ฐ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 854 |
const forward = new THREE.Vector3(0, 0, 1);
|
| 855 |
forward.applyEuler(this.rotation);
|
| 856 |
+
this.velocity = forward.multiplyScalar(this.speed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 857 |
|
| 858 |
// ์์น ์
๋ฐ์ดํธ
|
| 859 |
this.position.add(this.velocity.clone().multiplyScalar(deltaTime));
|
|
|
|
| 861 |
// ๊ณ ๋ ์ ํ
|
| 862 |
if (this.position.y < 500) {
|
| 863 |
this.position.y = 500;
|
| 864 |
+
this.targetRotation.x = -0.2; // ์์น
|
| 865 |
}
|
| 866 |
if (this.position.y > GAME_CONSTANTS.MAX_ALTITUDE - 500) {
|
| 867 |
this.position.y = GAME_CONSTANTS.MAX_ALTITUDE - 500;
|
| 868 |
+
this.targetRotation.x = 0.2; // ํ๊ฐ
|
| 869 |
}
|
| 870 |
|
| 871 |
// ๋งต ๊ฒฝ๊ณ ์ฒ๋ฆฌ
|
| 872 |
const mapLimit = GAME_CONSTANTS.MAP_SIZE / 2;
|
| 873 |
+
if (Math.abs(this.position.x) > mapLimit * 0.9 || Math.abs(this.position.z) > mapLimit * 0.9) {
|
| 874 |
+
// ๋งต ๊ฒฝ๊ณ์ ๊ฐ๊น์์ง๋ฉด ์ค์์ผ๋ก ํฅํ๋ ์ ๋ชฉํ ์ค์
|
| 875 |
+
this.targetPosition = new THREE.Vector3(
|
| 876 |
+
(Math.random() - 0.5) * mapLimit * 0.5,
|
| 877 |
+
1000 + Math.random() * 3000,
|
| 878 |
+
(Math.random() - 0.5) * mapLimit * 0.5
|
| 879 |
+
);
|
| 880 |
+
this.lastDirectionChange = currentTime;
|
| 881 |
}
|
| 882 |
|
| 883 |
// ๋ฉ์ ์
๋ฐ์ดํธ
|
|
|
|
| 889 |
this.updateBullets(deltaTime);
|
| 890 |
}
|
| 891 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 892 |
avoidOtherEnemies(deltaTime) {
|
| 893 |
if (!this.nearbyEnemies) return;
|
| 894 |
|
| 895 |
+
let closestDistance = Infinity;
|
| 896 |
+
let avoidanceNeeded = false;
|
| 897 |
+
let avoidDirection = new THREE.Vector3();
|
| 898 |
|
| 899 |
this.nearbyEnemies.forEach(enemy => {
|
| 900 |
if (enemy === this || !enemy.position) return;
|
| 901 |
|
| 902 |
const distance = this.position.distanceTo(enemy.position);
|
| 903 |
if (distance < this.separationRadius && distance > 0) {
|
| 904 |
+
avoidanceNeeded = true;
|
| 905 |
+
if (distance < closestDistance) {
|
| 906 |
+
closestDistance = distance;
|
| 907 |
+
// ๋ฐ๋ ๋ฐฉํฅ๏ฟฝ๏ฟฝ๋ก ํํผ
|
| 908 |
+
avoidDirection = this.position.clone().sub(enemy.position).normalize();
|
| 909 |
+
}
|
| 910 |
}
|
| 911 |
});
|
| 912 |
|
| 913 |
+
if (avoidanceNeeded) {
|
| 914 |
+
// ๊ธด๊ธ ํํผ: ๊ธ์ ํ
|
| 915 |
+
const avoidAngle = Math.atan2(avoidDirection.x, avoidDirection.z);
|
| 916 |
+
this.targetRotation.y = avoidAngle;
|
| 917 |
+
this.isTurning = true;
|
| 918 |
|
| 919 |
+
// ๊ณ ๋๋ ๋ณ๊ฒฝ
|
| 920 |
+
if (avoidDirection.y > 0) {
|
| 921 |
this.targetRotation.x = -0.3; // ์์น
|
| 922 |
+
} else {
|
| 923 |
this.targetRotation.x = 0.3; // ํ๊ฐ
|
| 924 |
}
|
| 925 |
}
|
|
|
|
| 1662 |
}
|
| 1663 |
|
| 1664 |
// Over-G ์์ผ ํจ๊ณผ - ์์ ๋ ๋ถ๋ถ
|
| 1665 |
+
if (this.fighter.overG && this.fighter.overGTimer > 1.5) {
|
| 1666 |
let blurEffect = document.getElementById('overGBlurEffect');
|
| 1667 |
if (!blurEffect) {
|
| 1668 |
blurEffect = document.createElement('div');
|
|
|
|
| 1671 |
}
|
| 1672 |
|
| 1673 |
// Over-G ์ง์ ์๊ฐ์ ๋ฐ๋ผ ์ ์ง์ ์ผ๋ก ์ด๋์์ง
|
| 1674 |
+
// 1.5์ด๋ถํฐ ์์ํ์ฌ ์์ํ ์งํ
|
| 1675 |
+
const adjustedTimer = Math.max(0, this.fighter.overGTimer - 1.5); // 1.5์ด ์ดํ๋ถํฐ ์นด์ดํธ
|
| 1676 |
+
const darknessFactor = Math.min(adjustedTimer / 2.0, 0.7); // 2์ด์ ๊ฑธ์ณ ์ต๋ 70%๊น์ง๋ง ์ด๋์์ง
|
| 1677 |
|
| 1678 |
// ์์ผ ๊ฐ์ฅ์๋ฆฌ๋ถํฐ ์ด๋์์ง๋ ํจ๊ณผ
|
| 1679 |
// ์ค์์ ์๋์ ์ผ๋ก ๋ฆ๊ฒ ์ด๋์์ง
|
| 1680 |
+
const centerTransparency = Math.max(0.3, 1 - darknessFactor * 0.8); // ์ค์์ ์ต์ 30% ํฌ๋ช
๋ ์ ์ง
|
| 1681 |
+
const midTransparency = Math.max(0.2, 1 - darknessFactor * 0.6); // ์ค๊ฐ ํฌ๋ช
๋
|
| 1682 |
+
const edgeOpacity = Math.min(0.8, darknessFactor * 0.8); // ๊ฐ์ฅ์๋ฆฌ ์ต๋ 80% ๋ถํฌ๋ช
|
|
|
|
|
|
|
|
|
|
| 1683 |
|
| 1684 |
+
// ๋ถ์ ์์กฐ ์ ๊ฑฐ, ๊ฒ์์๋ง ์ฌ์ฉ
|
| 1685 |
blurEffect.style.cssText = `
|
| 1686 |
position: fixed;
|
| 1687 |
top: 0;
|
|
|
|
| 1689 |
width: 100%;
|
| 1690 |
height: 100%;
|
| 1691 |
background: radial-gradient(ellipse at center,
|
| 1692 |
+
rgba(0, 0, 0, ${1 - centerTransparency}) 0%,
|
| 1693 |
+
rgba(0, 0, 0, ${1 - midTransparency}) 50%,
|
| 1694 |
+
rgba(0, 0, 0, ${edgeOpacity}) 80%,
|
| 1695 |
+
rgba(0, 0, 0, ${Math.min(0.85, edgeOpacity + 0.05)}) 100%);
|
| 1696 |
pointer-events: none;
|
| 1697 |
z-index: 1400;
|
| 1698 |
+
transition: background 0.3s ease-out;
|
| 1699 |
`;
|
| 1700 |
|
| 1701 |
+
// ์ฌํ Over-G ์ํ์์ ์ฝ๊ฐ์ ํ๋ฉด ํ๋ค๋ฆผ ํจ๊ณผ
|
| 1702 |
+
if (darknessFactor > 0.5) {
|
| 1703 |
+
const shake = (1 - Math.random() * 2) * 1;
|
| 1704 |
blurEffect.style.transform = `translate(${shake}px, ${shake}px)`;
|
| 1705 |
}
|
| 1706 |
|
|
|
|
|
|
|
|
|
|
| 1707 |
} else {
|
| 1708 |
// Over-G ์ํ๊ฐ ์๋๋ฉด ํจ๊ณผ ์ ๊ฑฐ
|
| 1709 |
const blurEffect = document.getElementById('overGBlurEffect');
|