示例#1
0
        private Vector3 followerPositionAt(FormationType formation, int index)
        {
            switch (formation)
            {
            case FormationType.Square:
            {
                var right = Vector3.Cross(Direction, Vector3.up);

                Vector3 position;

                switch (index)
                {
                case 0: position = transform.position - (right + Direction).normalized * Square.Distance; break;

                case 1: position = transform.position - (-right + Direction).normalized * Square.Distance; break;

                default: position = transform.position - Direction * Square.Distance * index; break;
                }

                var ideal = position;

                AIUtil.GetClosestStandablePosition(ref position);

                var closest    = Vector3.zero;
                var hasClosest = false;
                var minDist    = 0f;

                for (int i = 0; i < _followers.Count; i++)
                {
                    var dist = Vector3.Distance(_followers[i].transform.position, ideal);

                    if (_followers[i]._obstacle != null && _followers[i]._obstacle.enabled && dist <= _followers[i]._obstacle.radius + float.Epsilon)
                    {
                        dist = 0;
                    }

                    if (!hasClosest || dist < minDist)
                    {
                        closest    = _followers[i].transform.position;
                        minDist    = dist;
                        hasClosest = true;
                    }
                }

                if (hasClosest && Vector3.Distance(position, ideal) > minDist)
                {
                    position = closest;
                }

                return(position);
            }

            case FormationType.Line:
                return(_line[index]);

            default:
                Debug.Assert(false);
                return(Vector3.zero);
            }
        }
        /// <summary>
        /// React to attacks on other AI.
        /// </summary>
        public void OnFriendHit(Actor friend)
        {
            if (friend == null)
            {
                return;
            }

            var vector = friend.transform.position - transform.position;

            if (vector.magnitude < View.CommunicationDistance)
            {
                _situation.IsAlerted = true;
            }
            else if (vector.magnitude < View.SightDistance && !IsAlerted)
            {
                if (AIUtil.IsInSight(this, friend.TopPosition))
                {
                    _situation.IsAlerted = true;
                }
            }

            if (_situation.IsAlerted && _situation.Threat == null)
            {
                var ai = friend.GetComponent <AIController>();

                if (ai != null)
                {
                    _situation.TakeEnemyState(ai);
                }
            }
        }
        private bool updateIsMelee()
        {
            _meleeTarget = null;

            var weapon = _motor.EquippedWeapon;

            if (!weapon.HasMelee || weapon.Gun != null)
            {
                return(false);
            }

            var minDist = 0f;

            for (int i = 0; i < AIUtil.FindActors(_motor.transform.position, MeleeRadius, _actor); i++)
            {
                var actor = AIUtil.Actors[i];

                if (actor.Side == _actor.Side)
                {
                    continue;
                }

                var dist = Vector3.Distance(_motor.transform.position, actor.transform.position);

                if (_meleeTarget == null || dist < minDist)
                {
                    _meleeTarget = actor;
                    minDist      = dist;
                }
            }

            return(_meleeTarget != null);
        }
示例#4
0
        /// <summary>
        /// Sets up the navigation agent to move to the givent position.
        /// </summary>
        private void updatePath()
        {
            AIUtil.Path(ref _path, transform.position, _target);

            _pathLength       = _path.GetCornersNonAlloc(_pathPoints);
            _currentPathIndex = 0;

            if (_pathLength > _pathPoints.Length)
            {
                _pathLength = _pathPoints.Length;
            }

            if (_pathLength > 1)
            {
                var vector   = _pathPoints[1] - _pathPoints[0];
                var distance = vector.magnitude;

                if (distance > 0.3f)
                {
                    updateDirection(vector / distance, true);
                }
            }

            _hasCheckedIfReachable      = false;
            _positionToCheckIfReachable = _target;
        }
示例#5
0
        private bool canMoveInDirection(Vector3 vector)
        {
            if (AIUtil.IsNavigationBlocked(transform.position, transform.position + vector))
            {
                return(false);
            }

            return(true);
        }
示例#6
0
        /// <summary>
        /// Sets up the navigation agent to move to the givent position.
        /// </summary>
        private void updatePath()
        {
            AIUtil.Path(ref _path, transform.position, _target);

            _pathLength       = _path.GetCornersNonAlloc(_pathPoints);
            _currentPathIndex = 0;

            if (_pathLength > 1)
            {
                updateDirection((_pathPoints[1] - _pathPoints[0]).normalized, true);
            }
        }
        /// <summary>
        /// Catches the animator event during the execution and may perform the action. Returns true if that is the case.
        /// </summary>
        public override bool OnFinishAction()
        {
            var count = AIUtil.FindActorsIncludingDead(_targetPosition, Radius);

            for (int i = 0; i < count; i++)
            {
                PlayEffect(AIUtil.Actors[i], AIUtil.Actors[i].transform.position);
                Perform(AIUtil.Actors[i]);
            }

            return(true);
        }
示例#8
0
        private bool shouldRunTo(Vector3 position)
        {
            var distance = Vector3.Distance(transform.position, position);

            if (distance > WalkDistance || (distance > VerifyDistance && !AIUtil.IsInSight(_actor, position, VerifyDistance, 360)))
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
示例#9
0
        private bool isValidSide(Vector3 vector)
        {
            if (!_motor.IsFree(vector, 0.5f, 0.1f))
            {
                return(false);
            }

            if (AIUtil.IsObstructed(transform.position + Vector3.up * 2, _target + Vector3.up * 2, 1000))
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// React to attacks and notify other AI about it.
        /// </summary>
        public void OnHit(Hit hit)
        {
            _situation.IsAlerted = true;

            if (hit.Attacker != null && _situation.Threat == null)
            {
                var threat = hit.Attacker.GetComponent <Actor>();

                if (threat != null && threat.Side != _actor.Side)
                {
                    _situation.ReadEnemyState(threat);
                }
            }

            AIUtil.NotifyFriends(_actor, "OnFriendHit", _actor);
        }
示例#11
0
        private void runTo(Vector3 position)
        {
            if (_isKeepingCloseTo && Vector3.Distance(position, _keepCloseTo.Position) > _keepCloseTo.Distance)
            {
                position = _keepCloseTo.Position + (position - _keepCloseTo.Position).normalized * _keepCloseTo.Distance;
            }

            if (AIUtil.GetClosestStandablePosition(ref position))
            {
                Message("ToRunTo", position);
            }
            else
            {
                OnPositionUnreachable(position);
            }
        }
示例#12
0
        /// <summary>
        /// Updates the target situation to approach an enemy that's in cover.
        /// </summary>
        public static void ApproachACovered(AIController controller, ref AISituation situation)
        {
            var path    = new NavMeshPath();
            var corners = new Vector3[16];

            var resultPosition = situation.ThreatGroundPosition;
            var resultDistance = 9999f;

            var coverAngle = Util.AngleOfVector(situation.ThreatCoverForward);

            for (int a = 0; a < 18; a++)
            {
                var angle    = coverAngle - 180f + a * 10;
                var position = situation.ThreatGroundPosition + new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad), 0, Mathf.Sin(angle * Mathf.Deg2Rad)) * controller.Distances.MinEnemy;

                NavMeshHit hit;
                if (NavMesh.SamplePosition(position, out hit, 1.0f, NavMesh.AllAreas) &&
                    AIUtil.IsInSight(controller, hit.position, situation.ThreatStandingTopPosition))
                {
                    NavMesh.CalculatePath(controller.transform.position, hit.position, NavMesh.AllAreas, path);

                    if (path.status == NavMeshPathStatus.PathComplete &&
                        !AIUtil.IsPositionTooCloseToFriends(controller, hit.position))
                    {
                        var dist = 0f;

                        for (int i = 1; i < path.GetCornersNonAlloc(corners); i++)
                        {
                            dist += Vector3.Distance(corners[i - 1], corners[i]);
                        }

                        if (dist < resultDistance)
                        {
                            resultDistance = dist;
                            resultPosition = position;
                        }
                    }
                }
            }

            situation.TargetPosition = resultPosition;
            situation.TargetCover    = null;
        }
示例#13
0
        private bool canBeInvestigated(SearchPoint point)
        {
            var position        = point.Position + Vector3.up * VerifyHeight;
            var distanceToPoint = Vector3.Distance(transform.position, position);

            var checkDistance = VerifyDistance;

            if (point.Visibility < checkDistance)
            {
                checkDistance = point.Visibility;
            }

            if (distanceToPoint < checkDistance &&
                (distanceToPoint < 1 ||
                 AIUtil.IsInSight(_actor, position, checkDistance, FieldOfView)))
            {
                return(!point.RequiresReaching || distanceToPoint < 1.1f);
            }

            return(false);
        }
示例#14
0
        /// <summary>
        /// Notified by the brains of a new threat position.
        /// </summary>
        public void OnThreatPosition(Vector3 position)
        {
            if (!_isAssaulting || !isActiveAndEnabled)
            {
                return;
            }

            _threatPosition = position;

            if (Vector3.Distance(position, _targetPosition) > 0.5f)
            {
                _targetPosition = position;

                if (AIUtil.GetClosestStandablePosition(ref position))
                {
                    Message("ToRunTo", position);
                }
                else
                {
                    OnPositionUnreachable(position);
                }
            }
        }
示例#15
0
        /// <summary>
        /// Checks if the given actor is field of view. Result is immediate, does not execute any events or messages.
        /// </summary>
        public bool CheckVisibility(Actor actor)
        {
            var viewDistance = actor.GetViewDistance(Distance, _isAlerted);

            return(AIUtil.IsInSight(_actor, actor.TopPosition, viewDistance, FieldOfView, ObstacleIgnoreDistance));
        }
        private void Update()
        {
            if (_situation.IsAlerted)
            {
                if (!_hasAddedToAlertedControllers)
                {
                    _hasAddedToAlertedControllers = true;
                    _alertedControllers.Add(this);
                }
            }
            else if (_hasAddedToAlertedControllers)
            {
                _alertedControllers.Remove(this);
            }

            _stateTime += Time.deltaTime;

            _agent.updatePosition = false;
            _agent.updateRotation = false;
            _agent.updateUpAxis   = false;
            _agent.autoRepath     = true;
            _agent.autoBraking    = false;

            if (!_motor.IsAlive)
            {
                _situation.TargetCover = null;
            }

            if (_lastTargetCover != _situation.TargetCover)
            {
                if (_lastTargetCover != null)
                {
                    _lastTargetCover.UnregisterUser(_actor);
                }

                _lastTargetCover = _situation.TargetCover;

                if (_lastTargetCover != null)
                {
                    _lastTargetCover.RegisterUser(_actor);
                }
            }

            if (_isWaitingForPath && !_agent.pathPending)
            {
                _pathLength       = _agent.path.GetCornersNonAlloc(_path);
                _currentPathIndex = 0;
                _isWaitingForPath = false;
            }

            if (!_motor.IsAlive)
            {
                _state         = AIState.none;
                _agent.enabled = false;
                return;
            }
            else
            {
                _agent.enabled = true;
            }

            if (_motor.PotentialCover != null)
            {
                _motor.InputTakeCover();
            }

            if (_situation.IsAlerted)
            {
                if (!_motor.IsInCover)
                {
                    _motor.InputAim();
                }

                // Make the AI pick up a weapon.
                if (Fighting.WeaponToUse <= 0)
                {
                    _motor.InputWeapon(0);
                }
                else if (Fighting.WeaponToUse - 1 < _motor.Weapons.Length)
                {
                    _motor.InputWeapon(Fighting.WeaponToUse);
                }
                else
                {
                    _motor.InputWeapon(_motor.Weapons.Length);
                }

                _situation.IsAllowedToBeAggressive = true;

                ///
                /// POTENTIALLY FORGET ABOUT THE ENEMY. CHECK IF CAN BE AGGRESSIVE.
                ///
                if (_situation.Threat != null)
                {
                    if (_situation.Threat.IsAlive)
                    {
                        if (!_situation.CanSeeTheThreat && _situation.NoThreatTimer > View.EnemySustainTime)
                        {
                            _situation.RemoveEnemyState();
                        }
                        else
                        {
                            if (_registeredGroup != null)
                            {
                                _registeredGroup.MarkAsPotentialAggressive(this);
                                _situation.IsAllowedToBeAggressive = _registeredGroup.IsAggressive(this);
                            }
                        }
                    }
                    else
                    {
                        _situation.RemoveEnemyState();
                    }
                }

                ///
                /// AIM AND FIRE
                ///
                if (_situation.Threat != null && (_situation.CanSeeTheThreat || _situation.NoThreatTimer < View.SightSustainTime))
                {
                    // Process grenade throwing
                    if (_situation.ThrownGrenadeCount < Grenades.GrenadeCount)
                    {
                        var doThrow = false;

                        if (_situation.IsAllowedToBeAggressive)
                        {
                            if (_hasThrowFirstGrenade)
                            {
                                if (_grenadeTimer < Grenades.Interval)
                                {
                                    _grenadeTimer += Time.deltaTime;
                                }
                                else
                                {
                                    doThrow = true;
                                }
                            }
                            else
                            {
                                if (_grenadeTimer < Grenades.FirstGrenadeDelay)
                                {
                                    _grenadeTimer += Time.deltaTime;
                                }
                                else
                                {
                                    doThrow = true;
                                }
                            }
                        }

                        if (doThrow && _motor.PotentialGrenade != null)
                        {
                            if (_grenadeCheckTimer <= float.Epsilon)
                            {
                                GrenadeDescription desc;
                                desc.Gravity    = _motor.Grenade.Gravity;
                                desc.Duration   = _motor.PotentialGrenade.Timer;
                                desc.Bounciness = _motor.PotentialGrenade.Bounciness;

                                var length = GrenadePath.Calculate(GrenadePath.Origin(_motor, Util.AngleOfVector(_situation.ThreatGroundPosition - transform.position)),
                                                                   _situation.ThreatGroundPosition,
                                                                   _motor.Grenade.MaxVelocity,
                                                                   desc,
                                                                   _grenadePath,
                                                                   _motor.Grenade.Step);

                                if (Vector3.Distance(_grenadePath[length - 1], _situation.ThreatGroundPosition) > Grenades.MaxRadius ||
                                    Vector3.Distance(_grenadePath[length - 1], _situation.CurrentPosition) < Grenades.AvoidDistance)
                                {
                                    _grenadeCheckTimer = Grenades.CheckInterval;
                                }
                                else
                                {
                                    _motor.InputThrowGrenade(_grenadePath, length, _motor.Grenade.Step);
                                    _situation.ThrownGrenadeCount++;

                                    _grenadeTimer         = 0;
                                    _hasThrowFirstGrenade = true;
                                }
                            }
                            else
                            {
                                _grenadeCheckTimer -= Time.deltaTime;
                            }
                        }
                        else
                        {
                            _grenadeCheckTimer = 0;
                        }
                    }

                    // Position in world space that is best fit to aim at.
                    var perfectTarget = _situation.ThreatGroundPosition + (_situation.ThreatTopPosition - _situation.ThreatGroundPosition) * 0.7f;

                    if (_situation.IsThreatInCover)
                    {
                        var dot = Vector3.Dot(_situation.ThreatCoverForward, (_situation.ThreatGroundPosition - transform.position).normalized);

                        if (dot < -0.1f)
                        {
                            perfectTarget = _situation.ThreatStandingTopPosition;
                        }
                    }

                    // Make the AI look at the target.
                    {
                        var vector = perfectTarget - _motor.transform.position;
                        vector.y = 0;

                        if (vector.magnitude < 2)
                        {
                            _motor.SetLookTarget(perfectTarget + vector * 2);
                        }
                        else
                        {
                            _motor.SetLookTarget(perfectTarget);
                        }

                        _motor.SetBodyLookTarget(perfectTarget);
                    }

                    // Aim the gun at the inprecise target.
                    var targetRadius = Fighting.TargetRadius.Get(Vector3.Distance(_situation.ThreatGroundPosition, transform.position));
                    _motor.SetFireTarget(perfectTarget + new Vector3(UnityEngine.Random.Range(-1, 1) * targetRadius,
                                                                     UnityEngine.Random.Range(-1, 1) * targetRadius,
                                                                     UnityEngine.Random.Range(-1, 1) * targetRadius));

                    // We want AI too look at the corner when standing near it.
                    if (_motor.IsInTallCover)
                    {
                        if (_situation.TargetDirection < 0)
                        {
                            _motor.InputStandLeft();
                        }
                        else if (_situation.TargetDirection > 0)
                        {
                            _motor.InputStandRight();
                        }
                    }

                    // Fire
                    {
                        var isAllowedToFire = _situation.IsAllowedToBeAggressive;

                        if (Behaviour.OnlyFireWhenSeen || !_situation.IsAllowedToBeAggressive)
                        {
                            var up   = Camera.main.WorldToViewportPoint(transform.position);
                            var down = Camera.main.WorldToViewportPoint(transform.position + Vector3.up * 2);

                            if ((up.x < 0 ||
                                 up.y < 0 ||
                                 up.x > 1 ||
                                 up.y > 1 ||
                                 up.z < 0) &&
                                (down.x < 0 ||
                                 down.y < 0 ||
                                 down.x > 1 ||
                                 down.y > 1 ||
                                 down.z < 0))
                            {
                                isAllowedToFire = false;
                            }
                            else
                            {
                                isAllowedToFire = true;
                            }
                        }

                        if (isAllowedToFire)
                        {
                            var burst  = Behaviour.IsFightingUsingCovers ? CoveredFightingBursts : CoveredApproachBursts;
                            var isDumb = _state == AIState.fireInCover &&
                                         (_stateTime <= burst.IntroDuration || _stateTime >= burst.IntroDuration + burst.Duration);

                            var isWalking = _state != AIState.takeCover && _state != AIState.approach && _state != AIState.retreat;

                            // Check if can fire right now.
                            if (Behaviour.CanFire &&
                                (!isWalking || _walkingBurstWait < WalkingBursts.Duration) &&
                                (!_situation.IsTargetCoverGood ||
                                 (_state != AIState.hideInCover &&
                                  (_state != AIState.takeCover || _motor.Cover == null))))
                            {
                                var aimPoint = transform.position;

                                if (_motor.IsInTallCover && _situation.IsTargetCoverGood)
                                {
                                    if (_situation.TargetDirection < 0)
                                    {
                                        aimPoint = _motor.Cover.LeftCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                                    }
                                    else
                                    {
                                        aimPoint = _motor.Cover.RightCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                                    }
                                }

                                // See if the motor can hit the standing enemy after potentially peeking.
                                if (AIUtil.IsInSight(this, aimPoint, _situation.ThreatStandingTopPosition))
                                {
                                    if (_state == AIState.fireInCover)
                                    {
                                        _motor.InputAim();
                                    }

                                    if (!isDumb)
                                    {
                                        _motor.InputFire();
                                    }
                                }
                            }
                        }

                        _lookPointTimer = 0;
                    }
                }
                else
                {
                    _motor.SetFireTarget(_situation.ThreatGroundPosition);
                    _motor.SetLookTarget(_situation.ThreatGroundPosition);
                    _motor.SetBodyLookTarget(_situation.ThreatGroundPosition);
                    lookAround(_situation.ThreatGroundPosition - _motor.transform.position);
                }
            }
            else
            {
                _motor.InputWeapon(0);

                if (_state == AIState.patrol || _state == AIState.patrolPause)
                {
                    Vector3 forward;

                    if (Waypoints.Length > 1)
                    {
                        var next = Waypoints[_situation.PatrolPoint];

                        forward = next.Position - transform.position;

                        if (forward.magnitude < 0.5f)
                        {
                            var previous = _situation.PatrolPoint == 0 ? Waypoints[Waypoints.Length - 1] : Waypoints[_situation.PatrolPoint - 1];
                            var line     = next.Position - previous.Position;

                            if (Vector2.Dot(line, forward) > 0)
                            {
                                forward = line;
                            }
                        }
                    }
                    else
                    {
                        forward = transform.forward;
                    }

                    lookAround(forward);
                }
                else
                {
                    _lookPointTimer = 0;
                }
            }

            var positionToMoveTo = transform.position;

            ///
            /// STATE MANAGEMENT
            ///
            {
                var updateSituationInDetail = false;

                {
                    // Update the update delay timer.
                    _updateTimer -= Time.deltaTime;

                    if (_updateTimer < 0)
                    {
                        _updateTimer            = Fighting.ReactionTime;
                        updateSituationInDetail = true;
                    }
                }

                // Update standing burst timer.
                {
                    _walkingBurstWait += Time.deltaTime;

                    if (_walkingBurstWait > WalkingBursts.Duration + WalkingBursts.Wait)
                    {
                        _walkingBurstWait = 0;
                    }
                }

                {
                    _situation.Update(this, _previousSituation, updateSituationInDetail);

                    if (!isStateStillValid(_state, _stateTime, _situation, _situation))
                    {
                        updateSituation(calcState(_situation, _state, _stateTime));
                    }
                }
            }

            ///
            /// WALK
            ///
            if (!_motor.IsInCornerAimState)
            {
                if (_state == AIState.takeCover ||
                    _state == AIState.approach ||
                    _state == AIState.investigate ||
                    _state == AIState.retreat ||
                    _state == AIState.patrol ||
                    _state == AIState.avoidGrenade)
                {
                    var toTarget = _situation.TargetPosition - transform.position;

                    // If patrolling, set the body to rotate towards the target.
                    if (_state == AIState.patrol)
                    {
                        if (toTarget.magnitude > 0.1f)
                        {
                            var normalized = toTarget.normalized;
                            var position   = transform.position + normalized * 4;
                            var dot        = Vector3.Dot(toTarget.normalized, _motor.transform.forward);

                            if (Waypoints[_situation.PatrolPoint].Run)
                            {
                                _motor.SetBodyLookTarget(position, 8);
                            }
                            else
                            {
                                if (dot > 0)
                                {
                                    _motor.SetBodyLookTarget(position, 1.6f);
                                }
                                else if (dot > -0.5f)
                                {
                                    _motor.SetBodyLookTarget(position, 2.5f);
                                }
                                else
                                {
                                    _motor.SetBodyLookTarget(position, 4f);
                                }
                            }
                        }
                    }

                    // Move the last meter without using the agent.
                    if (toTarget.magnitude > 1.0f)
                    {
                        var vectorToAgent   = _agent.nextPosition - transform.position;
                        var distanceToAgent = vectorToAgent.magnitude;

                        if (distanceToAgent > float.Epsilon)
                        {
                            vectorToAgent /= distanceToAgent;
                        }

                        // If agent moved too far, reset it.
                        if (distanceToAgent > 1f)
                        {
                            updateAgent(_situation.TargetPosition);
                        }

                        float walkSpeed;

                        if (_state == AIState.patrol && !Patrol.IsAlwaysRunning && (Waypoints.Length == 0 || !Waypoints[_situation.PatrolPoint].Run))
                        {
                            walkSpeed = 0.5f;
                        }
                        else
                        {
                            walkSpeed = 1.0f;
                        }

                        var point = _currentPathIndex + 1 < _pathLength ? _path[_currentPathIndex + 1] : _situation.TargetPosition;

                        var vectorToPoint   = point - transform.position;
                        var distanceToPoint = vectorToPoint.magnitude;

                        if (distanceToPoint > float.Epsilon)
                        {
                            vectorToPoint /= distanceToPoint;
                        }

                        if (distanceToPoint < 0.1f && _currentPathIndex + 1 < _pathLength)
                        {
                            _currentPathIndex++;
                        }

                        _agent.speed = 0.1f;
                        _motor.InputMovement(new CharacterMovement(vectorToPoint, walkSpeed));
                    }
                    else
                    {
                        if (_state == AIState.takeCover)
                        {
                            _motor.InputImmediateCoverSearch();
                            _motor.InputTakeCover();
                        }

                        if (toTarget.magnitude > 0.05f)
                        {
                            _motor.InputMovement(new CharacterMovement(toTarget.normalized, 0.5f));
                        }
                        else
                        {
                            _motor.transform.position = _situation.TargetPosition;
                        }
                    }
                }
            }
        }
示例#17
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);
            }
        }
示例#18
0
        private void Update()
        {
            _isMoving = false;

            if (_obstacle != null && _obstacle.enabled)
            {
                _obstacle.enabled = false;
            }

            if (_motor == null || !_motor.IsAlive)
            {
                if (_wasMoving)
                {
                    Message("OnStopMoving");
                    _wasMoving = false;
                }

                _mode = Mode.none;
                return;
            }

            if (_isCrouching)
            {
                _motor.InputCrouch();
            }

            if (_isAvoidingMover)
            {
                if (_avoidingTimer > float.Epsilon)
                {
                    _avoidingTimer -= Time.deltaTime;
                    move(_avoidDirection, 1, false);
                }
                else
                {
                    _isAvoidingMover = false;
                }
            }

            if (_mode == Mode.none)
            {
                if (_wasMoving)
                {
                    Message("OnStopMoving");
                    _wasMoving = false;
                }

                checkIncomingCollisions(Vector3.zero, 1);

                return;
            }

            if (DebugDestination)
            {
                Debug.DrawLine(transform.position, _target, Color.blue);
            }

            if (DebugPath)
            {
                for (int i = 0; i < _pathLength - 1; i++)
                {
                    if (i == _currentPathIndex)
                    {
                        Debug.DrawLine(_pathPoints[i], _pathPoints[i + 1], Color.cyan);
                        Debug.DrawLine(_pathPoints[i + 1], _pathPoints[i + 1] + Vector3.up, Color.cyan);
                    }
                    else
                    {
                        Debug.DrawLine(_pathPoints[i], _pathPoints[i + 1], Color.green);
                    }
                }
            }

            var vector = _target - transform.position;

            vector.y = 0;

            var direction = vector.normalized;
            var side      = Vector3.Cross(direction, Vector3.up);

            if (_futureCircleDirection == 0)
            {
                _circleWait = 0;
            }

            switch (_mode)
            {
            case Mode.inDirection:
                if (!checkIncomingCollisions(_direction, _speed))
                {
                    if (canMoveInDirection(_direction))
                    {
                        move(_direction, _speed, true);
                    }

                    _inDirectionLeft -= Time.deltaTime;

                    if (_inDirectionLeft <= float.Epsilon)
                    {
                        _mode = Mode.none;
                    }
                }
                break;

            case Mode.toPosition:
                var vectorToPath     = Vector3.zero;
                var isCloseToThePath = false;
                var distanceToPath   = 0f;

                if (_currentPathIndex <= _pathLength - 1)
                {
                    vectorToPath     = Util.VectorToSegment(transform.position, _pathPoints[_currentPathIndex], _pathPoints[_currentPathIndex + 1]);
                    distanceToPath   = vectorToPath.magnitude;
                    isCloseToThePath = distanceToPath < 0.5f;
                }

                if (!isCloseToThePath)
                {
                    updatePath();
                }

                var isLastStepOnPartialPath = _currentPathIndex >= _pathLength - 2 && _path.status == NavMeshPathStatus.PathPartial;

                if (_path.status != NavMeshPathStatus.PathInvalid && !_hasCheckedIfReachable)
                {
                    if (_pathLength == 0 || Vector3.Distance(_pathPoints[_pathLength - 1], _positionToCheckIfReachable) >= 0.2f)
                    {
                        Message("OnPositionUnreachable", _positionToCheckIfReachable);
                    }

                    _hasCheckedIfReachable = true;
                }

                if (vector.magnitude >= 0.3f && !isLastStepOnPartialPath)
                {
                    if (_path.status == NavMeshPathStatus.PathInvalid || _pathLength == 0)
                    {
                        updatePath();
                    }

                    var point = _currentPathIndex + 1 < _pathLength ? _pathPoints[_currentPathIndex + 1] : _target;

                    if (!AIUtil.IsPositionOnNavMesh(point))
                    {
                        updatePath();
                    }

                    direction   = point - transform.position;
                    direction.y = 0;

                    var distanceToPoint = direction.magnitude;

                    if (distanceToPoint > float.Epsilon)
                    {
                        direction /= distanceToPoint;
                    }

                    if (!checkIncomingCollisions(direction, _speed))
                    {
                        if (distanceToPoint < 0.2f && _currentPathIndex + 1 < _pathLength)
                        {
                            var index = _currentPathIndex;

                            if (distanceToPoint > 0.07f && _currentPathIndex + 2 < _pathLength)
                            {
                                if (Vector3.Dot(point - transform.position, _pathPoints[_currentPathIndex + 2] - transform.position) <= 0.1f)
                                {
                                    _currentPathIndex++;
                                }
                            }
                            else
                            {
                                _currentPathIndex++;
                            }
                        }

                        if (distanceToPath > 0.12f)
                        {
                            direction = (direction + vectorToPath).normalized;
                        }

                        if (Vector3.Dot(direction, _direction) < 0.9f)
                        {
                            updateDirection(direction, false);
                        }

                        move(direction, _speed, false);
                    }
                }
                else
                {
                    if (vector.magnitude > 0.03f)
                    {
                        if (!checkIncomingCollisions(direction, _speed))
                        {
                            if (vector.magnitude < 0.2f)
                            {
                                _motor.InputImmediateCoverSearch();
                                transform.position = Util.Lerp(transform.position, _target, 6);
                            }
                            else
                            {
                                if (_motor.IsInCover)
                                {
                                    move(direction, 1.0f, false);
                                }
                                else
                                {
                                    move(direction, 0.5f, false);
                                }
                            }
                        }
                    }
                    else
                    {
                        _motor.transform.position = _target;
                        _mode = Mode.none;
                    }
                }
                break;

            case Mode.fromPosition:
                _pathLength = 0;

                if (!checkIncomingCollisions(-direction, _speed))
                {
                    direction = -direction;

                    if (canMoveInDirection(direction))
                    {
                        _motor.InputMovement(new CharacterMovement(direction, 1.0f));
                        _isMoving = true;
                    }
                    else
                    {
                        if (_side == 0)
                        {
                            if (Random.Range(0, 10) < 5 && _motor.IsFreeToMove(side, 0.5f, 0.25f))
                            {
                                _side = 1;
                            }
                            else
                            {
                                _side = -1;
                            }
                        }

                        if (!canMoveInDirection(side * _side))
                        {
                            if (!_motor.IsFreeToMove(-side * _side, 0.5f, 0.25f))
                            {
                                Message("OnMoveFromFail");
                            }
                            else
                            {
                                _side = -_side;
                            }
                        }

                        move(side * _side, 1.0f, true);
                    }

                    updateDirection(direction, false);

                    if (_isRunningAwayTemp)
                    {
                        _runningAwayFramesLeft--;

                        if (_runningAwayFramesLeft <= 0)
                        {
                            ToStopMoving();
                        }
                    }
                }

                break;

            case Mode.circle:
                _pathLength = 0;

                if (_futureCircleDirection != 0)
                {
                    if (_circleWait > float.Epsilon)
                    {
                        _circleWait -= Time.deltaTime;
                    }

                    if (_circleWait < float.Epsilon)
                    {
                        _circleWait            = 0;
                        _side                  = _futureCircleDirection;
                        _futureCircleDirection = 0;
                    }
                }


                if (_futureCircleDirection == 0)
                {
                    if (_side == 0)
                    {
                        if (Random.Range(0, 10) < 5 && canMoveInDirection(side))
                        {
                            _side = 1;
                        }
                        else
                        {
                            _side = -1;
                        }
                    }

                    if (!canMoveInDirection(side * _side))
                    {
                        if (!canMoveInDirection(-side * _side))
                        {
                            Message("OnCircleFail");
                        }
                        else
                        {
                            _futureCircleDirection = -_side;
                            _circleWait            = CircleDelay;
                        }
                    }

                    direction = side * _side;

                    if (!checkIncomingCollisions(direction, _speed))
                    {
                        move(direction, 1.0f, true);
                        updateDirection(direction, false);
                    }
                }
                break;
            }

            if (_isMoving && !_wasMoving)
            {
                Message("OnMoving");
            }
            else if (!_isMoving && _wasMoving)
            {
                Message("OnStopMoving");
            }

            _wasMoving = _isMoving;
        }
示例#19
0
        private bool isValidCover(Cover cover, Vector3 position, int direction, bool checkPath, bool avoidPivot = true)
        {
            if (cover == _unreachableCover)
            {
                return(false);
            }

            if (_isKeepingCloseTo && Vector3.Distance(position, _keepCloseTo.Position) > _keepCloseTo.Distance)
            {
                return(false);
            }

            if (!_hasPivot)
            {
                if (!AIUtil.IsCoverPositionFree(cover, position, 1, _actor))
                {
                    return(false);
                }

                return(true);
            }

            if (!_hasCachedEnemies)
            {
                _cachedEnemyCount = 0;
                _hasCachedEnemies = true;

                var totalActorCount = AIUtil.FindActors(position, MinDefenselessDistance, _actor);

                if (totalActorCount > 0)
                {
                    var enemyCount = 0;
                    for (int i = 0; i < totalActorCount; i++)
                    {
                        if (AIUtil.Actors[i].Side != _actor.Side)
                        {
                            enemyCount++;
                        }
                    }

                    if (enemyCount > 0)
                    {
                        if (_cachedEnemies == null || _cachedEnemies.Length < enemyCount)
                        {
                            _cachedEnemies = new Actor[enemyCount];
                        }

                        var index = 0;

                        for (int i = 0; i < totalActorCount; i++)
                        {
                            if (AIUtil.Actors[i].Side != _actor.Side)
                            {
                                _cachedEnemies[index++] = AIUtil.Actors[i];
                            }
                        }

                        _cachedEnemyCount = index;
                    }
                }
            }

            for (int i = 0; i < _cachedEnemyCount; i++)
            {
                var enemy = _cachedEnemies[i];

                if (enemy.Side != _actor.Side)
                {
                    var enemyPosition = enemy.transform.position;
                    var distance      = Vector3.Distance(position, enemyPosition);

                    if (distance < AvoidDistance)
                    {
                        return(false);
                    }

                    if (!AIUtil.IsGoodAngle(MaxTallCoverThreatAngle,
                                            MaxLowCoverThreatAngle,
                                            cover,
                                            position,
                                            enemyPosition,
                                            cover.IsTall))
                    {
                        return(false);
                    }
                }
            }

            if (_isPivotThreat)
            {
                var distance = Vector3.Distance(position, _pivotPosition);

                if (_hasMaxPivotDistance && distance > _maxPivotDistance)
                {
                    return(false);
                }

                var aimPosition = position;

                if (AIUtil.IsObstructed(aimPosition + (_actor.StandingTopPosition - transform.position),
                                        _pivotPosition + Vector3.up * 2))
                {
                    return(false);
                }
            }
            else
            {
                var distance = Vector3.Distance(position, _pivotPosition);

                if (_hasMaxPivotDistance && distance > _maxPivotDistance)
                {
                    return(false);
                }

                if (!AIUtil.IsGoodAngle(MaxDefenseAngle,
                                        MaxDefenseAngle,
                                        cover,
                                        _pivotPosition,
                                        position,
                                        cover.IsTall))
                {
                    return(false);
                }
            }

            if (!AIUtil.IsCoverPositionFree(cover, position, 1, _actor))
            {
                return(false);
            }

            if (checkPath)
            {
                if (NavMesh.CalculatePath(transform.position, position, 1, _path))
                {
                    if (avoidPivot)
                    {
                        var count = _path.GetCornersNonAlloc(_corners);

                        for (int i = 0; i < count; i++)
                        {
                            var a = i == 0 ? transform.position : _corners[i - 1];
                            var b = _corners[i];

                            var closest = Util.FindClosestToPath(a, b, _pivotPosition);

                            if (Vector3.Distance(closest, _pivotPosition) < AvoidDistance)
                            {
                                return(false);
                            }
                        }
                    }
                }
                else
                {
                    return(false);
                }
            }

            return(true);
        }
示例#20
0
        private bool verify(Vector3 position)
        {
            var distance = Vector3.Distance(transform.position, position);

            return((_cover != null && AIUtil.IsInSight(_actor, position + Vector3.up * VerifyHeight, _verifyDistance, FieldOfView)) || distance < VerifyRadius || (distance < _verifyDistance && _verifyDistance < VerifyRadius));
        }
示例#21
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");
                    }
                }
            }
        }
        /// <summary>
        /// Returns an updated situation struct.
        /// </summary>
        public void Update(AIController controller, AISituation previous, bool updateInDetail)
        {
            if (!IsAlerted)
            {
                HasInvestigatedTheLatestAlert = false;
            }
            else if (Threat == null & Vector3.Distance(CurrentPosition, ThreatGroundPosition) < controller.Distances.ThreatInvestigation)
            {
                MarkInvestigated();
            }

            if (HasAnInvestigatedAlert)
            {
                InvestigatedAlertAge += Time.deltaTime;
            }

            // Check grenades
            {
                IsNearGrenade = false;
                float minDist = 1000;

                foreach (var grenade in GrenadeList.All)
                {
                    var vec  = grenade.transform.position - controller.transform.position;
                    var dist = vec.magnitude;

                    if (dist < grenade.ExplosionRadius)
                    {
                        if (!IsNearGrenade || dist < minDist)
                        {
                            minDist                = dist;
                            IsNearGrenade          = true;
                            NearestGrenadePosition = grenade.transform.position;

                            if (Threat == null)
                            {
                                HasInvestigatedTheLatestAlert = false;
                                HasAnInvestigatedAlert        = false;
                                ThreatGroundPosition          = grenade.transform.position;
                            }
                        }
                    }
                }
            }

            // Check friends and enemies.
            if (Threat == null || (!IsAlerted && !IsGettingAlerted))
            {
                var minEnemyInfoTimer = controller.View.EnemySustainTime;

                foreach (var actor in Actors.All)
                {
                    if (actor != controller.Actor)
                    {
                        if (actor.Side != controller.Actor.Side)
                        {
                            if (AIUtil.IsInSight(controller, actor.TopPosition))
                            {
                                IsAlerted = true;
                                ReadEnemyState(actor);
                                break;
                            }
                        }
                        else if (actor.AI != null && actor.AI.IsAlerted)
                        {
                            var vector = actor.transform.position - controller.transform.position;

                            if (vector.magnitude < controller.View.CommunicationDistance)
                            {
                                IsAlerted = true;

                                if (actor.AI.Situation.NoThreatTimer < actor.AI.View.EnemySustainTime &&
                                    minEnemyInfoTimer > actor.AI.Situation.NoThreatTimer)
                                {
                                    TakeEnemyState(actor.AI);
                                }
                            }
                        }
                    }
                }
            }

            // Check friends if they had investigated the same position
            if (IsAlerted && Threat == null && !HasInvestigatedTheLatestAlert)
            {
                foreach (var friend in Actors.All)
                {
                    if (friend != controller.Actor &&
                        friend.Side == controller.Actor.Side &&
                        friend.AI.IsAlerted &&
                        friend.AI.Situation.HasAnInvestigatedAlert &&
                        friend.AI.Situation.InvestigatedAlertAge < 10 &&
                        Vector3.Distance(friend.transform.position, controller.transform.position) < controller.View.CommunicationDistance &&
                        Vector3.Distance(friend.AI.Situation.InvestigatedThreatPosition, ThreatGroundPosition) < controller.Distances.ThreatInvestigation)
                    {
                        MarkInvestigated();
                        break;
                    }
                }
            }


            // Check threats
            if (Threat == null)
            {
                var minDist = 100000f;

                foreach (var alert in Alerts.All)
                {
                    var dist = Vector3.Distance(controller.transform.position, alert.Position);

                    if (dist < alert.Range)
                    {
                        if (dist < minDist)
                        {
                            minDist                       = dist;
                            IsAlerted                     = true;
                            ThreatGroundPosition          = alert.Position;
                            HasAnInvestigatedAlert        = false;
                            HasInvestigatedTheLatestAlert = false;
                        }
                    }
                }
            }

            // React to grenades
            if (IsNoticingGrenade)
            {
                if (GrenadeReaction < float.Epsilon)
                {
                    IsNoticingGrenade = false;
                }
                else
                {
                    GrenadeReaction -= Time.deltaTime;
                    IsNearGrenade    = false;
                }
            }
            else if (IsNearGrenade && !previous.IsNearGrenade)
            {
                GrenadeReaction   = controller.Fighting.GrenadeReactionTime;
                IsNoticingGrenade = true;
                IsNearGrenade     = false;
            }

            if (IsNearGrenade)
            {
                IsAlerted = true;
            }

            // React to being alerted.
            if (IsGettingAlerted)
            {
                if (AlertReaction < float.Epsilon)
                {
                    IsGettingAlerted = false;
                    IsAlerted        = true;
                }
                else
                {
                    AlertReaction -= Time.deltaTime;
                    IsAlerted      = false;
                }
            }
            else if (IsAlerted && !previous.IsAlerted)
            {
                AlertReaction    = controller.Fighting.ReactionTime;
                IsGettingAlerted = true;
                IsAlerted        = false;
            }

            if (previous.TargetCover != null &&
                (controller.Motor.LeftCover == previous.TargetCover || controller.Motor.RightCover == previous.TargetCover || controller.Motor.Cover == previous.TargetCover))
            {
                CurrentCover = previous.TargetCover;
            }
            else
            {
                CurrentCover = controller.Motor.Cover;
            }

            CurrentPosition = controller.transform.position;
            IsGunReady      = controller.Motor.IsGunReady && controller.Motor.Gun.Clip >= controller.Motor.Gun.ClipSize * controller.Fighting.ReloadFraction;

            if (controller.Health != null && Threat != null && Threat.IsAttacking)
            {
                IsRetreating = IsAlerted && controller.Health.Health <= controller.Fighting.MinHealth;
            }
            else
            {
                IsRetreating = false;
            }

            if (IsAlerted)
            {
                var couldSeeTheEnemy = CanSeeTheThreat;
                CanSeeTheThreat = false;

                if (Threat != null)
                {
                    if (couldSeeTheEnemy || updateInDetail)
                    {
                        CanSeeTheThreat = AIUtil.IsInSight(controller, Threat.TopPosition);
                    }

                    if (CanSeeTheThreat)
                    {
                        ReadEnemyState(Threat);
                    }
                    else
                    {
                        NoThreatTimer += Time.deltaTime;

                        if (updateInDetail)
                        {
                            // Check friends and enemies.
                            foreach (var friend in Actors.All)
                            {
                                if (friend != controller.Actor &&
                                    friend.Side == controller.Actor.Side &&
                                    friend.AI != null &&
                                    friend.AI.IsAlerted &&
                                    friend.AI.Situation.CanSeeTheThreat &&
                                    friend.AI.Situation.Threat == Threat)
                                {
                                    var vector = friend.transform.position - controller.transform.position;

                                    if (vector.magnitude < controller.View.CommunicationDistance)
                                    {
                                        TakeEnemyState(friend.AI);
                                    }
                                }
                            }
                        }
                    }
                }

                if (TargetCover != null && updateInDetail)
                {
                    var distanceToThreat = Vector3.Distance(TargetPosition, ThreatGroundPosition);

                    IsTargetCoverGood = distanceToThreat >= controller.Distances.MinEnemy &&
                                        distanceToThreat >= controller.Cover.MinCoverToEnemyDistance &&
                                        AIUtil.IsGoodAngle(controller,
                                                           TargetCover,
                                                           TargetPosition,
                                                           ThreatGroundPosition,
                                                           TargetCover.IsTall(controller.Motor.CoverSettings.TallThreshold)) &&
                                        !AIUtil.IsCoverPositionTooCloseToFriends(TargetCover, controller, TargetPosition);
                }

                if (updateInDetail)
                {
                    if (TargetCover != null && TargetCover.IsTall(controller.Motor.CoverSettings.TallThreshold))
                    {
                        Vector3 aimPoint;

                        if (TargetDirection < 0)
                        {
                            aimPoint = TargetCover.LeftCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                        }
                        else
                        {
                            aimPoint = TargetCover.RightCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                        }

                        CanSeeFromTargetPosition = AIUtil.IsInSight(controller, aimPoint, ThreatStandingTopPosition);
                    }
                    else
                    {
                        CanSeeFromTargetPosition = AIUtil.IsInSight(controller, TargetPosition, ThreatStandingTopPosition);
                    }
                }
            }
            else
            {
                if (TargetCover != null && updateInDetail)
                {
                    IsTargetCoverGood = !AIUtil.IsCoverPositionTooCloseToFriends(TargetCover, controller, TargetPosition);
                }

                CanSeeFromTargetPosition = true;
            }
        }
示例#23
0
        /// <summary>
        /// Updates the target situation to approach an enemy that's not in cover.
        /// </summary>
        public static void ApproachAFree(AIController controller, ref AISituation situation, NavMeshAgent agent, float maxDistance, bool approachStanding)
        {
            situation.TargetCover    = null;
            situation.TargetPosition = situation.ThreatGroundPosition;

            var path = new NavMeshPath();

            agent.CalculatePath(situation.ThreatGroundPosition, path);

            var corners = new Vector3[16];
            var count   = path.GetCornersNonAlloc(corners);

            if (count < 2)
            {
                return;
            }

            var i  = 0;
            var p0 = corners[i];
            var p1 = corners[i + 1];
            var f  = 1f;

            var targetPosition = approachStanding ? situation.ThreatStandingTopPosition : situation.ThreatGroundPosition;

            {
                var distLeft = Vector3.Distance(controller.transform.position, situation.ThreatGroundPosition);

                while (distLeft > maxDistance)
                {
                    var pd   = Vector3.Distance(p0, p1);
                    var left = distLeft - maxDistance;
                    distLeft -= pd;

                    if (pd >= left)
                    {
                        f = left / pd;
                        break;
                    }
                    else
                    {
                        i++;

                        if (i + 1 >= count)
                        {
                            i = 0;
                            break;
                        }
                        else
                        {
                            p0 = corners[i];
                            p1 = corners[i + 1];
                        }
                    }
                }
            }

            while (i + 1 < count)
            {
                var p = p0 + (p1 - p0) * f;

                if (AIUtil.IsInSight(controller, p, targetPosition))
                {
                    situation.TargetPosition = p;
                    break;
                }

                f += 0.2f;

                if (f >= 1f)
                {
                    if (AIUtil.IsInSight(controller, p1, targetPosition))
                    {
                        situation.TargetPosition = p1;
                        break;
                    }

                    f = 0;
                    i++;
                }
            }
        }
示例#24
0
        private void Update()
        {
            if (!_actor.IsAlive)
            {
                return;
            }

            _wait -= Time.deltaTime;

            if (_wait > float.Epsilon)
            {
                _oldVisible.Clear();
                _oldVisibleHash.Clear();

                for (int i = 0; i < _visible.Count; i++)
                {
                    var actor = _visible[i];

                    if (actor != null)
                    {
                        _oldVisible.Add(actor);
                        _oldVisibleHash.Add(actor);
                    }
                }

                for (int i = 0; i < _oldVisible.Count; i++)
                {
                    var actor = _oldVisible[i];

                    if (!actor.IsAlive)
                    {
                        _visible.Remove(actor);
                        _visibleHash.Remove(actor);

                        if (!_seenDeadHash.Contains(actor))
                        {
                            _seenDeadHash.Add(actor);
                            Message("OnSeeDeath", actor);
                        }
                    }
                }

                return;
            }

            _wait = Random.Range(UpdateDelay * 0.8f, UpdateDelay * 1.2f);

            _oldVisible.Clear();
            _oldVisibleHash.Clear();

            for (int i = 0; i < _visible.Count; i++)
            {
                var actor = _visible[i];

                if (actor != null)
                {
                    _oldVisible.Add(actor);
                    _oldVisibleHash.Add(actor);
                }
            }

            _visible.Clear();
            _visibleHash.Clear();

            var count = AIUtil.FindActorsIncludingDead(_actor.TopPosition, Distance, _actor);

            for (int i = 0; i < count; i++)
            {
                var actor = AIUtil.Actors[i];

                if (CheckVisibility(actor))
                {
                    if (actor.IsAlive)
                    {
                        _visible.Add(actor);
                        _visibleHash.Add(actor);
                    }
                    else
                    {
                        if (!_seenDeadHash.Contains(actor))
                        {
                            _seenDeadHash.Add(actor);
                            Message("OnSeeDeath", actor);
                        }
                        // A hack, should fix in some other way
                        else if (_brain != null && _brain.Threat == actor)
                        {
                            _brain.OnSeeDeath(actor);
                        }
                    }
                }
            }

            for (int i = 0; i < _oldVisible.Count; i++)
            {
                var actor = _oldVisible[i];

                if (!_visibleHash.Contains(actor))
                {
                    Message("OnUnseeActor", actor);
                }
            }

            for (int i = 0; i < _visible.Count; i++)
            {
                var actor = _visible[i];

                if (!_oldVisibleHash.Contains(actor))
                {
                    Message("OnSeeActor", actor);
                }
            }
        }
示例#25
0
        private void Update()
        {
            if ((Disabler != null && Disabler.activeSelf) || EventSystem.current.IsPointerOverGameObject())
            {
                hideMarker();
                hideOutline(ref _targetOutline);
                hideSphere();

                if (Target == null)
                {
                    hideOutline(ref _performerOutline);
                }
                else
                {
                    showOutline(ref _performerOutline, Target, SelectColor);
                }

                return;
            }

            var camera = _camera;

            if (camera == null)
            {
                camera = Camera.main;
            }
            if (camera == null)
            {
                return;
            }

            var mouse = Input.mousePosition;

            mouse.z = camera.nearClipPlane;

            var near = camera.ScreenToWorldPoint(mouse);

            mouse.z = camera.farClipPlane;
            var far = camera.ScreenToWorldPoint(mouse);

            var hit         = Util.GetClosestNonActorHit(near, far, 1);
            var targetActor = AIUtil.FindClosestActorIncludingDead(hit, 0.7f);

            var isMouseDown = Input.GetMouseButtonDown(0);

            if (Target == null)
            {
                if (targetActor != null && targetActor.Side == Side && targetActor.IsAlive)
                {
                    showOutline(ref _performerOutline, targetActor, PickColor);

                    if (isMouseDown)
                    {
                        Target      = targetActor;
                        isMouseDown = false;
                    }
                }
                else
                {
                    hideOutline(ref _performerOutline);
                }
            }
            else if (Target != null)
            {
                showOutline(ref _performerOutline, Target, SelectColor);
            }
            else
            {
                hideOutline(ref _performerOutline);
            }

            AIActions targetActions = null;

            if (Target != null)
            {
                targetActions = Target.GetComponent <AIActions>();
            }

            if (targetActions)
            {
                var target = hit;
                AIUtil.GetClosestStandablePosition(ref target);

                var isActor    = targetActor != null;
                var isSelf     = isActor && targetActor == Target;
                var isAlly     = isActor && targetActor.Side == Target.Side;
                var isEnemy    = isActor && targetActor.Side != Target.Side;
                var isDead     = isActor && !targetActor.IsAlive;
                var isLocation = Vector3.Distance(target, hit) < 0.5f;

                AIAction action           = null;
                var      isTargetingActor = false;

                if (_forcedAction != null)
                {
                    if (_forcedAction.CanTargetGround && isLocation)
                    {
                        action = _forcedAction;
                    }
                    else if ((!isDead || !_forcedAction.ShouldIgnoreDead) &&
                             ((isSelf && _forcedAction.CanTargetSelf) ||
                              (isAlly && _forcedAction.CanTargetAlly) ||
                              (isEnemy && _forcedAction.CanTargetEnemy)))
                    {
                        action           = _forcedAction;
                        isTargetingActor = true;
                    }
                }
                else
                {
                    for (int i = 0; i < targetActions.Actions.Length; i++)
                    {
                        var a = targetActions.Actions[i];

                        if (a.CanTargetGround && isLocation)
                        {
                            action = a;
                            break;
                        }
                        else if ((!isDead || !a.ShouldIgnoreDead) &&
                                 ((isSelf && a.CanTargetSelf) ||
                                  (isAlly && a.CanTargetAlly) ||
                                  (isEnemy && a.CanTargetEnemy)))
                        {
                            action           = a;
                            isTargetingActor = true;
                            break;
                        }
                    }
                }

                if (action != null)
                {
                    if (isTargetingActor)
                    {
                        if (isSelf)
                        {
                            hideOutline(ref _performerOutline);
                        }

                        showOutline(ref _targetOutline, targetActor, action.UIColor);
                        hideMarker();
                        hideSphere();
                    }
                    else
                    {
                        if (action.UIRadius > 0.001f)
                        {
                            showSphere(target, action.UIColor, action.UIRadius);
                            hideOutline(ref _targetOutline);
                            hideMarker();
                        }
                        else
                        {
                            showMarker(target, action.UIColor);
                            hideOutline(ref _targetOutline);
                            hideSphere();
                        }
                    }
                }

                if (isMouseDown)
                {
                    isMouseDown = false;

                    if (action != null)
                    {
                        if (action.CanTargetGround)
                        {
                            targetActions.Execute(action, target);
                        }
                        else
                        {
                            targetActions.Execute(action, targetActor);
                        }

                        if (_forcedAction != null)
                        {
                            _forcedAction = null;
                        }
                    }

                    Target = null;
                }
                else if (Input.GetMouseButtonDown(1))
                {
                    Target = null;
                }
            }
            else
            {
                hideOutline(ref _targetOutline);
                hideMarker();
                hideSphere();
            }
        }
示例#26
0
        private void Update()
        {
            if (!_actor.IsAlive)
            {
                return;
            }

            var wantsToAlwaysAim = AlwaysAim && _motor.Cover == null;

            if (wantsToAlwaysAim)
            {
                Equip(_motor);
            }

            if (_motor.Gun == null)
            {
                return;
            }

            if (_isReloading)
            {
                _isReloading = !_motor.IsGunReady;
            }
            else if (_motor.Gun != null && _motor.Gun.IsClipEmpty)
            {
                _isReloading = true;
                _motor.InputReload();
            }

            var isObstructed = false;

            if (_isFiring && _isAimingAtAPosition)
            {
                var origin = transform.position;

                if (_motor.Cover != null && _motor.Cover.IsTall)
                {
                    if (_motor.CoverDirection > 0 && _motor.IsNearRightCorner)
                    {
                        origin = _motor.Cover.RightCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                    }
                    else if (_motor.CoverDirection < 0 && _motor.IsNearLeftCorner)
                    {
                        origin = _motor.Cover.LeftCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x);
                    }
                }

                var start    = origin + Vector3.up * 2;
                var distance = Vector3.Distance(start, _aim);

                if (distance > 1.5f)
                {
                    isObstructed = AIUtil.IsObstructed(start, _aim, distance - 1.5f);
                }
            }

            if (_motor.Cover == null && (_isAiming || wantsToAlwaysAim) && !_isReloading)
            {
                _motor.InputAim();
            }

            if (_isFiring && !_isReloading && !isObstructed)
            {
                var cycleDuration = _motor.Cover != null ? CoverBursts.CycleDuration : Bursts.CycleDuration;

                if (_fireCycle >= cycleDuration)
                {
                    if (_isFiringABurst)
                    {
                        _gunBurstsWereCalculatedFor = _motor.Gun;
                        _burstBulletCount           = _bulletCountAtStart - _motor.Gun.Clip;
                    }

                    _isFiringABurst = false;
                    _fireCycle     -= cycleDuration;

                    if (_gunBurstsWereCalculatedFor == _motor.Gun && _motor.Gun.Clip < _burstBulletCount)
                    {
                        _isReloading = true;
                        _motor.InputReload();
                    }
                }

                if (_motor.Cover != null)
                {
                    if (_fireCycle >= CoverBursts.Wait)
                    {
                        _motor.InputAim();

                        if (_fireCycle >= CoverBursts.Wait + CoverBursts.IntroDuration &&
                            _fireCycle < CoverBursts.CycleDuration - CoverBursts.OutroDuration)
                        {
                            if (!_isFiringABurst)
                            {
                                _bulletCountAtStart = _motor.Gun.Clip;
                                _isFiringABurst     = true;
                            }

                            if (_motor.IsGunReady)
                            {
                                _motor.InputFireOnCondition(_actor.Side);
                            }
                        }
                    }
                }
                else
                {
                    _motor.InputAim();

                    if (_fireCycle >= Bursts.Wait)
                    {
                        if (!_isFiringABurst)
                        {
                            _bulletCountAtStart = _motor.Gun.Clip;
                            _isFiringABurst     = true;
                        }

                        if (_motor.IsGunReady)
                        {
                            _motor.InputFireOnCondition(_actor.Side);
                        }
                    }
                }

                _fireCycle += Time.deltaTime;
            }
            else
            {
                _fireCycle      = 0;
                _isFiringABurst = false;
            }
        }
示例#27
0
        private bool checkIncomingCollisions(Vector3 ownMovement, float speed)
        {
            var count = AIUtil.FindActors(transform.position, ObstructionRadius, _actor);

            var ownMovementMagnitude = ownMovement.magnitude;
            var hasOwnMovement       = ownMovementMagnitude > 0.25f;
            var ownDirection         = ownMovement / ownMovementMagnitude;

            var closestDot       = 0f;
            var closestVector    = Vector3.zero;
            var closestDirection = Vector3.zero;
            var closestPosition  = Vector3.zero;
            var isClosestPrimary = false;
            var isClosestStatic  = false;
            var hasClosest       = false;

            for (int i = 0; i < count; i++)
            {
                var other = AIUtil.Actors[i];

                if (other.Side != _actor.Side && other.IsAggressive && _actor.IsAggressive)
                {
                    continue;
                }

                Vector3 velocity;
                float   magnitude;

                var movement = _movements.ContainsKey(other) ? _movements[other] : null;
                var isStatic = false;

                if (movement != null && movement._isAvoidingMover)
                {
                    velocity  = movement._avoidDirection;
                    magnitude = 1;
                }
                else
                {
                    velocity  = other.Motor.MovementDirection;
                    magnitude = velocity.magnitude;

                    if (magnitude < 0.1f)
                    {
                        var body = other.Body;

                        if (body == null)
                        {
                            continue;
                        }

                        velocity  = body.velocity;
                        magnitude = velocity.magnitude;

                        if (magnitude < 0.1f)
                        {
                            if (hasOwnMovement)
                            {
                                isStatic  = true;
                                velocity  = -ownMovement;
                                magnitude = 1;
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }
                }

                var direction = velocity / magnitude;

                if (hasOwnMovement && Vector3.Dot(ownDirection, direction) > -0.5f)
                {
                    continue;
                }

                var vector = (transform.position - other.transform.position).normalized;
                var dot    = Vector3.Dot(direction, vector);

                if (dot < 0.7f)
                {
                    continue;
                }

                var isPrimary = (movement == null ? true : !movement._isAvoidingMover) && !isStatic;

                if (!hasClosest || (isClosestStatic && !isStatic) || (isPrimary && !isClosestPrimary) || (isPrimary && dot > closestDot) || (!isPrimary && !isClosestPrimary && dot > closestDot))
                {
                    hasClosest       = true;
                    isClosestPrimary = isPrimary;
                    isClosestStatic  = isStatic;
                    closestPosition  = other.transform.position;
                    closestDirection = direction;
                    closestVector    = vector;
                    closestDot       = dot;
                }
            }

            if (hasClosest)
            {
                if (!isClosestPrimary && !isClosestStatic && !hasOwnMovement && canMoveInDirection(closestVector))
                {
                    return(avoid(closestVector, speed));
                }

                var point    = Util.FindClosestToPath(closestPosition, closestPosition + closestDirection * 100, transform.position);
                var vector   = transform.position - point;
                var distance = vector.magnitude;

                if (distance < 0.1f)
                {
                    var right = Vector3.Cross(closestVector, Vector3.up);
                    var left  = -right;

                    if (hasOwnMovement && isClosestStatic)
                    {
                        right = (right + ownMovement).normalized;
                        left  = (left + ownMovement).normalized;
                    }

                    if (canMoveInDirection(right))
                    {
                        return(avoid(right, speed));
                    }

                    if (canMoveInDirection(left))
                    {
                        return(avoid(left, speed));
                    }
                }
                else
                {
                    var direction = vector / distance;

                    if (hasOwnMovement && isClosestStatic)
                    {
                        direction = (direction + ownMovement).normalized;
                    }

                    if (canMoveInDirection(direction))
                    {
                        return(avoid(direction, speed));
                    }
                }

                if (isClosestPrimary && !isClosestStatic && !hasOwnMovement && canMoveInDirection(closestVector))
                {
                    return(avoid(closestVector, speed));
                }
            }

            return(false);
        }
示例#28
0
        private void Update()
        {
            if (_autoWait > float.Epsilon)
            {
                _autoWait -= Time.deltaTime;
            }
            if (_checkWait > float.Epsilon)
            {
                _checkWait -= Time.deltaTime;
            }
            if (_coverTimer > float.Epsilon)
            {
                _coverTimer -= Time.deltaTime;
            }

            if (_active != null && (!_active.Update() || (!_active.HasNoTimeout && (Time.timeSinceLevelLoad - _actionStart) > Timeout)))
            {
                end();
            }

            if (_actor.Cover == null)
            {
                _isInCover  = false;
                _coverTimer = 0;
            }
            else if (!_isInCover)
            {
                _coverTimer = CoverDelay;
                _isInCover  = true;
            }

            if (_active == null &&
                _autoWait <= float.Epsilon &&
                _checkWait <= float.Epsilon &&
                _brain.enabled &&
                _brain.State != FighterState.process &&
                _actor.IsAlive &&
                _coverTimer <= float.Epsilon &&
                (!WaitForCoverActions || !_isTakingCover))
            {
                _checkWait = 0.5f;
                _nearbyActors.Clear();

                {
                    var count = AIUtil.FindActorsIncludingDead(transform.position, AutoDistance);
                    for (int i = 0; i < count; i++)
                    {
                        _nearbyActors.Add(AIUtil.Actors[i]);
                    }
                }

                var canUseAttackAction = !AutoAttackOnlyFromCover || _actor.Cover != null;

                AIAction bestSingleAction       = null;
                Actor    bestSingleActionTarget = null;

                ///////////////////////////////////////////////////////
                //
                // CONSIDER MULTIPLE TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                AIAction bestMultipleAction            = null;
                int      bestMultipleActionTargetCount = 0;

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || action.NeedsSingleTargetActor || action.NeedsTargetLocation || action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    int count = 0;

                    for (int j = 0; j < Actors.Count; j++)
                    {
                        var actor = Actors.Get(j);

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor.Side == _actor.Side)
                        {
                            if (((actor == _actor && action.CanTargetSelf) || action.CanTargetAlly) && action.IsNeededFor(actor))
                            {
                                count++;
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor)))
                        {
                            count++;
                        }
                    }

                    if (count > bestMultipleActionTargetCount)
                    {
                        bestMultipleAction            = action;
                        bestMultipleActionTargetCount = count;
                    }
                }

                if (bestMultipleAction != null)
                {
                    _autoWait = AutoCooldown;
                    Execute(bestMultipleAction);
                    return;
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER SELF ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    if (action.CanTargetSelf && action.IsNeededFor(_actor))
                    {
                        if (_actor == Priority)
                        {
                            _autoWait = AutoCooldown;
                            Execute(action, _actor);
                            return;
                        }

                        bestSingleAction       = action;
                        bestSingleActionTarget = _actor;
                        break;
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER SINGLE TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsSingleTargetActor)
                    {
                        continue;
                    }

                    Actor best         = null;
                    var   bestDistance = 0f;
                    var   isBestSelf   = false;

                    for (int j = 0; j < _nearbyActors.Count; j++)
                    {
                        var actor = _nearbyActors[j];

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor == _actor)
                        {
                            if (action.CanTargetSelf && action.IsNeededFor(actor))
                            {
                                if (actor == Priority)
                                {
                                    _autoWait = AutoCooldown;
                                    Execute(action, actor);
                                    return;
                                }

                                if (best == null)
                                {
                                    best         = actor;
                                    bestDistance = 0;
                                    isBestSelf   = true;
                                }
                            }
                        }
                        else if (actor.Side == _actor.Side)
                        {
                            if (action.CanTargetAlly && action.IsNeededFor(actor))
                            {
                                if (actor == Priority)
                                {
                                    _autoWait = AutoCooldown;
                                    Execute(action, actor);
                                    return;
                                }

                                var distance = Vector3.Distance(transform.position, actor.transform.position);

                                if (best == null || isBestSelf || distance < bestDistance)
                                {
                                    best         = actor;
                                    bestDistance = distance;
                                    isBestSelf   = false;
                                }
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor) && (!AutoAttackOnlyFromCover || !action.WillMoveForActor(actor)))
                        {
                            if (actor == Priority)
                            {
                                _autoWait = AutoCooldown;
                                Execute(action, actor);
                                return;
                            }

                            var distance = Vector3.Distance(transform.position, actor.transform.position);

                            if (best == null || isBestSelf || distance < bestDistance)
                            {
                                best         = actor;
                                bestDistance = distance;
                                isBestSelf   = false;
                            }
                        }
                    }

                    if (best != null)
                    {
                        bestSingleAction       = action;
                        bestSingleActionTarget = best;
                        break;
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER AREA ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || !action.NeedsTargetLocation)
                    {
                        continue;
                    }

                    _possibleActionTargets.Clear();

                    for (int j = 0; j < _nearbyActors.Count; j++)
                    {
                        var actor = _nearbyActors[j];

                        if (!actor.IsAlive && action.ShouldIgnoreDead)
                        {
                            continue;
                        }

                        if (actor == _actor)
                        {
                            if (action.CanTargetSelf && action.IsNeededFor(actor))
                            {
                                _possibleActionTargets.Add(actor);
                            }
                        }
                        else if (actor.Side == _actor.Side)
                        {
                            if (action.CanTargetAlly && action.IsNeededFor(actor))
                            {
                                _possibleActionTargets.Add(actor);
                            }
                        }
                        else if (canUseAttackAction && action.CanTargetEnemy && action.IsNeededFor(actor))
                        {
                            _possibleActionTargets.Add(actor);
                        }
                    }

                    if (_possibleActionTargets.Count == 0 || (_possibleActionTargets.Count == 1 && bestSingleAction != null))
                    {
                        continue;
                    }

                    if (action.UIRadius > float.Epsilon)
                    {
                        var radius = action.UIRadius;
                        var steps  = (int)(2 * AutoDistance / radius);

                        var hasBest         = false;
                        var bestPosition    = Vector3.zero;
                        var bestDistance    = 0f;
                        var bestActorCount  = 0;
                        var bestHasPriority = false;

                        for (int x = -steps / 2; x < steps / 2; x++)
                        {
                            for (int y = -steps / 2; y < steps / 2; y++)
                            {
                                var position = transform.position + new Vector3(x * action.UIRadius, 0, y * radius);
                                var distance = Vector3.Distance(position, transform.position);

                                if (distance > AutoDistance)
                                {
                                    continue;
                                }

                                if (AutoAttackOnlyFromCover && action.CanTargetEnemy && action.WillMoveForPosition(position))
                                {
                                    continue;
                                }

                                var actorCount  = 0;
                                var hasPriority = false;

                                for (int j = 0; j < _possibleActionTargets.Count; j++)
                                {
                                    var a = _possibleActionTargets[j];

                                    if (Vector3.Distance(position, a.transform.position) < radius)
                                    {
                                        actorCount++;

                                        if (a == Priority)
                                        {
                                            hasPriority = true;
                                        }
                                    }
                                }

                                if (actorCount > 0)
                                {
                                    var isBetter = false;

                                    if (!hasBest)
                                    {
                                        isBetter = true;
                                    }
                                    else if (hasPriority && !bestHasPriority)
                                    {
                                        isBetter = false;
                                    }
                                    else if (!bestHasPriority)
                                    {
                                        if (actorCount > bestActorCount)
                                        {
                                            isBetter = true;
                                        }
                                        else if (actorCount == bestActorCount)
                                        {
                                            isBetter = distance < bestDistance;
                                        }
                                    }

                                    if (isBetter)
                                    {
                                        hasBest         = true;
                                        bestPosition    = position;
                                        bestDistance    = distance;
                                        bestHasPriority = hasPriority;
                                        bestActorCount  = actorCount;
                                    }
                                }
                            }
                        }

                        if (hasBest &&
                            (bestSingleAction == null || bestActorCount > 1))
                        {
                            _autoWait = AutoCooldown;
                            Execute(action, bestPosition);
                            return;
                        }
                    }
                }

                ///////////////////////////////////////////////////////
                //
                // EXECUTE BEST SINGLE IF NO AREA POSSIBLE
                //
                ///////////////////////////////////////////////////////

                if (bestSingleAction != null)
                {
                    _autoWait = AutoCooldown;
                    Execute(bestSingleAction, bestSingleActionTarget);
                }

                ///////////////////////////////////////////////////////
                //
                // CONSIDER NON-TARGET ACTIONS
                //
                ///////////////////////////////////////////////////////

                for (int i = 0; i < Actions.Length; i++)
                {
                    var action = Actions[i];
                    if (action.Wait > float.Epsilon || !action.Auto || action.CanTargetAny || action.CanTargetGround || action.UIRadius > float.Epsilon || action.CanTargetMultiple || action.NeedsOnlySelf)
                    {
                        continue;
                    }

                    _autoWait = AutoCooldown;
                    Execute(action);
                    return;
                }
            }
        }
示例#29
0
        private void consider(Cover cover, Vector3 position, int direction, Vector3 observer, float maxDistance)
        {
            if (float.IsNaN(position.x) || float.IsNaN(position.z))
            {
                return;
            }

            CoverItem item = new CoverItem();

            item.Cover      = cover;
            item.Position   = position;
            item.Position.y = cover.Bottom;
            item.Distance   = Vector3.Distance(observer, item.Position);
            item.Direction  = direction;

            var distanceToObserver = Vector3.Distance(observer, item.Position);

            if (distanceToObserver > maxDistance)
            {
                return;
            }

            var areThereOthers = false;

            const float threshold = 3;

            if (cover.IsTall)
            {
                if (!AIUtil.IsCoverPositionFree(cover, item.Position, threshold, null))
                {
                    areThereOthers = true;
                }
            }
            else
            {
                var hasChangedPosition = false;

                Vector3 side;

                if (Vector3.Dot((item.Position - observer).normalized, cover.Right) > 0)
                {
                    side = cover.Right;
                }
                else
                {
                    side = cover.Left;
                }

                do
                {
                    hasChangedPosition = false;

                    if (!AIUtil.IsCoverPositionFree(cover, item.Position, threshold, null))
                    {
                        var next = item.Position + side * 0.5f;

                        if (cover.IsInFront(next, false))
                        {
                            item.Position      = next;
                            hasChangedPosition = true;
                        }
                        else
                        {
                            areThereOthers = true;
                        }
                    }
                }while (hasChangedPosition);
            }

            if (areThereOthers)
            {
                return;
            }

            Items.Add(item);
        }
示例#30
0
        private static void debugAI(Transform transform)
        {
#if UNITY_EDITOR
            var motor = transform.GetComponent <CharacterMotor>();
            if (motor == null || !motor.IsAlive)
            {
                return;
            }

            var ai = transform.GetComponent <AIController>();
            if (ai == null)
            {
                return;
            }

            var position = transform.position + Vector3.up * 2;
            var offset   = -8;

            DebugText.Draw(ai.State.ToString(), position, 0, offset);
            offset += 16;

            DebugText.Draw(ai.StateReason.ToString(), position, 0, offset);
            offset += 16;

            if (ai.IsAlerted)
            {
                if (ai.Situation.WouldLikeToRetreat)
                {
                    DebugText.Draw("Would like to retreat", position, 0, offset, Color.yellow);
                    offset += 16;
                }

                if (motor.Target != null)
                {
                    var actor = motor.Target.GetComponent <Actor>();

                    if (actor != null && actor.Side == ai.Actor.Side)
                    {
                        DebugText.Draw("Is aiming at a friend", position, 0, offset, Color.red);
                        offset += 16;
                    }
                }

                if (ai.Situation.IsAllowedToBeAggressive)
                {
                    DebugText.Draw("Is aggressive", position, 0, offset, Color.green);
                    offset += 16;
                }

                if (ai.IsAiming)
                {
                    DebugText.Draw("Is aiming", position, 0, offset, Color.cyan);
                    offset += 16;
                }

                if (ai.Situation.Threat != null)
                {
                    if (ai.Situation.CanSeeTheThreat)
                    {
                        Debug.DrawLine(ai.Situation.CurrentPosition, ai.Situation.ThreatGroundPosition, Color.green);
                    }
                    else
                    {
                        Debug.DrawLine(ai.Situation.CurrentPosition, ai.Situation.ThreatGroundPosition, Color.red);
                    }
                }
                else
                {
                    Debug.DrawLine(ai.Situation.CurrentPosition, ai.Situation.ThreatGroundPosition, Color.red);
                }
            }

            if (AIUtil.IsMovingState(ai.State))
            {
                Debug.DrawLine(ai.Situation.CurrentPosition, ai.Situation.TargetPosition, Color.blue);
            }
#endif
        }