cutechicken commited on
Commit
3b64f64
ยท
verified ยท
1 Parent(s): 02c1d69

Update game.js

Browse files
Files changed (1) hide show
  1. game.js +148 -14
game.js CHANGED
@@ -737,6 +737,13 @@ class EnemyFighter {
737
  this.targetPosition = null;
738
  this.playerFighter = null;
739
 
 
 
 
 
 
 
 
740
  // ์ „ํˆฌ ์‹œ์Šคํ…œ
741
  this.bullets = [];
742
  this.burstCounter = 0; // ํ˜„์žฌ ์—ฐ๋ฐœ ์นด์šดํ„ฐ
@@ -804,18 +811,31 @@ class EnemyFighter {
804
  update(playerPosition, deltaTime) {
805
  if (!this.mesh || !this.isLoaded) return;
806
 
 
 
 
 
 
 
 
 
807
  const distanceToPlayer = this.position.distanceTo(playerPosition);
808
 
809
- // ์ƒํƒœ ๊ฒฐ์ • - ๋‹จ์ˆœํ™”
810
- if (distanceToPlayer <= 3000) {
 
 
811
  this.aiState = 'combat';
812
  } else {
813
  this.aiState = 'patrol';
814
  }
815
 
816
- // ์ถฉ๋Œ ํšŒํ”ผ ๊ณ„์‚ฐ
817
  this.calculateAvoidance();
818
 
 
 
 
819
  // AI ํ–‰๋™ ์‹คํ–‰
820
  switch (this.aiState) {
821
  case 'patrol':
@@ -824,6 +844,9 @@ class EnemyFighter {
824
  case 'combat':
825
  this.executeCombat(playerPosition, deltaTime);
826
  break;
 
 
 
827
  }
828
 
829
  // ๋ฌผ๋ฆฌ ์—…๋ฐ์ดํŠธ
@@ -883,7 +906,82 @@ class EnemyFighter {
883
  }
884
  }
885
 
886
- // AI ์ƒํƒœ (ํšŒํ”ผ ๊ด€๋ จ ๋กœ์ง ์ œ๊ฑฐ, patrol๊ณผ combat๋งŒ ์œ ์ง€)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
 
888
  smoothTurnToTarget(targetPos, deltaTime) {
889
  // ํƒ€๊ฒŸ ๋ฐฉํ–ฅ ๊ณ„์‚ฐ
@@ -891,9 +989,11 @@ class EnemyFighter {
891
  direction.y *= 0.5; // ์ˆ˜์ง ์ด๋™์„ ๋œ ์ œํ•œ์ ์œผ๋กœ
892
  direction.normalize();
893
 
894
- // ์ถฉ๋Œ ํšŒํ”ผ ๋ฒกํ„ฐ ์ ์šฉ
895
  if (this.avoidanceVector.length() > 0) {
896
- direction.add(this.avoidanceVector.multiplyScalar(0.5));
 
 
897
  direction.normalize();
898
  }
899
 
@@ -902,12 +1002,11 @@ class EnemyFighter {
902
  const targetPitch = Math.asin(-direction.y);
903
 
904
  // ๋ถ€๋“œ๋Ÿฌ์šด ํšŒ์ „ (์ตœ๋Œ€ ํšŒ์ „ ์†๋„ ์ œํ•œ)
905
- const yawDiff = this.normalizeAngle(targetYaw - this.rotation.y);
906
- const pitchDiff = targetPitch - this.rotation.x;
907
-
908
- const maxTurnRate = this.turnSpeed * deltaTime;
909
 
910
  // Yaw ํšŒ์ „
 
911
  if (Math.abs(yawDiff) > maxTurnRate) {
912
  this.rotation.y += Math.sign(yawDiff) * maxTurnRate;
913
  } else {
@@ -916,8 +1015,8 @@ class EnemyFighter {
916
 
917
  // Pitch ํšŒ์ „ (์ œํ•œ์ )
918
  const maxPitchRate = maxTurnRate * 0.7; // ํ”ผ์น˜๋Š” ์กฐ๊ธˆ ๋” ๋น ๋ฅด๊ฒŒ
919
- if (Math.abs(pitchDiff) > maxPitchRate) {
920
- this.rotation.x += Math.sign(pitchDiff) * maxPitchRate;
921
  } else {
922
  this.rotation.x = targetPitch;
923
  }
@@ -925,6 +1024,12 @@ class EnemyFighter {
925
  // Pitch ์ œํ•œ (ยฑ40๋„)
926
  const maxPitchAngle = Math.PI * 40 / 180; // 40๋„๋ฅผ ๋ผ๋””์•ˆ์œผ๋กœ
927
  this.rotation.x = THREE.MathUtils.clamp(this.rotation.x, -maxPitchAngle, maxPitchAngle);
 
 
 
 
 
 
928
  }
929
 
930
  calculateAvoidance() {
@@ -933,15 +1038,36 @@ class EnemyFighter {
933
  if (!this.nearbyEnemies) return;
934
 
935
  let avoidCount = 0;
 
936
 
937
  this.nearbyEnemies.forEach(enemy => {
938
  if (enemy === this || !enemy.position) return;
939
 
940
  const distance = this.position.distanceTo(enemy.position);
941
- if (distance < 300 && distance > 0) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
942
  // ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ํšŒํ”ผ
943
  const avoidDir = this.position.clone().sub(enemy.position).normalize();
944
- const strength = (300 - distance) / 300;
945
  this.avoidanceVector.add(avoidDir.multiplyScalar(strength));
946
  avoidCount++;
947
  }
@@ -950,6 +1076,14 @@ class EnemyFighter {
950
  if (avoidCount > 0) {
951
  this.avoidanceVector.divideScalar(avoidCount);
952
  this.avoidanceVector.normalize();
 
 
 
 
 
 
 
 
953
  }
954
  }
955
 
 
737
  this.targetPosition = null;
738
  this.playerFighter = null;
739
 
740
+ // ํšŒํ”ผ ์‹œ์Šคํ…œ
741
+ this.temporaryEvadeMode = false;
742
+ this.evadeTimer = 0;
743
+
744
+ // ์ถฉ๋Œ ์˜ˆ์ธก
745
+ this.predictedPosition = new THREE.Vector3();
746
+
747
  // ์ „ํˆฌ ์‹œ์Šคํ…œ
748
  this.bullets = [];
749
  this.burstCounter = 0; // ํ˜„์žฌ ์—ฐ๋ฐœ ์นด์šดํ„ฐ
 
811
  update(playerPosition, deltaTime) {
812
  if (!this.mesh || !this.isLoaded) return;
813
 
814
+ // ํšŒํ”ผ ํƒ€์ด๋จธ ์—…๋ฐ์ดํŠธ
815
+ if (this.temporaryEvadeMode && this.evadeTimer > 0) {
816
+ this.evadeTimer -= deltaTime;
817
+ if (this.evadeTimer <= 0) {
818
+ this.temporaryEvadeMode = false;
819
+ }
820
+ }
821
+
822
  const distanceToPlayer = this.position.distanceTo(playerPosition);
823
 
824
+ // ์ƒํƒœ ๊ฒฐ์ • - ์ผ์‹œ์  ํšŒํ”ผ ๋ชจ๋“œ๊ฐ€ ์šฐ์„ 
825
+ if (this.temporaryEvadeMode) {
826
+ this.aiState = 'evade';
827
+ } else if (distanceToPlayer <= 3000) {
828
  this.aiState = 'combat';
829
  } else {
830
  this.aiState = 'patrol';
831
  }
832
 
833
+ // ์ถฉ๋Œ ํšŒํ”ผ ๊ณ„์‚ฐ (ํ•ญ์ƒ ์‹คํ–‰)
834
  this.calculateAvoidance();
835
 
836
+ // ์ถฉ๋Œ ์˜ˆ์ธก ๊ฒ€์‚ฌ
837
+ this.checkCollisionPrediction(deltaTime);
838
+
839
  // AI ํ–‰๋™ ์‹คํ–‰
840
  switch (this.aiState) {
841
  case 'patrol':
 
844
  case 'combat':
845
  this.executeCombat(playerPosition, deltaTime);
846
  break;
847
+ case 'evade':
848
+ this.executeEmergencyEvade(deltaTime);
849
+ break;
850
  }
851
 
852
  // ๋ฌผ๋ฆฌ ์—…๋ฐ์ดํŠธ
 
906
  }
907
  }
908
 
909
+ // ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ: ์ถฉ๋Œ ์˜ˆ์ธก
910
+ checkCollisionPrediction(deltaTime) {
911
+ if (!this.nearbyEnemies) return;
912
+
913
+ // 2์ดˆ ํ›„ ์˜ˆ์ƒ ์œ„์น˜ ๊ณ„์‚ฐ
914
+ const predictTime = 2.0;
915
+ const forward = new THREE.Vector3(0, 0, 1).applyEuler(this.rotation);
916
+ this.predictedPosition.copy(this.position).add(forward.multiplyScalar(this.speed * predictTime));
917
+
918
+ this.nearbyEnemies.forEach(enemy => {
919
+ if (enemy === this || !enemy.position) return;
920
+
921
+ // ๋‹ค๋ฅธ ์ ๊ธฐ์˜ ์˜ˆ์ƒ ์œ„์น˜
922
+ const enemyForward = new THREE.Vector3(0, 0, 1).applyEuler(enemy.rotation);
923
+ const enemyPredicted = enemy.position.clone().add(enemyForward.multiplyScalar(enemy.speed * predictTime));
924
+
925
+ // ์˜ˆ์ƒ ๊ฑฐ๋ฆฌ
926
+ const predictedDistance = this.predictedPosition.distanceTo(enemyPredicted);
927
+
928
+ // 150m ์ด๋‚ด๋กœ ์ ‘๊ทผ ์˜ˆ์ƒ ์‹œ ์‚ฌ์ „ ํšŒํ”ผ
929
+ if (predictedDistance < 150) {
930
+ // ์˜ˆ๋ฐฉ์  ํšŒํ”ผ ๋ฐฉํ–ฅ ์„ค์ •
931
+ const avoidDir = this.predictedPosition.clone().sub(enemyPredicted).normalize();
932
+
933
+ // ์ˆ˜์ง ๋ถ„๋ฆฌ ์ถ”๊ฐ€
934
+ if (this.position.y > enemy.position.y) {
935
+ avoidDir.y += 0.3;
936
+ } else {
937
+ avoidDir.y -= 0.3;
938
+ }
939
+
940
+ this.avoidanceVector.add(avoidDir.multiplyScalar(1.5));
941
+ }
942
+ });
943
+ }
944
+
945
+ // ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ: ๊ธด๊ธ‰ ํšŒํ”ผ ์‹คํ–‰
946
+ executeEmergencyEvade(deltaTime) {
947
+ // ํšŒํ”ผ ๋ฒกํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ ๋ฐฉํ–ฅ์œผ๋กœ, ์—†์œผ๋ฉด ๊ธ‰์ƒ์Šน
948
+ if (this.avoidanceVector.length() > 0) {
949
+ const evadeDirection = this.avoidanceVector.clone().normalize();
950
+
951
+ // ๊ธ‰์„ ํšŒ
952
+ const targetYaw = Math.atan2(evadeDirection.x, evadeDirection.z);
953
+ const targetPitch = Math.asin(-evadeDirection.y) * 0.5; // ํ”ผ์น˜๋Š” ์ ˆ๋ฐ˜๋งŒ
954
+
955
+ // ๋น ๋ฅธ ํšŒ์ „ ์†๋„
956
+ const emergencyTurnSpeed = this.turnSpeed * 2.0;
957
+ const maxTurnRate = emergencyTurnSpeed * deltaTime;
958
+
959
+ // Yaw ํšŒ์ „
960
+ const yawDiff = this.normalizeAngle(targetYaw - this.rotation.y);
961
+ if (Math.abs(yawDiff) > maxTurnRate) {
962
+ this.rotation.y += Math.sign(yawDiff) * maxTurnRate;
963
+ } else {
964
+ this.rotation.y = targetYaw;
965
+ }
966
+
967
+ // Pitch ํšŒ์ „
968
+ const pitchDiff = targetPitch - this.rotation.x;
969
+ if (Math.abs(pitchDiff) > maxTurnRate * 0.7) {
970
+ this.rotation.x += Math.sign(pitchDiff) * maxTurnRate * 0.7;
971
+ } else {
972
+ this.rotation.x = targetPitch;
973
+ }
974
+
975
+ // ๊ธ‰์„ ํšŒ ์‹œ ์•ฝ๊ฐ„์˜ ๋กค ์ถ”๊ฐ€
976
+ this.rotation.z = Math.sign(yawDiff) * Math.min(Math.abs(yawDiff), Math.PI / 6);
977
+ } else {
978
+ // ๊ธฐ๋ณธ ํšŒํ”ผ: ๊ธ‰์ƒ์Šน
979
+ this.rotation.x = -Math.PI / 6; // 30๋„ ์ƒ์Šน
980
+ }
981
+
982
+ // ํšŒํ”ผ ์ค‘์—๋Š” ์ตœ๋Œ€ ์†๋„
983
+ this.speed = this.maxSpeed;
984
+ }
985
 
986
  smoothTurnToTarget(targetPos, deltaTime) {
987
  // ํƒ€๊ฒŸ ๋ฐฉํ–ฅ ๊ณ„์‚ฐ
 
989
  direction.y *= 0.5; // ์ˆ˜์ง ์ด๋™์„ ๋œ ์ œํ•œ์ ์œผ๋กœ
990
  direction.normalize();
991
 
992
+ // ์ถฉ๋Œ ํšŒํ”ผ ๋ฒกํ„ฐ ์ ์šฉ (ํšŒํ”ผ๊ฐ€ ์šฐ์„ )
993
  if (this.avoidanceVector.length() > 0) {
994
+ // ํšŒํ”ผ ๋ชจ๋“œ์—์„œ๋Š” ํšŒํ”ผ ๋ฒกํ„ฐ์˜ ์˜ํ–ฅ์„ ํฌ๊ฒŒ
995
+ const avoidanceStrength = this.temporaryEvadeMode ? 1.0 : 0.5;
996
+ direction.add(this.avoidanceVector.multiplyScalar(avoidanceStrength));
997
  direction.normalize();
998
  }
999
 
 
1002
  const targetPitch = Math.asin(-direction.y);
1003
 
1004
  // ๋ถ€๋“œ๋Ÿฌ์šด ํšŒ์ „ (์ตœ๋Œ€ ํšŒ์ „ ์†๋„ ์ œํ•œ)
1005
+ const turnSpeed = this.temporaryEvadeMode ? this.turnSpeed * 1.5 : this.turnSpeed;
1006
+ const maxTurnRate = turnSpeed * deltaTime;
 
 
1007
 
1008
  // Yaw ํšŒ์ „
1009
+ const yawDiff = this.normalizeAngle(targetYaw - this.rotation.y);
1010
  if (Math.abs(yawDiff) > maxTurnRate) {
1011
  this.rotation.y += Math.sign(yawDiff) * maxTurnRate;
1012
  } else {
 
1015
 
1016
  // Pitch ํšŒ์ „ (์ œํ•œ์ )
1017
  const maxPitchRate = maxTurnRate * 0.7; // ํ”ผ์น˜๋Š” ์กฐ๊ธˆ ๋” ๋น ๋ฅด๊ฒŒ
1018
+ if (Math.abs(targetPitch - this.rotation.x) > maxPitchRate) {
1019
+ this.rotation.x += Math.sign(targetPitch - this.rotation.x) * maxPitchRate;
1020
  } else {
1021
  this.rotation.x = targetPitch;
1022
  }
 
1024
  // Pitch ์ œํ•œ (ยฑ40๋„)
1025
  const maxPitchAngle = Math.PI * 40 / 180; // 40๋„๋ฅผ ๋ผ๋””์•ˆ์œผ๋กœ
1026
  this.rotation.x = THREE.MathUtils.clamp(this.rotation.x, -maxPitchAngle, maxPitchAngle);
1027
+
1028
+ // ๋กค ์ž๋™ ๊ณ„์‚ฐ (์„ ํšŒ ์‹œ)
1029
+ if (!this.temporaryEvadeMode) {
1030
+ this.rotation.z = -yawDiff * 0.5; // ์„ ํšŒ ๋ฐฉํ–ฅ์œผ๋กœ ๊ธฐ์šธ๊ธฐ
1031
+ this.rotation.z = THREE.MathUtils.clamp(this.rotation.z, -Math.PI / 4, Math.PI / 4);
1032
+ }
1033
  }
1034
 
1035
  calculateAvoidance() {
 
1038
  if (!this.nearbyEnemies) return;
1039
 
1040
  let avoidCount = 0;
1041
+ let criticalAvoidance = false;
1042
 
1043
  this.nearbyEnemies.forEach(enemy => {
1044
  if (enemy === this || !enemy.position) return;
1045
 
1046
  const distance = this.position.distanceTo(enemy.position);
1047
+
1048
+ // 100m ๋ฏธ๋งŒ: ๊ธด๊ธ‰ ํšŒํ”ผ
1049
+ if (distance < 100 && distance > 0) {
1050
+ criticalAvoidance = true;
1051
+
1052
+ // ๊ฐ•ํ•œ ๋ฐ˜๋ฐœ๋ ฅ
1053
+ const avoidDir = this.position.clone().sub(enemy.position).normalize();
1054
+ const strength = 2.0; // ๋งค์šฐ ๊ฐ•ํ•œ ํšŒํ”ผ
1055
+ this.avoidanceVector.add(avoidDir.multiplyScalar(strength));
1056
+
1057
+ // ๊ณ ๋„ ์ฐจ์ด ์ถ”๊ฐ€ (์œ„/์•„๋ž˜๋กœ ๋ถ„์‚ฐ)
1058
+ if (this.position.y > enemy.position.y) {
1059
+ this.avoidanceVector.y += 0.5; // ์œ„๋กœ
1060
+ } else {
1061
+ this.avoidanceVector.y -= 0.5; // ์•„๋ž˜๋กœ
1062
+ }
1063
+
1064
+ avoidCount++;
1065
+ }
1066
+ // 100-300m: ์˜ˆ๋ฐฉ์  ํšŒํ”ผ
1067
+ else if (distance < 300) {
1068
  // ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ ํšŒํ”ผ
1069
  const avoidDir = this.position.clone().sub(enemy.position).normalize();
1070
+ const strength = (300 - distance) / 200; // 100-300m ๋ฒ”์œ„์—์„œ ๊ฐ•๋„ ๊ณ„์‚ฐ
1071
  this.avoidanceVector.add(avoidDir.multiplyScalar(strength));
1072
  avoidCount++;
1073
  }
 
1076
  if (avoidCount > 0) {
1077
  this.avoidanceVector.divideScalar(avoidCount);
1078
  this.avoidanceVector.normalize();
1079
+
1080
+ // ๊ธด๊ธ‰ ํšŒํ”ผ ์‹œ ๋” ๊ฐ•ํ•œ ํšŒํ”ผ๋ ฅ ์ ์šฉ
1081
+ if (criticalAvoidance) {
1082
+ this.avoidanceVector.multiplyScalar(2.0);
1083
+ // ์ผ์‹œ์ ์œผ๋กœ ์ „ํˆฌ ์ƒํƒœ ํ•ด์ œ
1084
+ this.temporaryEvadeMode = true;
1085
+ this.evadeTimer = 2.0; // 2์ดˆ ๋™๏ฟฝ๏ฟฝ๏ฟฝ ํšŒํ”ผ ์šฐ์„ 
1086
+ }
1087
  }
1088
  }
1089