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