public virtual void TakeDamage(float damage, GameObject attacker = null, ParticleType particleType = ParticleType.None, Transform hitSource = null) { Character character = GetComponentInParent <Character>(); // Nobody should be able to hit him/herself if (attacker == character.gameObject) { return; } if (character != null) { bool rightHit = true; // Figuring out whether it's a hit from the right or left float sign = Mathf.Sign(Vector3.Cross((transform.position - character.transform.position).normalized, character.transform.forward).y); if (sign < 0) { rightHit = false; } character.Animator.SetTrigger(rightHit ? "HitRight" : "HitLeft"); } if (_stateMachine != null) { _stateMachine.AISCanner.AddPotentialThreat(attacker); // If we just took damage from nowhere (when we don't have a player or a character as target, then we look around and set the attacker as an angry at threat) if ((_stateMachine.CurrentTarget == null || (_stateMachine.CurrentTarget != null && (_stateMachine.CurrentTarget.Type != AITargetType.Enemy && _stateMachine.CurrentTarget.Type != AITargetType.Player)))) { _stateMachine.CurrentTarget = null; _stateMachine.Agent.ResetPath(); _stateMachine.SwitchState(AIState.AIStateType.Alert); _justGotHit = true; _resetJustGotHitTime = Time.time + 5f; } } _health -= damage; _health = Mathf.Max(0, _health); if (particleType != ParticleType.None) { GameManager.Instance.ParticlesManager.InstantiatePaticle(particleType, hitSource == null ? transform.position :hitSource.position); } if (_health <= 0) { Die(); } }
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); } } }