Spaces:
Running
Running
cutechicken
commited on
Commit
โข
632d61f
1
Parent(s):
876ef81
Update game.js
Browse files
game.js
CHANGED
@@ -570,6 +570,7 @@ startReload() {
|
|
570 |
// Enemy ํด๋์ค
|
571 |
class Enemy {
|
572 |
constructor(scene, position, type = 'tank') {
|
|
|
573 |
this.scene = scene;
|
574 |
this.position = position;
|
575 |
this.mesh = null;
|
@@ -582,28 +583,213 @@ class Enemy {
|
|
582 |
|
583 |
// AI ์ํ ๊ด๋ฆฌ
|
584 |
this.aiState = {
|
585 |
-
mode: 'pursue',
|
586 |
lastStateChange: 0,
|
587 |
stateChangeCooldown: 3000,
|
588 |
lastVisibilityCheck: 0,
|
589 |
visibilityCheckInterval: 500,
|
590 |
canSeePlayer: false,
|
591 |
lastKnownPlayerPosition: null,
|
592 |
-
searchStartTime: null
|
|
|
|
|
|
|
|
|
|
|
593 |
};
|
594 |
|
595 |
-
// ๊ฒฝ๋ก ํ์
|
596 |
this.pathfinding = {
|
597 |
currentPath: [],
|
598 |
pathUpdateInterval: 1000,
|
599 |
lastPathUpdate: 0,
|
600 |
isAvoidingObstacle: false,
|
601 |
avoidanceDirection: null,
|
602 |
-
obstacleCheckDistance: 10
|
|
|
|
|
|
|
|
|
603 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
604 |
}
|
605 |
|
606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
607 |
try {
|
608 |
const modelPath = this.type === 'tank' ? '/models/t90.glb' : '/models/t90.glb';
|
609 |
const result = await loader.loadAsync(modelPath);
|
@@ -630,7 +816,7 @@ class Enemy {
|
|
630 |
if (!this.mesh) return false;
|
631 |
|
632 |
const startPos = this.mesh.position.clone();
|
633 |
-
startPos.y += 2;
|
634 |
const direction = new THREE.Vector3().subVectors(playerPosition, startPos).normalize();
|
635 |
const distance = startPos.distanceTo(playerPosition);
|
636 |
|
@@ -644,7 +830,6 @@ class Enemy {
|
|
644 |
const currentTime = Date.now();
|
645 |
const distanceToPlayer = this.mesh.position.distanceTo(playerPosition);
|
646 |
|
647 |
-
// ์์ผ ์ฒดํฌ
|
648 |
if (currentTime - this.aiState.lastVisibilityCheck > this.aiState.visibilityCheckInterval) {
|
649 |
this.aiState.canSeePlayer = this.checkLineOfSight(playerPosition);
|
650 |
this.aiState.lastVisibilityCheck = currentTime;
|
@@ -655,7 +840,6 @@ class Enemy {
|
|
655 |
}
|
656 |
}
|
657 |
|
658 |
-
// AI ์ํ ์
๋ฐ์ดํธ
|
659 |
if (currentTime - this.aiState.lastStateChange > this.aiState.stateChangeCooldown) {
|
660 |
if (this.health < 30) {
|
661 |
this.aiState.mode = 'retreat';
|
@@ -674,12 +858,7 @@ class Enemy {
|
|
674 |
return;
|
675 |
}
|
676 |
|
677 |
-
|
678 |
-
const start = this.mesh.position.clone();
|
679 |
-
const end = targetPosition.clone();
|
680 |
-
|
681 |
-
// ์ฅ์ ๋ฌผ์ ๊ณ ๋ คํ ๊ฒฝ๋ก์ ์์ฑ
|
682 |
-
this.pathfinding.currentPath = this.generatePathPoints(start, end);
|
683 |
this.pathfinding.lastPathUpdate = currentTime;
|
684 |
}
|
685 |
|
@@ -705,92 +884,14 @@ class Enemy {
|
|
705 |
.subVectors(targetPoint, this.mesh.position)
|
706 |
.normalize();
|
707 |
|
708 |
-
// ์ฅ์ ๋ฌผ ๊ฐ์ง ๋ฐ ํํผ
|
709 |
-
if (this.detectObstacle(direction)) {
|
710 |
-
if (!this.pathfinding.isAvoidingObstacle) {
|
711 |
-
this.pathfinding.isAvoidingObstacle = true;
|
712 |
-
this.pathfinding.avoidanceDirection = this.calculateAvoidanceDirection(direction);
|
713 |
-
}
|
714 |
-
direction.copy(this.pathfinding.avoidanceDirection);
|
715 |
-
} else {
|
716 |
-
this.pathfinding.isAvoidingObstacle = false;
|
717 |
-
}
|
718 |
-
|
719 |
-
// ์ด๋ ์ ์ฉ
|
720 |
const moveVector = direction.multiplyScalar(this.moveSpeed);
|
721 |
this.mesh.position.add(moveVector);
|
722 |
|
723 |
-
// ๊ฒฝ๋ก์ ์ ๋๋ฌํ๋์ง ํ์ธ
|
724 |
if (this.mesh.position.distanceTo(targetPoint) < 2) {
|
725 |
this.pathfinding.currentPath.shift();
|
726 |
}
|
727 |
}
|
728 |
|
729 |
-
detectObstacle(direction) {
|
730 |
-
const raycaster = new THREE.Raycaster(
|
731 |
-
this.mesh.position,
|
732 |
-
direction,
|
733 |
-
0,
|
734 |
-
this.pathfinding.obstacleCheckDistance
|
735 |
-
);
|
736 |
-
const intersects = raycaster.intersectObjects(window.gameInstance.obstacles, true);
|
737 |
-
return intersects.length > 0;
|
738 |
-
}
|
739 |
-
|
740 |
-
calculateAvoidanceDirection(currentDirection) {
|
741 |
-
const left = new THREE.Vector3(-currentDirection.z, 0, currentDirection.x);
|
742 |
-
const right = new THREE.Vector3(currentDirection.z, 0, -currentDirection.x);
|
743 |
-
|
744 |
-
// ์ผ์ชฝ๊ณผ ์ค๋ฅธ์ชฝ ๋ฐฉํฅ ์ค ์ฅ์ ๋ฌผ์ด ์๋ ๋ฐฉํฅ ์ ํ
|
745 |
-
if (!this.detectObstacle(left)) return left;
|
746 |
-
if (!this.detectObstacle(right)) return right;
|
747 |
-
|
748 |
-
// ๋ ๋ค ๋งํ์์ผ๋ฉด ๋ค๋ก
|
749 |
-
return currentDirection.multiplyScalar(-1);
|
750 |
-
}
|
751 |
-
|
752 |
-
update(playerPosition) {
|
753 |
-
if (!this.mesh || !this.isLoaded) return;
|
754 |
-
|
755 |
-
this.updateAIState(playerPosition);
|
756 |
-
|
757 |
-
let targetPosition = playerPosition;
|
758 |
-
if (!this.aiState.canSeePlayer && this.aiState.lastKnownPlayerPosition) {
|
759 |
-
targetPosition = this.aiState.lastKnownPlayerPosition;
|
760 |
-
}
|
761 |
-
|
762 |
-
// AI ๋ชจ๋์ ๋ฐ๋ฅธ ํ๋
|
763 |
-
switch (this.aiState.mode) {
|
764 |
-
case 'pursue':
|
765 |
-
this.findPathToTarget(targetPosition);
|
766 |
-
this.moveAlongPath();
|
767 |
-
break;
|
768 |
-
|
769 |
-
case 'flank':
|
770 |
-
const flankPosition = this.calculateFlankPosition(playerPosition);
|
771 |
-
this.findPathToTarget(flankPosition);
|
772 |
-
this.moveAlongPath();
|
773 |
-
break;
|
774 |
-
|
775 |
-
case 'retreat':
|
776 |
-
const retreatPosition = this.calculateRetreatPosition(playerPosition);
|
777 |
-
this.findPathToTarget(retreatPosition);
|
778 |
-
this.moveAlongPath();
|
779 |
-
break;
|
780 |
-
}
|
781 |
-
|
782 |
-
// ์ด์ ์
๋ฐ์ดํธ
|
783 |
-
this.updateBullets();
|
784 |
-
|
785 |
-
// ํ๋ ์ด์ด๊ฐ ์์ผ์ ์์ผ๋ฉด ๋ฐ์ฌ
|
786 |
-
if (this.aiState.canSeePlayer) {
|
787 |
-
this.shoot(playerPosition);
|
788 |
-
}
|
789 |
-
|
790 |
-
// ์งํ์ ๋ฐ๋ฅธ ํฑํฌ ๊ธฐ์ธ๊ธฐ ์กฐ์
|
791 |
-
this.adjustTankTilt();
|
792 |
-
}
|
793 |
-
|
794 |
calculateFlankPosition(playerPosition) {
|
795 |
const angle = Math.random() * Math.PI * 2;
|
796 |
const radius = 40;
|
|
|
570 |
// Enemy ํด๋์ค
|
571 |
class Enemy {
|
572 |
constructor(scene, position, type = 'tank') {
|
573 |
+
// ๊ธฐ๋ณธ ์์ฑ
|
574 |
this.scene = scene;
|
575 |
this.position = position;
|
576 |
this.mesh = null;
|
|
|
583 |
|
584 |
// AI ์ํ ๊ด๋ฆฌ
|
585 |
this.aiState = {
|
586 |
+
mode: 'pursue',
|
587 |
lastStateChange: 0,
|
588 |
stateChangeCooldown: 3000,
|
589 |
lastVisibilityCheck: 0,
|
590 |
visibilityCheckInterval: 500,
|
591 |
canSeePlayer: false,
|
592 |
lastKnownPlayerPosition: null,
|
593 |
+
searchStartTime: null,
|
594 |
+
targetRotation: 0,
|
595 |
+
currentRotation: 0,
|
596 |
+
isAiming: false,
|
597 |
+
aimingTime: 0,
|
598 |
+
requiredAimTime: 1000 // ์กฐ์ค์ ํ์ํ ์๊ฐ
|
599 |
};
|
600 |
|
601 |
+
// ๊ฒฝ๋ก ํ์ ๋ฐ ํํผ ์์คํ
|
602 |
this.pathfinding = {
|
603 |
currentPath: [],
|
604 |
pathUpdateInterval: 1000,
|
605 |
lastPathUpdate: 0,
|
606 |
isAvoidingObstacle: false,
|
607 |
avoidanceDirection: null,
|
608 |
+
obstacleCheckDistance: 10,
|
609 |
+
avoidanceTime: 0,
|
610 |
+
maxAvoidanceTime: 3000, // ์ต๋ ํํผ ์๊ฐ
|
611 |
+
sensorAngles: [-45, 0, 45], // ์ ๋ฐฉ ๊ฐ์ง ๊ฐ๋
|
612 |
+
sensorDistance: 15 // ๊ฐ์ง ๊ฑฐ๋ฆฌ
|
613 |
};
|
614 |
+
|
615 |
+
// ์ ํฌ ์์คํ
|
616 |
+
this.combat = {
|
617 |
+
minEngagementRange: 30,
|
618 |
+
maxEngagementRange: 150,
|
619 |
+
optimalRange: 80,
|
620 |
+
aimThreshold: 0.1, // ์กฐ์ค ์ ํ๋ ์๊ณ๊ฐ
|
621 |
+
lastShotAccuracy: 0,
|
622 |
+
consecutiveHits: 0,
|
623 |
+
maxConsecutiveHits: 3
|
624 |
+
};
|
625 |
+
}
|
626 |
+
|
627 |
+
// ์ฅ์ ๋ฌผ ๊ฐ์ง ์์คํ
|
628 |
+
detectObstacles() {
|
629 |
+
const obstacles = [];
|
630 |
+
const position = this.mesh.position.clone();
|
631 |
+
position.y += 1; // ์ผ์ ๋์ด ์กฐ์
|
632 |
+
|
633 |
+
this.pathfinding.sensorAngles.forEach(angle => {
|
634 |
+
const direction = new THREE.Vector3(0, 0, 1)
|
635 |
+
.applyQuaternion(this.mesh.quaternion)
|
636 |
+
.applyAxisAngle(new THREE.Vector3(0, 1, 0), angle * Math.PI / 180);
|
637 |
+
|
638 |
+
const raycaster = new THREE.Raycaster(position, direction, 0, this.pathfinding.sensorDistance);
|
639 |
+
const intersects = raycaster.intersectObjects(window.gameInstance.obstacles, true);
|
640 |
+
|
641 |
+
if (intersects.length > 0) {
|
642 |
+
obstacles.push({
|
643 |
+
angle: angle,
|
644 |
+
distance: intersects[0].distance,
|
645 |
+
point: intersects[0].point
|
646 |
+
});
|
647 |
+
}
|
648 |
+
});
|
649 |
+
|
650 |
+
return obstacles;
|
651 |
+
}
|
652 |
+
|
653 |
+
// ํํผ ๋ฐฉํฅ ๊ณ์ฐ
|
654 |
+
calculateAvoidanceDirection(obstacles) {
|
655 |
+
if (obstacles.length === 0) return null;
|
656 |
+
|
657 |
+
// ๋ชจ๋ ์ฅ์ ๋ฌผ์ ๋ฐฉํฅ์ ๊ณ ๋ คํ์ฌ ์ต์ ์ ํํผ ๋ฐฉํฅ ๊ณ์ฐ
|
658 |
+
const avoidanceVector = new THREE.Vector3();
|
659 |
+
obstacles.forEach(obstacle => {
|
660 |
+
const avoidDir = new THREE.Vector3()
|
661 |
+
.subVectors(this.mesh.position, obstacle.point)
|
662 |
+
.normalize()
|
663 |
+
.multiplyScalar(1 / obstacle.distance); // ๊ฑฐ๋ฆฌ์ ๋ฐ๋น๋กํ๋ ๊ฐ์ค์น
|
664 |
+
avoidanceVector.add(avoidDir);
|
665 |
+
});
|
666 |
+
|
667 |
+
return avoidanceVector.normalize();
|
668 |
+
}
|
669 |
+
|
670 |
+
// ์กฐ์ค ์์คํ
|
671 |
+
updateAiming(playerPosition) {
|
672 |
+
const targetDirection = new THREE.Vector3()
|
673 |
+
.subVectors(playerPosition, this.mesh.position)
|
674 |
+
.normalize();
|
675 |
+
|
676 |
+
// ๋ชฉํ ํ์ ๊ฐ ๊ณ์ฐ
|
677 |
+
this.aiState.targetRotation = Math.atan2(targetDirection.x, targetDirection.z);
|
678 |
+
|
679 |
+
// ํ์ฌ ํ์ ๊ฐ ๋ถ๋๋ฝ๊ฒ ์กฐ์
|
680 |
+
const rotationDiff = this.aiState.targetRotation - this.aiState.currentRotation;
|
681 |
+
let rotationStep = Math.sign(rotationDiff) * Math.min(Math.abs(rotationDiff), 0.05);
|
682 |
+
this.aiState.currentRotation += rotationStep;
|
683 |
+
|
684 |
+
// ๋ฉ์ ํ์ ์ ์ฉ
|
685 |
+
this.mesh.rotation.y = this.aiState.currentRotation;
|
686 |
+
|
687 |
+
// ์กฐ์ค ์ ํ๋ ๊ณ์ฐ
|
688 |
+
const aimAccuracy = 1 - Math.abs(rotationDiff) / Math.PI;
|
689 |
+
return aimAccuracy > this.combat.aimThreshold;
|
690 |
+
}
|
691 |
+
|
692 |
+
// ์ ํฌ ๊ฑฐ๋ฆฌ ๊ด๋ฆฌ
|
693 |
+
maintainCombatDistance(playerPosition) {
|
694 |
+
const distanceToPlayer = this.mesh.position.distanceTo(playerPosition);
|
695 |
+
let moveDirection = new THREE.Vector3();
|
696 |
+
|
697 |
+
if (distanceToPlayer < this.combat.minEngagementRange) {
|
698 |
+
// ๋๋ฌด ๊ฐ๊น์ฐ๋ฉด ํ์ง
|
699 |
+
moveDirection.subVectors(this.mesh.position, playerPosition).normalize();
|
700 |
+
} else if (distanceToPlayer > this.combat.maxEngagementRange) {
|
701 |
+
// ๋๋ฌด ๋ฉ๋ฉด ์ ์ง
|
702 |
+
moveDirection.subVectors(playerPosition, this.mesh.position).normalize();
|
703 |
+
} else if (Math.abs(distanceToPlayer - this.combat.optimalRange) > 10) {
|
704 |
+
// ์ต์ ๊ฑฐ๋ฆฌ๋ก ์กฐ์
|
705 |
+
const targetDistance = this.combat.optimalRange;
|
706 |
+
moveDirection.subVectors(playerPosition, this.mesh.position).normalize();
|
707 |
+
if (distanceToPlayer > targetDistance) {
|
708 |
+
moveDirection.multiplyScalar(1);
|
709 |
+
} else {
|
710 |
+
moveDirection.multiplyScalar(-1);
|
711 |
+
}
|
712 |
+
}
|
713 |
+
|
714 |
+
return moveDirection;
|
715 |
+
}
|
716 |
+
|
717 |
+
// ๋ฐ์ฌ ์กฐ๊ฑด ํ์ธ
|
718 |
+
canShoot(playerPosition) {
|
719 |
+
const distance = this.mesh.position.distanceTo(playerPosition);
|
720 |
+
const hasLineOfSight = this.checkLineOfSight(playerPosition);
|
721 |
+
const isAimed = this.updateAiming(playerPosition);
|
722 |
+
|
723 |
+
return distance <= this.combat.maxEngagementRange &&
|
724 |
+
distance >= this.combat.minEngagementRange &&
|
725 |
+
hasLineOfSight &&
|
726 |
+
isAimed;
|
727 |
}
|
728 |
|
729 |
+
// ๋ฉ์ธ ์
๋ฐ์ดํธ ํจ์
|
730 |
+
update(playerPosition) {
|
731 |
+
if (!this.mesh || !this.isLoaded) return;
|
732 |
+
|
733 |
+
// AI ์ํ ์
๋ฐ์ดํธ
|
734 |
+
this.updateAIState(playerPosition);
|
735 |
+
|
736 |
+
// ์ฅ์ ๋ฌผ ๊ฐ์ง
|
737 |
+
const obstacles = this.detectObstacles();
|
738 |
+
|
739 |
+
// ์ด๋ ๋ฐ ํํผ ๋ก์ง
|
740 |
+
if (obstacles.length > 0 && !this.pathfinding.isAvoidingObstacle) {
|
741 |
+
this.pathfinding.isAvoidingObstacle = true;
|
742 |
+
this.pathfinding.avoidanceDirection = this.calculateAvoidanceDirection(obstacles);
|
743 |
+
this.pathfinding.avoidanceTime = 0;
|
744 |
+
}
|
745 |
+
|
746 |
+
// ํํผ ๋์ ์ํ
|
747 |
+
if (this.pathfinding.isAvoidingObstacle) {
|
748 |
+
this.pathfinding.avoidanceTime += 16; // ์ฝ 16ms per frame
|
749 |
+
if (this.pathfinding.avoidanceTime >= this.pathfinding.maxAvoidanceTime) {
|
750 |
+
this.pathfinding.isAvoidingObstacle = false;
|
751 |
+
} else {
|
752 |
+
const avoidMove = this.pathfinding.avoidanceDirection.multiplyScalar(this.moveSpeed);
|
753 |
+
this.mesh.position.add(avoidMove);
|
754 |
+
}
|
755 |
+
} else {
|
756 |
+
// ์ผ๋ฐ ์ด๋ ๋ก์ง
|
757 |
+
switch (this.aiState.mode) {
|
758 |
+
case 'pursue':
|
759 |
+
this.findPathToTarget(playerPosition);
|
760 |
+
this.moveAlongPath();
|
761 |
+
break;
|
762 |
+
case 'flank':
|
763 |
+
const flankPosition = this.calculateFlankPosition(playerPosition);
|
764 |
+
this.findPathToTarget(flankPosition);
|
765 |
+
this.moveAlongPath();
|
766 |
+
break;
|
767 |
+
case 'retreat':
|
768 |
+
const retreatPosition = this.calculateRetreatPosition(playerPosition);
|
769 |
+
this.findPathToTarget(retreatPosition);
|
770 |
+
this.moveAlongPath();
|
771 |
+
break;
|
772 |
+
}
|
773 |
+
}
|
774 |
+
|
775 |
+
// ์ ํฌ ๊ฑฐ๋ฆฌ ์กฐ์
|
776 |
+
const combatMove = this.maintainCombatDistance(playerPosition);
|
777 |
+
if (combatMove.length() > 0) {
|
778 |
+
this.mesh.position.add(combatMove.multiplyScalar(this.moveSpeed));
|
779 |
+
}
|
780 |
+
|
781 |
+
// ๋ฐ์ฌ ์ฒ๋ฆฌ
|
782 |
+
if (this.canShoot(playerPosition)) {
|
783 |
+
this.shoot(playerPosition);
|
784 |
+
}
|
785 |
+
|
786 |
+
// ์ด์ ์
๋ฐ์ดํธ
|
787 |
+
this.updateBullets();
|
788 |
+
|
789 |
+
// ํฑํฌ ๊ธฐ์ธ๊ธฐ ์กฐ์
|
790 |
+
this.adjustTankTilt();
|
791 |
+
}
|
792 |
+
async initialize(loader) {
|
793 |
try {
|
794 |
const modelPath = this.type === 'tank' ? '/models/t90.glb' : '/models/t90.glb';
|
795 |
const result = await loader.loadAsync(modelPath);
|
|
|
816 |
if (!this.mesh) return false;
|
817 |
|
818 |
const startPos = this.mesh.position.clone();
|
819 |
+
startPos.y += 2;
|
820 |
const direction = new THREE.Vector3().subVectors(playerPosition, startPos).normalize();
|
821 |
const distance = startPos.distanceTo(playerPosition);
|
822 |
|
|
|
830 |
const currentTime = Date.now();
|
831 |
const distanceToPlayer = this.mesh.position.distanceTo(playerPosition);
|
832 |
|
|
|
833 |
if (currentTime - this.aiState.lastVisibilityCheck > this.aiState.visibilityCheckInterval) {
|
834 |
this.aiState.canSeePlayer = this.checkLineOfSight(playerPosition);
|
835 |
this.aiState.lastVisibilityCheck = currentTime;
|
|
|
840 |
}
|
841 |
}
|
842 |
|
|
|
843 |
if (currentTime - this.aiState.lastStateChange > this.aiState.stateChangeCooldown) {
|
844 |
if (this.health < 30) {
|
845 |
this.aiState.mode = 'retreat';
|
|
|
858 |
return;
|
859 |
}
|
860 |
|
861 |
+
this.pathfinding.currentPath = this.generatePathPoints(this.mesh.position.clone(), targetPosition);
|
|
|
|
|
|
|
|
|
|
|
862 |
this.pathfinding.lastPathUpdate = currentTime;
|
863 |
}
|
864 |
|
|
|
884 |
.subVectors(targetPoint, this.mesh.position)
|
885 |
.normalize();
|
886 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
887 |
const moveVector = direction.multiplyScalar(this.moveSpeed);
|
888 |
this.mesh.position.add(moveVector);
|
889 |
|
|
|
890 |
if (this.mesh.position.distanceTo(targetPoint) < 2) {
|
891 |
this.pathfinding.currentPath.shift();
|
892 |
}
|
893 |
}
|
894 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
895 |
calculateFlankPosition(playerPosition) {
|
896 |
const angle = Math.random() * Math.PI * 2;
|
897 |
const radius = 40;
|