Пример #1
0
    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        AIStatePursuit statePursuit = animator.GetComponent <AIStatePursuit>();

        if (!statePursuit.useRootPosition)
        {
            statePursuit.ResetSpeed();
        }
    }
    private void OnTriggerStay(Collider other)
    {
        if (_stateMachine.Health.IsDead)
        {
            return;
        }

        bool enemyOrPlayerThreatInSight = false;

        // This is for potential threats
        if (other.CompareTag("Player") || other.CompareTag("Enemy"))
        {
            if (_angryAt.Count == 0)
            {
                goto NotAngryAtAnyoneInSight;
            }

            // First check if we are angry at the potential target
            GameObject potentialTargetObject = _angryAt.Find(potentialTarget => potentialTarget == other.gameObject);
            if (potentialTargetObject == null)
            {
                goto NotAngryAtAnyoneInSight;
            }

            // If we are already seeing a player or enemy and the target we just saw is a different one, then we don't do anything
            if (_stateMachine.CurrentTarget != null && _stateMachine.CurrentTarget.TargetTransform.gameObject != other.gameObject &&
                (_stateMachine.CurrentTarget.Type == AITargetType.Player || _stateMachine.CurrentTarget.Type == AITargetType.Enemy))
            {
                return;
            }

            // At this point, we are only interacting with either the target that we already have as a target or a new one (since we don't have a target at all)


            RaycastHit hitInfo;
            if (Physics.Raycast(transform.position, (other.transform.position + Vector3.up) - transform.position, out hitInfo, _sphereCollider.radius, _seeablesMask))
            {
                if (hitInfo.transform.gameObject == other.gameObject)
                {
                    float angle = Vector3.Angle(transform.forward, (other.transform.position + Vector3.up) - transform.position);
                    if (angle <= _fieldOfView)
                    {
                        _stateMachine.SetTarget(other.transform, AITargetType.Player);
                        enemyOrPlayerThreatInSight = true;
                    }
                }
            }

            // Resetting target for when the player or the enemy is inside the scanner collider but not inside the field of view
            // If we were seeing the player or the enemy and no longer see him, then we reset the target after the tolerance time
            if (_stateMachine.CurrentTarget != null && _stateMachine.CurrentTarget.Type == AITargetType.Player && !enemyOrPlayerThreatInSight)
            {
                _targetOutOfSightTime += Time.deltaTime;

                if (_targetOutOfSightTime >= _targetOutOfSightTolerance)
                {
                    _targetOutOfSightTime = 0f;
                    _stateMachine.ResetTarget();
                }
            }
        }

        if (enemyOrPlayerThreatInSight)
        {
            return;
        }

NotAngryAtAnyoneInSight:

        if (other.CompareTag("AIVehicleDetector") &&
            (_stateMachine.CurrentTarget == null || _stateMachine.CurrentTarget.Type != AITargetType.Vehicle) &&
            _stateMachine.CurrentState.GetStateType() != AIState.AIStateType.Vehicle)
        {
            InteractiveVehicle interactiveVehicle = other.GetComponent <InteractiveVehicle>();
            if (interactiveVehicle != null && !interactiveVehicle.Occupied)
            {
                AIStateVehicle aiStateDriving = (AIStateVehicle)(_stateMachine.GetState(AIState.AIStateType.Vehicle));
                if ((aiStateDriving.WantToDrive && interactiveVehicle.DriverSeat) || (aiStateDriving.WantToBePassenger && !interactiveVehicle.DriverSeat))
                {
                    _stateMachine.SetTarget(other.transform, AITargetType.Vehicle);
                    return;
                }
            }
        }

        if (other.CompareTag("Chair") &&
            (_stateMachine.CurrentTarget == null || _stateMachine.CurrentTarget.Type != AITargetType.Chair) &&
            _stateMachine.CurrentState.GetStateType() != AIState.AIStateType.Sitting)
        {
            InteractiveChair interactiveChair = other.GetComponent <InteractiveChair>();
            if (interactiveChair != null && !interactiveChair.IsOccupied)
            {
                AIStateSitting aiStateDriving = (AIStateSitting)(_stateMachine.GetState(AIState.AIStateType.Sitting));
                if (aiStateDriving.IsTired)
                {
                    _stateMachine.SetTarget(other.transform, AITargetType.Chair);
                    return;
                }
            }
        }

        // For social Interaction
        if (other.CompareTag("Enemy"))
        {
            // if we are already interacting socially, then there is nothing to do here
            if (_stateMachine.CurrentTarget != null && _stateMachine.CurrentTarget.Type == AITargetType.Friend)
            {
                return;
            }

            AIStateMachine otherStateMachine = other.GetComponent <AIStateMachine>();

            AIStateSocialInteraction mySocialInteractionState     = (AIStateSocialInteraction)(_stateMachine.GetState(AIState.AIStateType.SocialInteraction));
            AIStatePursuit           myPursuitState               = (AIStatePursuit)(_stateMachine.GetState(AIState.AIStateType.Pursuit));
            AIStateSocialInteraction friendSocialInteractionState = (AIStateSocialInteraction)(otherStateMachine.GetState(AIState.AIStateType.SocialInteraction));
            AIStatePursuit           friendPursuitState           = (AIStatePursuit)(otherStateMachine.GetState(AIState.AIStateType.Pursuit));
            if (mySocialInteractionState.IsFeelingLonely && friendSocialInteractionState.IsFeelingLonely &&
                !otherStateMachine.Health.IsDead)
            {
                // If the friend hasn't gotten into social mode yet by setting a target of type friend, then we are the ones who are going to be making the first move
                if (otherStateMachine.CurrentTarget == null ||
                    otherStateMachine.CurrentTarget.Type == AITargetType.None ||
                    otherStateMachine.CurrentTarget.Type == AITargetType.NavigationPoint ||
                    otherStateMachine.CurrentTarget.Type == AITargetType.BoomBox)
                {
                    myPursuitState.ShouldMakeAMove = true;
                    mySocialInteractionState.FriendSocialInteraction = friendSocialInteractionState;
                    // We set our pursuit mode by setting a target
                    _stateMachine.SetTarget(other.transform, AITargetType.Friend);

                    // the friend should instantly get into social mode
                    friendSocialInteractionState.FriendSocialInteraction = mySocialInteractionState;
                    otherStateMachine.SetTarget(transform, AITargetType.Friend);
                    otherStateMachine.SwitchState(AIState.AIStateType.SocialInteraction);
                }
            }
        }

        if (other.CompareTag("BoomBox"))
        {
            // If we have a more important target: Another AI Agent as an enemy, a friend or a player, then we ignore the boombox
            if (_stateMachine.CurrentTarget != null &&
                (_stateMachine.CurrentTarget.Type == AITargetType.Player ||
                 _stateMachine.CurrentTarget.Type == AITargetType.Enemy ||
                 _stateMachine.CurrentTarget.Type == AITargetType.Friend))
            {
                return;
            }

            AIStateDancing aiStateDancing = (AIStateDancing)(_stateMachine.GetState(AIState.AIStateType.Dancing));
            if (aiStateDancing.IsHungry)
            {
                _stateMachine.SetTarget(other.transform, AITargetType.BoomBox);
            }
        }
    }
Пример #3
0
    private void Start()
    {
        // Getting cache variables
        _navMeshAgent     = GetComponent <NavMeshAgent>();
        _animator         = GetComponent <Animator>();
        _mouthAudioSource = GetComponent <AudioSource>();
        _targetTrigger    = GetComponentInChildren <TargetTrigger>();
        AIDecapitation[] parts = GetComponentsInChildren <AIDecapitation>();
        foreach (AIDecapitation part in parts)
        {
            _parts.Add(part);
        }

        HandleAnimatorController();

        // Getting the skinned mesh renderers for the metamorphosis
        if (_metamorphosisMaterial != null)
        {
            SkinnedMeshRenderer[] skinnedMeshRenderers = GetComponentsInChildren <SkinnedMeshRenderer>();
            foreach (SkinnedMeshRenderer meshRenderer in skinnedMeshRenderers)
            {
                _skinnedMeshRenderers.Add(meshRenderer);
            }
        }

        // We always have the rotation of the navmesh deactivated!
        // In fact, we either rotate with the root motion rotation of the turn around animation
        // Or we rotate it manually through code.
        // In sum, the navmesh is only useful for calculating the path: steertingTarget :)
        if (_navMeshAgent != null)
        {
            _navMeshAgent.updateRotation = false;
        }

        if (_targetTrigger != null)
        {
            _targetTrigger.RegisterTargetTrigger(this);
        }

        // Storing states
        AIStateIdle stateIdle = GetComponent <AIStateIdle>();

        if (stateIdle != null)
        {
            _statesDictionary.Add(AIStateType.Idle, stateIdle);
            _statesDictionary[AIStateType.Idle].RegisterState(this);
        }

        AIStatePatrol statePatrol = GetComponent <AIStatePatrol>();

        if (statePatrol != null)
        {
            _statesDictionary.Add(AIStateType.Patrol, statePatrol);
            _statesDictionary[AIStateType.Patrol].RegisterState(this);
        }

        AIStatePursuit statePursuit = GetComponent <AIStatePursuit>();

        if (statePursuit != null)
        {
            _statesDictionary.Add(AIStateType.Pursuit, statePursuit);
            _statesDictionary[AIStateType.Pursuit].RegisterState(this);
        }

        AIStateAttack stateAttack = GetComponent <AIStateAttack>();

        if (stateAttack != null)
        {
            _statesDictionary.Add(AIStateType.Attacking, stateAttack);
            _statesDictionary[AIStateType.Attacking].RegisterState(this);
        }

        AIStateAlert stateAlert = GetComponent <AIStateAlert>();

        if (stateAlert != null)
        {
            _statesDictionary.Add(AIStateType.Alert, stateAlert);
            _statesDictionary[AIStateType.Alert].RegisterState(this);
        }

        if (_statesDictionary.ContainsKey(AIStateType.Idle) && _statesDictionary[AIStateType.Idle] != null)
        {
            ChangeState(AIStateType.Idle);
        }

        // Get all body parts snapshot
        Transform[] bodyParts = transform.GetComponentsInChildren <Transform>();
        foreach (Transform bodyPart in bodyParts)
        {
            BodyPartSnapShot bodyPartSnapshot = new BodyPartSnapShot();
            bodyPartSnapshot.transform = bodyPart;
            _bodyPartsSnapshots.Add(bodyPartSnapshot);
        }

        // At the beginning, we should always be able to scream
        _screamTimer = _screamDelay;

        // Getting the navmesh agent initial speed for damageBehavior (in case we aren't using root rotation)
        if (_navMeshAgent != null)
        {
            _initialSpeed = _navMeshAgent.speed;
        }

        _initialVehicleStoppingDistance = _vehicleStoppingDistance;
    }