Example #1
0
 public AssignedAI(AIController ai, float distance)
 {
     AI       = ai;
     Distance = distance;
 }
Example #2
0
        private void Update()
        {
            var targetTransform = TargetOverride == null ? transform.parent : TargetOverride.transform;

            if (targetTransform == null)
            {
                return;
            }

            if (_cachedTransform != targetTransform)
            {
                _cachedTransform    = targetTransform;
                _cachedAIController = _cachedTransform.GetComponent <AIController>();
                _cachedMotor        = _cachedTransform.GetComponent <CharacterMotor>();
            }

            if (_cachedAIController == null)
            {
                return;
            }

            var character = Characters.Get(_cachedAIController.gameObject);

            if (character.Motor.IsAlive && !_cachedAIController.IsAlerted && (DisplayWhenAway || character.IsAnyInSight(0)))
            {
                _alpha += Time.deltaTime * FadeSpeed;
            }
            else
            {
                _alpha -= Time.deltaTime * FadeSpeed;
            }

            if (_cachedMotor != null)
            {
                var target = _cachedMotor.HeadLookTarget;
                target.y = transform.position.y;

                transform.LookAt(target);
            }

            _alpha = Mathf.Clamp01(_alpha);
            _mesh.Clear();

            var vertexCount = Detail * 3;
            var indexCount  = Detail * 3;

            if (_positions == null || _positions.Length != vertexCount)
            {
                _positions = new Vector3[vertexCount];
            }

            if (_colors == null || _colors.Length != vertexCount)
            {
                _colors = new Color[vertexCount];
            }

            if (_uv == null || _uv.Length != vertexCount)
            {
                _uv = new Vector2[vertexCount];
            }

            var wasEdited = false;

            if (_alpha >= 1f / 255f)
            {
                wasEdited = true;

                var fov      = _cachedAIController.View.FieldOfView * _alpha;
                var distance = _cachedAIController.View.SightDistance;

                for (int i = 0; i < Detail; i++)
                {
                    float a0 = fov * ((float)i / (float)Detail - 0.5f) + 90;
                    float a1 = fov * ((float)(i + 1) / (float)Detail - 0.5f) + 90;

                    _positions[i * 3 + 0] = Vector3.zero;
                    _positions[i * 3 + 1] = new Vector3(Mathf.Cos(a1 * Mathf.Deg2Rad), 0, Mathf.Sin(a1 * Mathf.Deg2Rad)) * distance;
                    _positions[i * 3 + 2] = new Vector3(Mathf.Cos(a0 * Mathf.Deg2Rad), 0, Mathf.Sin(a0 * Mathf.Deg2Rad)) * distance;
                }

                for (int i = 0; i < _colors.Length; i++)
                {
                    _colors[i] = new Color(1, 1, 1, _alpha);
                }

                for (int i = 0; i < _uv.Length; i++)
                {
                    _uv[i] = new Vector2((_positions[i].x / distance) * 0.5f + 0.5f, (_positions[i].z / distance) * 0.5f + 0.5f);
                }

                if (_indices == null || _indices.Length != indexCount)
                {
                    _indices = new int[indexCount];

                    for (int i = 0; i < _indices.Length; i++)
                    {
                        _indices[i] = i;
                    }
                }
            }

            if (wasEdited || !_hasSetAtLeastOnce)
            {
                _hasSetAtLeastOnce = true;

                _mesh.vertices  = _positions;
                _mesh.colors    = _colors;
                _mesh.uv        = _uv;
                _mesh.triangles = _indices;
            }
        }
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            if (targets.Length != 1)
            {
                return;
            }

            EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
            EditorGUILayout.LabelField("Waypoints", EditorStyles.boldLabel);

            var controller = (AIController)targets[0];

            if (controller.Waypoints != null)
            {
                int toDelete    = -1;
                int toMakeFirst = -1;

                if (GUILayout.Button("Reverse"))
                {
                    Undo.RecordObject(controller, "Reverse waypoints");

                    if (controller.Waypoints.Length == 2)
                    {
                        var t = controller.Waypoints[0];
                        controller.Waypoints[0] = controller.Waypoints[1];
                        controller.Waypoints[1] = t;
                    }
                    else if (controller.Waypoints.Length > 2)
                    {
                        for (int i = 1; i < controller.Waypoints.Length / 2 + 1; i++)
                        {
                            var t = controller.Waypoints[i];
                            controller.Waypoints[i] = controller.Waypoints[controller.Waypoints.Length - i];
                            controller.Waypoints[controller.Waypoints.Length - i] = t;
                        }
                    }

                    if (_lastSelectedWaypoint > 0)
                    {
                        _lastSelectedWaypoint = controller.Waypoints.Length - _lastSelectedWaypoint;
                    }
                }

                for (int i = 0; i < controller.Waypoints.Length; i++)
                {
                    EditorGUILayout.Space();

                    var isSelected = controller == _lastSelectedController && i == _lastSelectedWaypoint;

                    if (isSelected)
                    {
                        var oldColor = GUI.backgroundColor;
                        GUI.backgroundColor = Color.green;
                        EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
                        GUI.backgroundColor = oldColor;
                    }
                    else
                    {
                        EditorGUILayout.BeginHorizontal();
                    }

                    var rect = EditorGUILayout.BeginVertical();
                    GUI.Box(rect, GUIContent.none);

                    controller.Waypoints[i].Position = EditorGUILayout.Vector3Field("Position", controller.Waypoints[i].Position);
                    controller.Waypoints[i].Pause    = EditorGUILayout.FloatField("Pause", controller.Waypoints[i].Pause);
                    controller.Waypoints[i].Run      = EditorGUILayout.Toggle("Run", controller.Waypoints[i].Run);

                    if (!isSelected)
                    {
                        if (GUILayout.Button("Select"))
                        {
                            _lastSelectedController = controller;
                            _lastSelectedWaypoint   = i;
                            SceneView.RepaintAll();
                        }
                    }

                    if (i > 0)
                    {
                        if (GUILayout.Button("Make First"))
                        {
                            toMakeFirst = i;
                        }
                    }

                    EditorGUILayout.EndVertical();

                    {
                        var oldColor = GUI.backgroundColor;
                        GUI.backgroundColor = Color.red;
                        if (GUILayout.Button("X", GUILayout.Width(20)))
                        {
                            toDelete = i;
                        }
                        GUI.backgroundColor = oldColor;
                    }

                    EditorGUILayout.EndHorizontal();
                }

                if (toDelete >= 0)
                {
                    deleteWaypoint(controller, toDelete);
                }

                if (toMakeFirst >= 0)
                {
                    Undo.RecordObject(controller, "Make waypoint first");

                    var old = controller.Waypoints;
                    controller.Waypoints = new Waypoint[old.Length];

                    for (int i = 0; i < old.Length; i++)
                    {
                        controller.Waypoints[i] = old[(toMakeFirst + i) % old.Length];
                    }

                    _lastSelectedWaypoint = 0;
                }
            }

            EditorGUILayout.Space();

            if (GUILayout.Button("Add Waypoint"))
            {
                if (controller.Waypoints == null)
                {
                    controller.Waypoints = new Waypoint[1];
                }
                else
                {
                    var old = controller.Waypoints;
                    controller.Waypoints = new Waypoint[old.Length + 1];

                    for (int i = 0; i < old.Length; i++)
                    {
                        controller.Waypoints[i] = old[i];
                    }
                }

                var value = new Waypoint();

                if (controller.Waypoints.Length > 1)
                {
                    value.Position = controller.Waypoints[controller.Waypoints.Length - 2].Position;
                }
                else
                {
                    value.Position = controller.transform.position;
                }

                controller.Waypoints[controller.Waypoints.Length - 1] = value;
            }
        }
Example #4
0
 public bool IsAggressive(AIController ai)
 {
     return(_aggressive.Contains(ai));
 }
        /// <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;
            }
        }
        protected virtual void OnSceneGUI()
        {
            var controller = (AIController)target;
            var controlId  = GUIUtility.GetControlID(_editorHash, FocusType.Passive);

            var hasMousePosition = false;
            var mousePosition    = Vector3.zero;

            if (SceneView.currentDrawingSceneView.camera.pixelRect.Contains(HandleUtility.GUIPointToScreenPixelCoordinate(Event.current.mousePosition)))
            {
                var ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);

                RaycastHit hit;
                if (Physics.Raycast(ray, out hit))
                {
                    if (Vector3.Dot(hit.normal, Vector3.up) > 0.25f)
                    {
                        mousePosition    = hit.point;
                        hasMousePosition = true;
                    }
                }
            }

            var current     = Event.current;
            var hasToSelect = false;

            switch (current.GetTypeForControl(controlId))
            {
            case EventType.KeyDown:
                if (current.keyCode == KeyCode.Delete)
                {
                    if (_lastSelectedController == controller && _lastSelectedController.Waypoints != null && _lastSelectedWaypoint >= 0 && _lastSelectedWaypoint < _lastSelectedController.Waypoints.Length)
                    {
                        deleteWaypoint(_lastSelectedController, _lastSelectedWaypoint);

                        while (_lastSelectedWaypoint >= _lastSelectedController.Waypoints.Length)
                        {
                            _lastSelectedWaypoint--;
                        }

                        current.Use();
                    }
                }
                break;

            case EventType.MouseDown:
            case EventType.MouseDrag:
                if (current.button == 0)
                {
                    if ((GUIUtility.hotControl == 0 && current.GetTypeForControl(controlId) != EventType.MouseDrag && HandleUtility.nearestControl == controlId) ||
                        GUIUtility.hotControl == controlId)
                    {
                        _dontDrawPreview = false;

                        if (hasMousePosition)
                        {
                            if (!_wasMouseTooFarAway)
                            {
                                if (current.type == EventType.MouseDown)
                                {
                                    GUIUtility.hotControl = controlId;
                                    hasToSelect           = true;
                                }
                            }

                            current.Use();
                        }
                    }
                }
                break;

            case EventType.MouseUp:
                if (GUIUtility.hotControl == controlId)
                {
                    GUIUtility.hotControl = 0;
                }
                break;

            case EventType.MouseMove:
                if (HandleUtility.nearestControl != controlId)
                {
                    hasMousePosition = false;
                    _dontDrawPreview = !_wasMouseTooFarAway;
                }
                else
                {
                    _dontDrawPreview = false;
                }

                SceneView.RepaintAll();
                break;

            case EventType.Layout:
                if (!_wasMouseTooFarAway)
                {
                    HandleUtility.AddDefaultControl(controlId);
                }
                break;
            }

            var isHoveringPoint = false;

            var hasLowestPoint = false;
            var lowestPoint    = 0f;

            if (controller.Waypoints != null)
            {
                for (int i = 0; i < controller.Waypoints.Length; i++)
                {
                    if (!hasLowestPoint || controller.Waypoints[i].Position.y < lowestPoint)
                    {
                        hasLowestPoint = true;
                        lowestPoint    = controller.Waypoints[i].Position.y;
                    }
                }

                var oldColor = Handles.color;
                Handles.color = Color.magenta;

                for (int i = 0; i < controller.Waypoints.Length; i++)
                {
                    var bottom = controller.Waypoints[i].Position;
                    bottom.y = lowestPoint;

                    Handles.DrawLine(controller.Waypoints[i].Position, bottom);
                }

                Handles.color = oldColor;
            }

            if (controller.Waypoints != null)
            {
                var oldColor = Handles.color;
                Handles.color = Color.yellow;

                const float maxDistance = 0.5f;

                for (int i = 0; i < controller.Waypoints.Length; i++)
                {
                    if (i == 0 && controller.Waypoints.Length > 1)
                    {
                        var p0    = controller.Waypoints[0].Position;
                        var p1    = controller.Waypoints[1].Position;
                        var right = Vector3.Cross(p1 - p0, Vector3.up);

                        Handles.DrawLine(p1, p1 + Vector3.Lerp(p0 - p1, right, 0.35f) * 0.75f);
                        Handles.DrawLine(p1, p1 + Vector3.Lerp(p0 - p1, -right, 0.35f) * 0.75f);
                        Handles.DrawWireDisc(controller.Waypoints[i].Position, Vector3.up, maxDistance * 0.75f);
                    }

                    var isHovered       = false;
                    var wasJustSelected = false;

                    if (hasMousePosition && !isHoveringPoint && (GUIUtility.hotControl == 0 || hasToSelect))
                    {
                        if (Vector3.Distance(mousePosition, controller.Waypoints[i].Position) < maxDistance)
                        {
                            isHovered       = true;
                            isHoveringPoint = true;

                            if (!_dontDrawPreview)
                            {
                                Handles.color = Color.white;
                                Handles.DrawWireDisc(controller.Waypoints[i].Position, Vector3.up, maxDistance);
                                Handles.color = Color.yellow;
                            }

                            if (hasToSelect)
                            {
                                _lastSelectedWaypoint   = i;
                                _lastSelectedController = controller;
                                hasToSelect             = false;
                                wasJustSelected         = true;
                                EditorUtility.SetDirty(target);
                            }
                        }
                    }

                    if (!hasToSelect && !wasJustSelected)
                    {
                        if (_lastSelectedController == controller && _lastSelectedWaypoint == i)
                        {
                            Handles.color = Color.green;
                            Handles.DrawWireDisc(controller.Waypoints[i].Position, Vector3.up, maxDistance);

                            if (hasMousePosition)
                            {
                                if (GUIUtility.hotControl == controlId)
                                {
                                    controller.Waypoints[i].Position = mousePosition;
                                    Undo.RecordObject(controller, "Moving a waypoint");
                                }
                            }

                            Handles.color = Color.yellow;
                        }
                        else if (!isHovered)
                        {
                            Handles.DrawWireDisc(controller.Waypoints[i].Position, Vector3.up, maxDistance * 0.5f);
                        }
                    }

                    if (controller.Waypoints.Length > 1)
                    {
                        var next = controller.Waypoints[i].Position;

                        Vector3 previous;

                        if (i == 0)
                        {
                            previous = controller.Waypoints[controller.Waypoints.Length - 1].Position;
                        }
                        else
                        {
                            previous = controller.Waypoints[i - 1].Position;
                        }

                        Handles.DrawLine(previous, next);
                    }
                }

                Handles.color = oldColor;
            }

            var canPlacePoint = false;

            if (hasMousePosition && !isHoveringPoint && (GUIUtility.hotControl == 0 || hasToSelect))
            {
                var oldColor = Handles.color;
                Handles.color = Color.white;

                var indexInBetween = -1;
                var minDist        = 0f;

                if (controller.Waypoints != null)
                {
                    const float maxDistance = 8;

                    if (controller.Waypoints.Length == 0)
                    {
                        indexInBetween = -1;
                        canPlacePoint  = Vector3.Distance(mousePosition, controller.transform.position) < maxDistance;
                    }
                    else if (controller.Waypoints.Length == 1)
                    {
                        indexInBetween = 0;
                        canPlacePoint  = Vector3.Distance(mousePosition, controller.Waypoints[0].Position) < maxDistance;

                        if (canPlacePoint && !_dontDrawPreview)
                        {
                            Handles.DrawLine(mousePosition, controller.Waypoints[0].Position);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < controller.Waypoints.Length; i++)
                        {
                            var next = (i == controller.Waypoints.Length - 1) ? 0 : i + 1;

                            var p0   = controller.Waypoints[i].Position;
                            var p1   = controller.Waypoints[next].Position;
                            var dist = Vector3.Distance(mousePosition, Util.FindClosestToPath(p0, p1, mousePosition));

                            if (dist < maxDistance)
                            {
                                if (indexInBetween < 0 || dist < minDist)
                                {
                                    indexInBetween = i;
                                    minDist        = dist;
                                }
                            }
                        }

                        if (indexInBetween >= 0)
                        {
                            canPlacePoint = true;

                            if (!_dontDrawPreview)
                            {
                                var second = (indexInBetween == controller.Waypoints.Length - 1) ? 0 : indexInBetween + 1;
                                Handles.DrawLine(mousePosition, controller.Waypoints[indexInBetween].Position);
                                Handles.DrawLine(mousePosition, controller.Waypoints[second].Position);
                            }
                        }
                    }
                }

                if (canPlacePoint)
                {
                    if (!_dontDrawPreview)
                    {
                        Handles.DrawWireDisc(mousePosition, Vector3.up, 0.5f);

                        if (hasLowestPoint)
                        {
                            Handles.color = Color.grey;
                            Handles.DrawLine(mousePosition, new Vector3(mousePosition.x, lowestPoint, mousePosition.z));
                            Handles.color = Color.white;
                        }
                    }

                    if (hasToSelect)
                    {
                        Undo.RecordObject(controller, "Adding a waypoint");

                        var index = indexInBetween + 1;

                        if (controller.Waypoints == null)
                        {
                            controller.Waypoints = new Waypoint[1];
                        }
                        else if (controller.Waypoints.Length == 1)
                        {
                            var old = controller.Waypoints[0];
                            controller.Waypoints    = new Waypoint[2];
                            controller.Waypoints[0] = old;
                        }
                        else
                        {
                            var old = controller.Waypoints;
                            controller.Waypoints = new Waypoint[old.Length + 1];

                            for (int i = 0; i < index; i++)
                            {
                                controller.Waypoints[i] = old[i];
                            }

                            for (int i = index; i < old.Length; i++)
                            {
                                controller.Waypoints[i + 1] = old[i];
                            }
                        }

                        controller.Waypoints[index].Position = mousePosition;

                        if (index > 0)
                        {
                            controller.Waypoints[index].Run = controller.Waypoints[index - 1].Run;
                        }
                        else
                        {
                            controller.Waypoints[index].Run = controller.Waypoints[controller.Waypoints.Length - 1].Run;
                        }

                        _lastSelectedController = controller;
                        _lastSelectedWaypoint   = index;
                    }
                }

                Handles.color = oldColor;
            }

            _wasMouseTooFarAway = !canPlacePoint && !isHoveringPoint;
        }
Example #7
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++;
                }
            }
        }
Example #8
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);
            }
        }
Example #9
0
 /// <summary>
 /// Returns true if the given position on the cover protects the character from the enemy.
 /// </summary>
 public static bool IsGoodAngle(AIController controller, Cover cover, Vector3 positionOnCover, Vector3 enemy, bool isTall)
 {
     return(IsGoodAngle(controller.Cover.MaxTallAngle, controller.Cover.MaxLowAngle, cover, positionOnCover, enemy, isTall));
 }
Example #10
0
 /// <summary>
 /// Returns true if a given position is in sight.
 /// </summary>
 public static bool IsInSight(AIController controller, Vector3 target)
 {
     return(IsInSight(controller, controller.transform.position, target));
 }
Example #11
0
        /// <summary>
        /// Returns an updated situation struct.
        /// </summary>
        public void Update(AIController controller, AISituation previous, bool updateInDetail)
        {
            if (!IsAlerted)
            {
                HasInvestigatedTheLatestAlert = false;
            }
            else if (!HasInvestigatedTheLatestAlert && Vector3.Distance(CurrentPosition, InvestigationPosition) < controller.Distances.ThreatInvestigation)
            {
                MarkInvestigated();
            }

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

            if (IsIrritated)
            {
                if (IrritationTime > controller.Fighting.Irritation)
                {
                    IrritationTime = 0;
                    IsIrritated    = false;
                }
                else
                {
                    IrritationTime += Time.deltaTime;
                }
            }
            else
            {
                IrritationTime = 0;
            }

            // 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;
                                IsThreatPositionANewAlert     = true;
                                SetThreatPosition(grenade.transform.position, true);
                            }
                        }
                    }
                }
            }

            // Check friends and enemies.
            if (Threat == null || (!IsAlerted && !IsGettingAlerted))
            {
                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.State != AIState.investigate)
                                {
                                    if (actor.AI.Situation.Threat != null && actor.AI.Situation.HasBetterThreatInfo(actor.AI, ref this))
                                    {
                                        TakeEnemyState(actor.AI);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }

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

            var isCheckingAThreatInCover = Threat != null && IsThreatInCover && !CanSeeTheThreat;

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

                foreach (var alert in Alerts.All)
                {
                    bool  isOk;
                    Actor newThreat = null;

                    if (Threat != null)
                    {
                        if (alert.Actor == null)
                        {
                            isOk = NoThreatVisibilityTime > 6;
                        }
                        else if (alert.Actor.Side != controller.Actor.Side)
                        {
                            isOk      = true;
                            newThreat = alert.Actor;
                        }
                        else if (alert.Actor.AI != null)
                        {
                            isOk = NoThreatVisibilityTime > 2 && alert.Actor.AI.Situation.NoThreatVisibilityTime < 1;
                        }
                        else
                        {
                            isOk = NoThreatVisibilityTime > 6;
                        }
                    }
                    else
                    {
                        isOk = true;
                    }

                    if (isOk)
                    {
                        var dist = Vector3.Distance(controller.transform.position, alert.Position);

                        if (dist < alert.Range)
                        {
                            if (dist < minDist)
                            {
                                minDist   = dist;
                                IsAlerted = true;

                                HasAnInvestigatedAlert        = false;
                                HasInvestigatedTheLatestAlert = false;

                                if (newThreat != null)
                                {
                                    ReadEnemyState(newThreat);
                                }
                                else
                                {
                                    IsThreatPositionANewAlert = true;
                                    SetThreatPosition(alert.Position, true);
                                }
                            }
                        }
                    }
                }
            }

            // 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 (Threat == null || Threat.IsAggressive)
            {
                WouldLikeToRetreat = controller.Health.Health <= controller.Fighting.MinHealth;
            }
            else
            {
                WouldLikeToRetreat = false;
            }

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

                if (Threat != null)
                {
                    var noPatience = NoThreatVisibilityTime > controller.Fighting.Patience;

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

                    if (CanSeeTheThreat)
                    {
                        ReadEnemyState(Threat);

                        if (!couldSeeTheEnemy && noPatience)
                        {
                            IsIrritated = true;
                        }
                    }
                    else
                    {
                        if (noPatience || (NoThreatVisibilityTime > 2 && (!IsThreatInCover || Vector3.Dot(ThreatCoverForward, ThreatGroundPosition - CurrentPosition) > 0)))
                        {
                            if (!IsThreatInCover ||
                                noPatience ||
                                Vector3.Distance(CurrentPosition, ThreatGroundPosition) < controller.Distances.ThreatInvestigation ||
                                AIUtil.IsInSight(controller, (ThreatGroundPosition + ThreatTopPosition) * 0.5f))
                            {
                                CanSeeThatNoThreatAtLastPosition = true;
                            }
                        }

                        NoThreatVisibilityTime += Time.deltaTime;

                        if (updateInDetail)
                        {
                            // Check friends.
                            foreach (var friend in Actors.All)
                            {
                                if (friend != controller.Actor &&
                                    friend.Side == controller.Actor.Side &&
                                    friend.AI != null &&
                                    friend.AI.IsAlerted &&
                                    friend.AI.State != AIState.investigate &&
                                    friend.AI.Situation.Threat == Threat &&
                                    friend.AI.Situation.HasBetterThreatInfo(friend.AI, ref this))
                                {
                                    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) &&
                                        !AIUtil.IsCoverPositionTooCloseToFriends(TargetCover, controller, TargetPosition);
                }

                if (updateInDetail)
                {
                    if (IsThreatInCover)
                    {
                        if (CurrentCover != null && CurrentCover.IsTall)
                        {
                            var aimPoint = Vector3.zero;
                            var isGood   = true;

                            if (TargetDirection < 0)
                            {
                                isGood = CurrentCover.IsLeft(Util.AngleOfVector(ThreatStandingTopPosition - CurrentCover.LeftCorner(0)), controller.Motor.CoverSettings.Angles.LeftCorner, false);

                                if (isGood)
                                {
                                    aimPoint = CurrentCover.LeftCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                                }
                            }
                            else
                            {
                                isGood = CurrentCover.IsRight(Util.AngleOfVector(ThreatStandingTopPosition - CurrentCover.RightCorner(0)), controller.Motor.CoverSettings.Angles.LeftCorner, false);

                                if (isGood)
                                {
                                    aimPoint = CurrentCover.RightCorner(0, controller.Motor.CoverSettings.CornerOffset.x);
                                }
                            }

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