Example #1
0
    /// <summary>
    /// попытаться поставить avader'а в очередь, с возвратом его позиции
    /// </summary>
    /// <param name="avaider">кандидат в очередь</param>
    /// <param name="position">позиция в очереди</param>
    /// <returns>true - если добавлен в очередь, иначе  false</returns>
    /// <exception cref="ArgumentNullException"></exception>
    public bool Register(IAvaidObject avaider, out Vector3?position)
    {
        if (avaider == null)
        {
            throw new ArgumentNullException("avaider");
        }

        //определяем адиус виража, как расстояни до впереди идущего
        float maneurRadius =
            AngularMath.CircleRadius(avaider.MaxLinearSpeed, avaider.MaxAngularSpeed);

        LinkedListNode <IAvaidObject> search;
        //ищем позицию кандидата в очереди, или добавляем в конец
        bool result = !_distanceCache.TryGetValue(avaider, out search);

        if (result)
        {
            search = _order.AddLast(avaider);
            _distanceCache[avaider] = search;
        }

        //если нет никого впереди
        if (search.Previous == null || search.Previous.Value == null)
        {
            position = null;
        }
        //если впереди идущий есть, отсчитываем позицию до него
        else
        {
            IAvaidObject previous = search.Previous.Value;
            position = previous.Position - previous.Direction * maneurRadius;
        }
        return(result);
    }
Example #2
0
    /// <summary>
    /// возвращает позицию в очереди на посадку, или null, если можно садиться
    /// </summary>
    /// <exception cref="ArgumentNullException"></exception>
    public Vector3?this[IAvaidObject avaider]
    {
        get
        {
            if (avaider == null)
            {
                throw new ArgumentNullException("avaider");
            }
            //если в череди никого нет, можно садиться
            if (_order.Count == 0)
            {
                return(null);
            }

            LinkedListNode <IAvaidObject> search;
            //если avaider есть в очереди, то будем считать его позицию от предыдущего,
            //в противном случае - от последнего, если таковой есть
            if (!_distanceCache.TryGetValue(avaider, out search))
            {
                search = _order.Last;
            }
            if (search == null || search.Previous == null || search.Previous.Value == null)
            {
                return(null);
            }

            //определяем радиус моневра avaider'а, будет использовано, как расстояние до впереди идущего
            float maneurRadius =
                AngularMath.CircleRadius(avaider.MaxLinearSpeed, avaider.MaxAngularSpeed);
            IAvaidObject previous = search.Previous.Value;
            return(previous.Position - previous.Direction * maneurRadius);
        }
    }
Example #3
0
    private void Update()
    {
        //фиксация желания запуска самолета
        if (Input.GetButtonUp("scout"))
        {
            TryTakeoffPendingPlane();
        }

        //самолет возможно запустить, есть есть самолеты на запуск и при этом не производится посадка
        if (_landingQueue.Count == 0 && _takeoffPending > 0)
        {
            //интервал между запусками/посадкой равен времени полного виража самолета,
            //чтобы при истекании времени полета не создавать скученности самолетов на посадке
            float fullSpinTime = 360 / _planePrefab.MaxAngularSpeed;
            if (Time.time - _takeoffTime > fullSpinTime)
            {
                StartPlane();
            }
        }

        //логика определения угрозы столкновения и расчет точек избегания
        foreach (IAvaidObject avaider in _onTrack)
        {
            //если объект не способен уклоняться, расчитывать нечего
            if (!avaider.CanAvaid)
            {
                continue;
            }
            Vector3 avaiderVelocity = avaider.Direction * avaider.LinearSpeed;
            //итоговый вектор направления избегания столкновения
            Vector3 avaidVector = Vector3.zero;

            //проходимся по каждому из "соперников"
            foreach (IAvaidObject toAvaid in _onTrack)
            {
                if (toAvaid == avaider)
                {
                    continue;
                }

                Vector3 toAvaidVelocity = toAvaid.Direction * toAvaid.LinearSpeed;
                //длина проекции скорости и направления движения соперника
                //на скорость и направление движения рассматриваемого объекта
                float projectionLength = Vector3.Dot(avaiderVelocity, toAvaidVelocity) / avaiderVelocity.magnitude;
                //скорректированная скорость рассматриваемого объекта
                float correctedAvaiderLinearSpeed = avaiderVelocity.magnitude - projectionLength;
                //дистанция, на которой стоит предпринимать меы по уклонению начинается с безопасной дистанции полета
                float   distanceToReact = _flightParams.saveDistance;
                Vector3 avaiderToAvaid  = toAvaid.Position - avaider.Position;
                float   maneurRadius;
                //если скорректированная скорость рассматриваемого объекта не положительна,
                //а соперник вне безопасной зоны, можно не учитывать радиус маневрирования
                if (correctedAvaiderLinearSpeed <= 0 && distanceToReact < avaiderToAvaid.magnitude)
                {
                    maneurRadius = 0;
                }
                //иначе определяем максимальный радиус маневрирования для рассматриваемого объекта
                else
                {
                    maneurRadius =
                        AngularMath.CircleRadius(correctedAvaiderLinearSpeed, avaider.MaxAngularSpeed);
                }
                //итоговая дистанция, на которой нужно начинать уворачиваться
                distanceToReact += maneurRadius;
                float fromReactDistanceToAvaid = avaiderToAvaid.magnitude - distanceToReact;
                //если соперник находится за пределами дистанции реагирования, можно не беспокоиться
                if (fromReactDistanceToAvaid > 0)
                {
                    continue;
                }
                //иначе добавить к вектору уклонения противоположное направление в той мере,
                //в какой соперник приблизился к рассматриваемому объекту
                else
                {
                    if (_debug)
                    {
                        Debug.DrawLine(avaider.Position, toAvaid.Position, Color.blue);
                    }
                    avaidVector += avaiderToAvaid.normalized * fromReactDistanceToAvaid;
                }
            }

            //если вектор уворота есть - нужно увернуться
            if (avaidVector != Vector3.zero)
            {
                float maneurRadius =
                    AngularMath.CircleRadius(avaider.AvgLinearSpeed, avaider.MaxAngularSpeed);
                avaider.Target = avaider.Position + avaidVector.normalized * maneurRadius;
                if (_debug)
                {
                    Debug.DrawRay(avaider.Target.Value, Vector3.up, Color.magenta);
                }
            }
            else
            {
                avaider.Target = null;
            }
        }
    }