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;
        }
    }
Example #5
0
 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);
    }