Пример #1
0
        /// <summary>
        /// Takes cover based on the given search only if it was already adjacent to the previously held cover.
        /// </summary>
        /// <param name="search">Cover search.</param>
        /// <param name="observer">Position of the character.</param>
        public void Maintain(CoverSearch search, Vector3 observer)
        {
            Observer = observer;

            var closest      = search.FindClosest();
            var previousMain = Main;

            if (Main != null && Main != closest)
            {
                if (closest == null || (!Main.IsLeftAdjacent(closest, observer) && !Main.IsRightAdjacent(closest, observer)))
                {
                    Main = null;
                }
            }

            if (Main != null)
            {
                LeftAdjacent  = Main.LeftAdjacent;
                RightAdjacent = Main.RightAdjacent;
            }
            else
            {
                LeftAdjacent  = null;
                RightAdjacent = null;
            }
        }
Пример #2
0
        public static bool GetClosestCover(Vector3 position, float radius, ref Cover resultCover, ref Vector3 resultPosition)
        {
            var minDistance = 0f;
            var count       = Physics.OverlapSphereNonAlloc(position, radius, Colliders, Layers.Cover, QueryTriggerInteraction.Collide);

            resultCover = null;

            for (int i = 0; i < count; i++)
            {
                var cover = CoverSearch.GetCover(Util.Colliders[i].gameObject);

                if (cover != null)
                {
                    var point    = cover.ClosestPointTo(position, 0.3f, 0.3f);
                    var distance = Vector3.Distance(position, point);

                    if (distance < minDistance || resultCover == null)
                    {
                        resultCover    = cover;
                        resultPosition = point;
                        minDistance    = distance;
                    }
                }
            }

            return(resultCover != null);
        }
Пример #3
0
        /// <summary>
        /// Takes cover based on the given search.
        /// </summary>
        /// <param name="search">Cover search.</param>
        /// <param name="observer">Position of the character.</param>
        /// <returns>Was the cover taken.</returns>
        public bool Take(CoverSearch search, Vector3 observer)
        {
            Observer = observer;

            var wasIn        = In;
            var closest      = search.FindClosest();
            var previousMain = Main;

            if (Main == null && closest != null)
            {
                Main          = closest;
                LeftAdjacent  = Main.LeftAdjacent;
                RightAdjacent = Main.RightAdjacent;
            }
            else
            {
                Clear();
            }

            if (In && !wasIn)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #4
0
        /// <summary>
        /// Takes cover based on the given search.
        /// </summary>
        /// <param name="search">Cover search.</param>
        /// <param name="observer">Position of the character.</param>
        /// <returns>Was the cover taken.</returns>
        public bool Take(CoverSearch search, Vector3 observer, float tallThreshold)
        {
            Observer = observer;
            ObserverTallThreshold = tallThreshold;

            var wasIn        = In;
            var closest      = search.FindClosest();
            var previousMain = Main;

            if (Main == null && closest != null)
            {
                Main          = closest;
                LeftAdjacent  = Main.LeftAdjacent;
                RightAdjacent = Main.RightAdjacent;
            }
            else
            {
                Clear();
            }

            if (Main != previousMain)
            {
                MainChangeAge = 0;
            }

            if (In && !wasIn)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Пример #5
0
        /// <summary>
        /// Takes cover based on the given search only if it was already adjacent to the previously held cover.
        /// </summary>
        /// <param name="search">Cover search.</param>
        /// <param name="observer">Position of the character.</param>
        public void Maintain(CoverSearch search, Vector3 observer, float tallThreshold)
        {
            Observer = observer;
            ObserverTallThreshold = tallThreshold;

            var closest      = search.FindClosest();
            var previousMain = Main;

            if (Main != null && Main != closest)
            {
                if (closest != null)
                {
                    if (closest == LeftAdjacent)
                    {
                        StandLeft();
                        Main = closest;
                    }
                    else if (closest == RightAdjacent)
                    {
                        StandRight();
                        Main = closest;
                    }
                    else
                    {
                        Main = null;
                    }
                }
                else
                {
                    Main = null;
                }
            }

            if (Main != null)
            {
                LeftAdjacent  = Main.LeftAdjacent;
                RightAdjacent = Main.RightAdjacent;
            }
            else
            {
                LeftAdjacent  = null;
                RightAdjacent = null;
            }

            if (Main != previousMain)
            {
                MainChangeAge = 0;
            }
        }
Пример #6
0
        /// <summary>
        /// Finds covers near the position in a given radius. Calculates distances and sorts them.
        /// </summary>
        public void Reset(Vector3 observer, float maxDistance, bool detailedPositions = true)
        {
            Items.Clear();

            var count = Physics.OverlapSphereNonAlloc(observer, maxDistance, Util.Colliders, Layers.Cover, QueryTriggerInteraction.Collide);

            for (int i = 0; i < count; i++)
            {
                var collider = Util.Colliders[i];

                if (!collider.isTrigger)
                {
                    continue;
                }

                var cover = CoverSearch.GetCover(collider.gameObject);

                if (cover == null)
                {
                    continue;
                }

                if (cover.IsTall && detailedPositions)
                {
                    if (cover.OpenLeft)
                    {
                        consider(cover, cover.LeftCorner(0, -0.3f), -1, observer, maxDistance);
                    }

                    if (cover.OpenRight)
                    {
                        consider(cover, cover.RightCorner(0, -0.3f), 1, observer, maxDistance);
                    }
                }
                else
                {
                    consider(cover, cover.ClosestPointTo(observer, 0.3f, 0.3f), 0, observer, maxDistance);
                }
            }

            Items.Sort((a, b) => a.Distance.CompareTo(b.Distance));
        }
Пример #7
0
        /// <summary>
        /// Updates the target situation to take cover. Returns true if a cover was found.
        /// </summary>
        public static bool TakeCover(AIController controller, ref AISituation situation)
        {
            var currentVectorToTarget   = situation.ThreatGroundPosition - situation.CurrentPosition;
            var currentDistanceToTarget = currentVectorToTarget.magnitude;

            Cover   result             = null;
            float   resultPathDistance = 0;
            int     resultDirection    = 0;
            Vector3 resultPosition     = situation.CurrentPosition;

            var path    = new NavMeshPath();
            var corners = new Vector3[32];

            var isAlreadyTooClose = currentDistanceToTarget <= controller.Distances.MinEnemy || currentDistanceToTarget <= controller.Cover.MinCoverToEnemyDistance;

            var covers = new List <CoverItem>();

            foreach (var collider in Physics.OverlapSphere(controller.transform.position, controller.Cover.MaxDistance, 0x1 << 8, QueryTriggerInteraction.Collide))
            {
                if (!collider.isTrigger)
                {
                    continue;
                }

                var cover = CoverSearch.GetCover(collider.gameObject);

                if (cover == null || cover == situation.CurrentCover)
                {
                    continue;
                }

                var item = new CoverItem();
                item.Cover  = cover;
                item.IsTall = cover.IsTall(controller.Motor.CoverSettings.TallThreshold);

                if (item.IsTall)
                {
                    item.Direction = cover.ClosestCornerTo(situation.CurrentPosition, controller.Motor.CoverSettings.CornerAimTriggerDistance, out item.Point);
                }
                else
                {
                    item.Point = cover.ClosestPointTo(situation.CurrentPosition, controller.Motor.CoverSettings.LowSideEnterRadius, 0.3f);
                }

                if (float.IsNaN(item.Point.x) || float.IsNaN(item.Point.z))
                {
                    continue;
                }

                item.Point.y  = cover.Bottom;
                item.Distance = Vector3.Distance(controller.transform.position, item.Point);

                covers.Add(item);
            }

            foreach (var item in covers.OrderBy(o => o.Distance))
            {
                var isTall         = item.IsTall;
                var cover          = item.Cover;
                var point          = item.Point;
                var coverDirection = item.Direction;

                if (!AIUtil.IsGoodAngle(controller, cover, point, situation.ThreatGroundPosition, isTall))
                {
                    continue;
                }

                var distanceToTarget = Vector3.Distance(situation.ThreatGroundPosition, point);

                if (distanceToTarget < controller.Distances.MinEnemy ||
                    distanceToTarget < controller.Cover.MinCoverToEnemyDistance)
                {
                    continue;
                }

                if (situation.CurrentCover != null && Vector3.Distance(situation.CurrentPosition, point) < controller.Cover.MinSwitchDistance)
                {
                    continue;
                }

                if ((controller.Health == null || controller.Health.Health > controller.Fighting.MinHealth))
                {
                    if (isTall)
                    {
                        Vector3 aimPoint;
                        coverDirection = cover.ClosestCornerTo(point, -controller.Motor.CoverSettings.CornerOffset.x, out aimPoint);

                        if (!AIUtil.IsInSight(controller, aimPoint, situation.ThreatStandingTopPosition))
                        {
                            continue;
                        }
                    }
                    else if (!AIUtil.IsInSight(controller, point, situation.ThreatStandingTopPosition))
                    {
                        continue;
                    }
                }

                var distanceToOrigin = Vector3.Distance(situation.CurrentPosition, point);

                if (situation.CurrentCover == null)
                {
                    if (distanceToOrigin > controller.Cover.MaxDistance)
                    {
                        continue;
                    }
                }
                else
                if (distanceToOrigin > controller.Cover.MaxSwitchDistance)
                {
                    continue;
                }

                var areThereFriends = false;

                {
                    var hasChangedPosition = false;

                    Vector3 side;

                    if (Vector3.Dot((point - situation.CurrentPosition).normalized, cover.Right) > 0)
                    {
                        side = cover.Right;
                    }
                    else
                    {
                        side = cover.Left;
                    }

                    do
                    {
                        hasChangedPosition = false;

                        if (AIUtil.IsCoverPositionTooCloseToFriends(cover, controller, point))
                        {
                            var next = point + side * 0.5f;

                            if (cover.IsInFront(next, false))
                            {
                                point = next;
                                hasChangedPosition = true;
                            }
                            else
                            {
                                areThereFriends = true;
                            }
                        }
                    }while (hasChangedPosition);
                }

                if (areThereFriends)
                {
                    continue;
                }

                var isOk = false;

                NavMesh.CalculatePath(situation.CurrentPosition, point, NavMesh.AllAreas, path);

                float pathDistance = 0f;

                var count = path.GetCornersNonAlloc(corners);

                if (count < 2)
                {
                    continue;
                }

                var isTooCloseToEnemy = false;

                for (int i = 1; i < count; i++)
                {
                    pathDistance += Vector3.Distance(corners[i - 1], corners[i]);

                    if (!isAlreadyTooClose)
                    {
                        if (Util.DistanceToSegment(situation.ThreatGroundPosition, corners[i - 1], corners[i]) <= controller.Distances.MinPassing)
                        {
                            isTooCloseToEnemy = true;
                            break;
                        }
                    }
                }

                if (isTooCloseToEnemy)
                {
                    continue;
                }

                if (situation.CurrentCover == null)
                {
                    isOk = result == null || pathDistance < resultPathDistance;
                }
                else if (controller.Health == null || controller.Health.Health > controller.Fighting.MinHealth)
                {
                    isOk = (isAlreadyTooClose || distanceToTarget < currentDistanceToTarget) &&
                           (result == null || pathDistance < resultPathDistance);
                }
                else
                {
                    isOk = distanceToTarget > currentDistanceToTarget && (result == null || pathDistance < resultPathDistance);
                }

                if (isOk)
                {
                    result             = cover;
                    resultPosition     = point;
                    resultPathDistance = pathDistance;
                    resultDirection    = coverDirection;
                    break;
                }
            }

            situation.TargetDirection = resultDirection;

            if (result == null)
            {
                if (situation.IsThreatInCover)
                {
                    ApproachACovered(controller, ref situation);
                }
                else
                {
                    ApproachAFree(controller, ref situation, controller.Agent, controller.Distances.MaxWalkingFight, true);
                }

                return(false);
            }
            else
            {
                situation.IsNewCover     = true;
                situation.TargetCover    = result;
                situation.TargetPosition = resultPosition;

                return(true);
            }
        }
Пример #8
0
        /// <summary>
        /// Told by the brains to investigate a position.
        /// </summary>
        /// <param name="position"></param>
        public void ToInvestigatePosition(Vector3 position)
        {
            _isInvestigating = true;

            _position = position;
            _cover    = null;
            var minDistance = 0f;

            for (int i = 0; i < Physics.OverlapSphereNonAlloc(position, CoverSearchDistance, _colliders, 0x1 << 8, QueryTriggerInteraction.Collide); i++)
            {
                var cover = CoverSearch.GetCover(_colliders[i].gameObject);

                if (cover != null)
                {
                    var point    = cover.ClosestPointTo(position, 0.3f, 0.3f);
                    var distance = Vector3.Distance(position, point);

                    if (distance < minDistance || _cover == null)
                    {
                        _cover      = cover;
                        _position   = point;
                        minDistance = distance;
                    }
                }
            }

            _verifyDistance = Util.GetViewDistance(_position, VerifyDistance, true);

            if (_cover == null)
            {
                _hasReachedCoverLine = false;

                if (isActiveAndEnabled)
                {
                    Message("ToWalkTo", position);
                    Message("OnInvestigationStart");
                }
            }
            else
            {
                var vector = _position - transform.position;
                _hasReachedCoverLine = Vector3.Dot(_cover.Forward, vector) > 0;

                if (_hasReachedCoverLine)
                {
                    if (isActiveAndEnabled)
                    {
                        Message("ToWalkTo", _position);
                        Message("OnInvestigationStart");
                    }
                }
                else
                {
                    var left  = _cover.LeftCorner(_cover.Bottom, CoverOffset) - _cover.Forward * 1.0f;
                    var right = _cover.RightCorner(_cover.Bottom, CoverOffset) - _cover.Forward * 1.0f;

                    AIUtil.Path(ref _path, transform.position, left);
                    var leftLength = 0f;

                    if (_path.status == NavMeshPathStatus.PathInvalid)
                    {
                        leftLength = 999999f;
                    }
                    else
                    {
                        for (int i = 1; i < _path.GetCornersNonAlloc(_corners); i++)
                        {
                            leftLength += Vector3.Distance(_corners[i], _corners[i - 1]);
                        }
                    }

                    AIUtil.Path(ref _path, transform.position, right);
                    var rightLength = 0f;

                    if (_path.status == NavMeshPathStatus.PathInvalid)
                    {
                        rightLength = 999999f;
                    }
                    else
                    {
                        for (int i = 1; i < _path.GetCornersNonAlloc(_corners); i++)
                        {
                            rightLength += Vector3.Distance(_corners[i], _corners[i - 1]);
                        }
                    }

                    if (leftLength < rightLength)
                    {
                        _approachPosition = left;
                    }
                    else
                    {
                        _approachPosition = right;
                    }

                    var distance = Vector3.Distance(_approachPosition, _position);

                    if (distance + VerifyRadius > _verifyDistance)
                    {
                        _approachPosition = _position + Vector3.Normalize(_approachPosition - _position) * (_verifyDistance + VerifyRadius - 0.1f);
                    }

                    if (isActiveAndEnabled)
                    {
                        Message("ToWalkTo", _approachPosition);
                        Message("OnInvestigationStart");
                    }
                }
            }
        }