IEnumerator UpdateTargetPosition() { while (true) { if (_canUpdateTargetPositionAndPath) { if (TargetIsExist()) { bool isPathPossible; _targetPositionPair = TargetFindingMethods.GetNearestTargetPositionToSeeker(_performer.transform.position, _taskData.Target, out isPathPossible); if (!isPathPossible) { CompleteTask(); yield break; } } else { CompleteTask(); yield break; } } yield return(new WaitForSeconds(_performer.TargetFindingInterval)); } }
/// <summary> /// Возвращает ближайшие координаты цели к искателю /// </summary> public static TargetPositionPair GetNearestTargetPositionToSeeker(Vector3 seekerPos, Transform target, out bool isPathPossible) { isPathPossible = false; TargetPositionPair nearetTargetPositionPair = default(TargetPositionPair); float halfNodeSize = GameManager.NodeSize * 0.5f; Node seekerNode = AstarPath.active.GetNearest(seekerPos); NodeAndDistance[] nodeAndDistanceArray = null; Vector3 nodePos; if (target.IsUnit()) { //так как юниты пока-что небольшие(менее 1 ноды), то сетка не используется Vector3 targetPos = target.position; Node nearestNode = AstarPath.active.GetNearest(targetPos, NNConstraint.Default); if (nearestNode != null) { FixBugWith_IsPathPossible(ref seekerNode, seekerPos); if (GraphUpdateUtilities.IsPathPossible(seekerNode, nearestNode)) { isPathPossible = true; nearetTargetPositionPair.FollowPosition = targetPos; nearetTargetPositionPair.NearestBoundaryNodePosition = targetPos; } } } else //если цель - строение { Node[] nodes = target.GetComponent <BuildingGrid>().GetBoundaryNodesClone(); SortNodesByDistance(nodes, out nodeAndDistanceArray, seekerPos); //Поиск ближайшей ноды, до которой существует путь. for (int i = 0; i < nodeAndDistanceArray.Length; i++) { nodePos = nodeAndDistanceArray[i].Node.position.ToVector3(); Vector3 dir = (seekerPos - nodePos).normalized * halfNodeSize;//направление и половина расстояния до граничной ноды Node externalBoundaryNode = AstarPath.active.GetNearest(nodePos + dir, NNConstraint.Default); if (externalBoundaryNode != null) { FixBugWith_IsPathPossible(ref seekerNode, seekerPos); if (GraphUpdateUtilities.IsPathPossible(seekerNode, externalBoundaryNode)) { isPathPossible = true; nearetTargetPositionPair.FollowPosition = nodePos + dir; nearetTargetPositionPair.NearestBoundaryNodePosition = nodePos; break;//выход из цикла, т.к. путь к ноде существует, а ноды отсортированы в порядке близости к цели и поиск пути до более отдаленных нод бессмысленен. } } } } return(nearetTargetPositionPair); }
public override void StartTask() { if (_performer == null) { Debug.LogError("Performer is not added"); } if (_taskData == null) { Debug.LogError("TaskData is not added"); } if (!TargetIsExist()) { CompleteTask(); return; } if (!IsActive) { if (!_performer.gameObject.IsDied()) { //—брос всех вычисл¤емых параметров ClearTemporaryVariables(); enabled = true; IsActive = true; if (_taskData.Target.IsUnit()) //если цель - подвижный объект, то запускаем корутину дл¤ отслеживани¤ его позиции { StartCoroutine(func_UpdateTargetPosition); } else //иначе ищем позицию только 1 раз { bool isPathPossible; _targetPositionPair = TargetFindingMethods.GetNearestTargetPositionToSeeker(_performer.transform.position, _taskData.Target, out isPathPossible); if (!isPathPossible) { CompleteTask(); return; } } StartCoroutine(func_UpdatePath); } } }
protected float _lastAttackTime = -100.0f; //время, прошедшее с последней атаки public virtual void Attack(Transform target, TargetPositionPair targetPositionPair) { //поворот к цели Vector3 dirToTarget; if (target.IsBuilding()) { dirToTarget = targetPositionPair.NearestBoundaryNodePosition - transform.position; } else { dirToTarget = target.position - transform.position; } dirToTarget.y = 0;//чтобы юнит не вращался по оси Y Rotate(dirToTarget); if (ActionIsAllowed(dirToTarget)) { if (Time.time - _lastAttackTime > _attackInterval) { UnitAnimation.State = UnitAnimation.States.Attack; _lastAttackTime = Time.time; StartCoroutine("CauseDamage", target);//причинение повреждения с задержкой, чтобы урон не наносился, когда анимация удара только началась PauseAllTasks(); State = UnitState.Attack; Invoke("StartAllTasks", UnitAnimation.GetCurrentClipLength()); } else if (UnitAnimation.State != UnitAnimation.States.Attack) { UnitAnimation.State = UnitAnimation.States.IdleBattle; } } else { UnitAnimation.State = UnitAnimation.States.Run; } }
public void Attack(Transform target, TargetPositionPair targetPositionPair) { Attack(); }
/* Проверка (GraphUpdateUtilities.IsPathPossible(seekerNode, externalBoundaryNode)) - не совсем правильна(см. реализацию IsPathPossible функции)- вместо этого правильней было бы юзать AstarPath.StartPath(); * К тому же из-за IsPathPossible() есть баг - юнит не может найти цель, если попадает в непроходимую ноду. *В дальнейшем желательно переделать эту функции так, чтобы возвращала сразу и цель и ближайший путь, если они существуют. *Также при поиске ближайшей ноды правильней было бы проверять длину путей до каждой ноды и выбрать ближний путь, но это довольно затратно: * http://arongranberg.com/astar/docs/_multi_target_free_8cs-example.php * http://www.arongranberg.com/astar/docs/_multi_target_path_example_8cs-example.php */ /// <summary> /// [Для передвижных юнитов] Поиск ближашей цели и ближайшей ноды цели к юниту; одновременно проверяется существование пути. /// </summary> public static Transform FindNearestTarget(Vector3 seekerPos, float searchRadius, LayerMask targetLayerMask, out TargetPositionPair targetPositionPair) { Collider[] targets = Physics.OverlapSphere(seekerPos, searchRadius, targetLayerMask); TargetPositionPair nearetTargetPositionPair = default(TargetPositionPair); Transform nearestTarget = null; if (targets.Length != 0) { float halfNodeSize = GameManager.NodeSize * 0.5f; Node seekerNode = AstarPath.active.GetNearest(seekerPos); float minDistSqr = float.MaxValue; //инициализация переменной для проверки дистанции до цели NodeAndDistance[] nodeAndDistanceArray = null; Vector3 nodePos; foreach (Collider coll in targets) { if (coll.IsUnit()) { //так как юниты пока-что небольшие(менее 1 ноды), то сетка не используется Vector3 targetPos = coll.transform.position; float distSqr = (targetPos - seekerPos).sqrMagnitude;//Vector3.Distance(seekerPos, targetPos); if (distSqr < minDistSqr) { Node nearestNode = AstarPath.active.GetNearest(targetPos, NNConstraint.Default); if (nearestNode != null) { //исправление бага, связанного c IsPathPossible - если юнит вдруг находится в непроходимой точке и не движется. FixBugWith_IsPathPossible(ref seekerNode, seekerPos); if (GraphUpdateUtilities.IsPathPossible(seekerNode, nearestNode)) { minDistSqr = distSqr; nearestTarget = coll.transform; nearetTargetPositionPair.FollowPosition = targetPos; nearetTargetPositionPair.NearestBoundaryNodePosition = targetPos; } } } } else //если цель - строение { Node[] nodes = coll.GetComponent <BuildingGrid>().GetBoundaryNodesClone(); SortNodesByDistance(nodes, out nodeAndDistanceArray, seekerPos); //Поиск ближайшей ноды, до которой существует путь. for (int i = 0; i < nodeAndDistanceArray.Length; i++) { if (nodeAndDistanceArray[i].DistanceSqr < minDistSqr) { nodePos = nodeAndDistanceArray[i].Node.position.ToVector3(); Vector3 dir = (seekerPos - nodePos).normalized * halfNodeSize;//направление и половина расстояния до граничной ноды Node externalBoundaryNode = AstarPath.active.GetNearest(nodePos + dir, NNConstraint.Default); if (externalBoundaryNode != null) { //исправление бага, связанного c IsPathPossible - если юнит вдруг находится в непроходимой точке и не движется. FixBugWith_IsPathPossible(ref seekerNode, seekerPos); if (GraphUpdateUtilities.IsPathPossible(seekerNode, externalBoundaryNode)) { minDistSqr = nodeAndDistanceArray[i].DistanceSqr; nearestTarget = coll.transform; nearetTargetPositionPair.FollowPosition = nodePos + dir; nearetTargetPositionPair.NearestBoundaryNodePosition = nodePos; break;//выход из цикла, т.к. путь к ноде существует, а ноды отсортированы в порядке близости к цели и поиск пути до более отдаленных нод бессмысленен. } } } } } } } targetPositionPair = nearetTargetPositionPair; return(nearestTarget); }