//private IEnumerator AttackDelayTime() //{ // float rand = UnityEngine.Random.Range(.35f, 1.35f); // yield return CustomTimer.Timer(rand); // _canAttack = true; // canStartAttackDelayTime = true; //} //Attack time before going back to followTarget. private IEnumerator AttackTime(float time) { yield return(CustomTimer.Timer(time)); _canReposition = true; CurrentAttackState = RaccoonAttackState.FollowTarget; }
/// <summary> /// Event when entering a state /// </summary> public void OnStateEnter(RaccoonState state, RaccoonState fromState) { //SET MAXSPEED etc. HERE switch (state) { case RaccoonState.Default: { fieldOfView = 60; timesAlerted = 0; _canCheckPathfinding = true; _shouldMoveToHome = true; MaxStableMoveSpeed = 9f; //MaxMoveSpeed = x. //Set target to home position. //Reset numberOfTimesAlerted. break; } case RaccoonState.Alerted: { fieldOfView = 360; timesAlerted += 1; //MaxMoveSpeed = x. //Set target to the detected object (thrown object or player.) //Play a coroutine for x amount of time. //If the player caused the alert, add 1 to numberOfTimesAlerted . (This is reset in the default state.) break; } case RaccoonState.AlertOthers: { //(Field of view doesn't matter here) //Play coroutine for x amount of time. Transition to followTarget. break; } case RaccoonState.Attack: { //_canAttack = true; _canChooseRandomAttack = true; _canCheckPathfinding = true; timesAlerted = 0; _canReposition = true; canThrowRock = true; CurrentAttackState = RaccoonAttackState.FollowTarget; break; } case RaccoonState.Search: { SearchStateCoroutine = StartCoroutine(SearchStateTime()); fieldOfView = 60; break; } } }
//Rock throw timing private IEnumerator RockThrowTime() { float rand = UnityEngine.Random.Range(1f, 2.5f); yield return(CustomTimer.Timer(rand)); Debug.Log("Throwing a rock."); CurrentAttackState = RaccoonAttackState.RockAttack; yield return(CustomTimer.Timer(2.5f)); CurrentAttackState = RaccoonAttackState.FollowTarget; canThrowRock = true; }
/// <summary> /// (Called by KinematicCharacterMotor during its update cycle) /// This is called after the character has finished its movement update /// </summary> public void AfterCharacterUpdate(float deltaTime) { //SET STATE TRANSITIONS HERE. //Switch to default state if in midair if (!Motor.GroundingStatus.IsStableOnGround) { if (CurrentRaccoonState != RaccoonState.Default) { //Get the current state and store it. //Transition to falling state (and transition back to either a new state or the stored state). //Enemy should be able to transition back to the last state without anything screwing up. } } if (pathfinding.PathIsActive) { pathfinding.motorUpDirection = Motor.CharacterUp; } //Check line of sight to the target. _lineOfSightToTarget = LineOfSightToTarget(targetPosition, fieldOfView); //float maxDistance = 12f; Vector3 targetDirection = targetPosition - Motor.Transform.position; //Debug.Log(targetDirection); //State checking switch (CurrentRaccoonState) { case RaccoonState.Default: { if (_lineOfSightToTarget) { TransitionToState(RaccoonState.Alerted); } _lineOfSightToHome = LineOfSightToTarget(homePosition, 360f); //If the home position is too far away... Vector3 homeDirection = homePosition - Motor.Transform.position; Vector3 projectedHomeDirection = Vector3.ProjectOnPlane(homeDirection, Motor.CharacterUp); float homeMaxDistance = 2f; //Debug.Log(homeDirection); if (!_lineOfSightToHome) { if (_canCheckPathfinding) //(Reset this) { _canCheckPathfinding = false; pathfinding.CheckIfCanFollowPath(homePosition); } if (pathfinding.PathIsActive) { _shouldMoveToHome = true; } else { _shouldMoveToHome = false; } } else { //Debug.Log(projectedHomeDirection.magnitude); if (projectedHomeDirection.sqrMagnitude > Mathf.Pow(homeMaxDistance, 2)) { _shouldMoveToHome = true; } else { _shouldMoveToHome = false; } } //If player is detected, transition to alerted state. break; } case RaccoonState.Alerted: { if (timeWhileTargetSeen >= maxAlertedTime || timesAlerted > 1) { //For now, just transition to follow player until group detection is set up. TransitionToState(RaccoonState.Attack); } if (!_lineOfSightToTarget && canStartAlertToSearch) { canStartAlertToSearch = false; AlertToSearchCoroutine = StartCoroutine(AlertToSearchTransitionTime()); } break; } case RaccoonState.AlertOthers: { //Nuthin yet break; } case RaccoonState.Search: { if (_lineOfSightToTarget) { TransitionToState(RaccoonState.Alerted); } break; } case RaccoonState.Attack: { switch (CurrentAttackState) { case RaccoonAttackState.FollowTarget: { float targetDirMagnitude = targetDirection.sqrMagnitude; //Check the player's height //ISSUE: ONLY WORKS ON GROUND PLANE. NEEDS TO WORK WHILE THE ENEMY IS ALSO UP HIGH. float MaxHeightDistance = 2f; Vector3 targetDistOnPlane = Vector3.ProjectOnPlane(targetPosition, Motor.CharacterUp); //*Projects targetPosition on ground plane. float targetHeight = (targetPosition - targetDistOnPlane).sqrMagnitude; //Direction between target's position and it's point on the ground. Vector3 enemyDistOnPlane = Vector3.ProjectOnPlane(Motor.transform.position, Motor.CharacterUp); float enemyHeight = (Motor.transform.position - enemyDistOnPlane).sqrMagnitude; float heightDifference = targetHeight - enemyHeight; //Debug.Log(Mathf.Sqrt(Mathf.Abs(heightDifference))); bool targetIsWithinHeight = Mathf.Abs(heightDifference) < Mathf.Pow(MaxHeightDistance, 2); //The issue here is that we're comparing the player's height to it's point on the ground plane. We need to take the enemy's position into account //as well. (Ex: Repeat the process to get the enemy's height, then get the difference from both the player's height and enemy's height. //Repositioning stuff if (targetIsWithinHeight) { if (!canThrowRock) { canThrowRock = true; } StopActiveCoroutine(RockThrowCoroutine); if (targetDirMagnitude > Mathf.Pow(RepositionDistance, 2)) { //Debug.Log(targetDirMagnitude / targetDirection.magnitude); CurrentFollowState = RaccoonFollowTargetState.MoveToTarget; //** //If 1 hand is free... //Random chance to throw rocks. } else { if (_canReposition) //Remember to reset this, timesRepositioned, AND timesWaited. { _canReposition = false; int rand = UnityEngine.Random.Range(0, 100); //If repositioned/waited up to 3 times... if (timesRepositioned + timesWaitedInPlace <= 3) { //Reposition (up to 2) if ((rand > 50 && rand <= 75) || timesWaitedInPlace > 0) { Debug.Log("Repositioning."); timesRepositioned += 1; CurrentFollowState = RaccoonFollowTargetState.Reposition; RepositionTimeCoroutine = StartCoroutine(RepositionTime(.65f, .95f)); //RepositionTimeCoroutine = StartCoroutine(RepositionTime(, 10f)); } //Wait (up to 1) else if ((rand > 75 && rand <= 100) && timesWaitedInPlace == 0) { Debug.Log("Waiting."); timesWaitedInPlace += 1; CurrentFollowState = RaccoonFollowTargetState.Wait; RepositionTimeCoroutine = StartCoroutine(RepositionTime(.85f, 1.15f)); } } //If over the reposition amount OR rand <= 50... if (timesRepositioned + timesWaitedInPlace > 3 || rand <= 50) { //(Moves towards the target here in moveInputVector) Debug.Log("Continuing movement."); CurrentFollowState = RaccoonFollowTargetState.MoveToTarget; //** } } } } //else if (_lineOfSightToTarget && !pathfinding.PathIsActive) //{ //if (canThrowRock) //{ // canThrowRock = false; // CurrentFollowState = RaccoonFollowTargetState.Wait; // RockThrowCoroutine = StartCoroutine(RockThrowTime()); //} //} //Transition to sword attack switch (CurrentFollowState) { case RaccoonFollowTargetState.MoveToTarget: { if (targetDirMagnitude < Mathf.Pow(AttackDistance, 2)) //** { //Sword Attack. Debug.Log("Sword attack"); CurrentAttackState = RaccoonAttackState.SwordAttack; AttackTimeCoroutine = StartCoroutine(AttackTime(1.2f)); timesRepositioned = 0; timesWaitedInPlace = 0; } break; } } //Pathfinding (line of sight) if (!_lineOfSightToTarget) { CurrentFollowState = RaccoonFollowTargetState.MoveToTarget; if (_canCheckPathfinding) { _canCheckPathfinding = false; pathfinding.CheckIfCanFollowPath(targetPosition); } //If path is unreachable... if (!pathfinding.PathIsActive && !pathfinding.CheckingPath) //*Double check this in game. { //Coroutine to wait? Then... TransitionToState(RaccoonState.Search); } } //Pathfinding (target height check) else if (!targetIsWithinHeight) { if (_canCheckPathfinding) { _canCheckPathfinding = false; pathfinding.CheckIfCanFollowPath(targetPosition); } if (!pathfinding.PathIsActive && !pathfinding.CheckingPath) { if (canThrowRock) { canThrowRock = false; CurrentFollowState = RaccoonFollowTargetState.Wait; RockThrowCoroutine = StartCoroutine(RockThrowTime()); } } } else //*Make sure no other code interrupts this section. { _canCheckPathfinding = true; pathfinding.StopFollowPath(); } break; } } break; } } }