public virtual void UpdateAi() { // reset our inputs Horz = 0; Vert = 0; var obstacleFinderResult = IsObstacleAhead(); switch (CurrentAiState) { // ----------------------------- case AIState.MovingLookingForTarget: // look for chase target if (FollowTarget != null) { LookAroundFor(FollowTarget); } // the AvoidWalls function looks to see if there's anything in-front. If there is, // it will automatically change the value of moveDirection before we do the actual move if (obstacleFinderResult == 1) { // GO LEFT SetAiState(AIState.StoppedTurningLeft); } if (obstacleFinderResult == 2) { // GO RIGHT SetAiState(AIState.StoppedTurningRight); } if (obstacleFinderResult == 3) { // BACK UP SetAiState(AIState.BackingUpLookingForTarget); } // all clear! head forward MoveForward(); break; case AIState.ChasingTarget: // chasing // in case mode, we point toward the target and go right at it! // quick check to make sure that we have a target (if not, we drop back to patrol mode) if (FollowTarget == null) { SetAiState(AIState.MovingLookingForTarget); } // the TurnTowardTarget function does just that, so to chase we just throw it the current target TurnTowardTarget(FollowTarget); // find the distance between us and the chase target to see if it is within range _distanceToChaseTarget = Vector3.Distance(MyTransform.position, FollowTarget.position); // check the range if (_distanceToChaseTarget > MinChaseDistance) { // keep charging forward MoveForward(); } // here we do a quick check to test the distance between AI and target. If it's higher than // our maxChaseDistance variable, we drop out of chase mode and go back to patrolling. if (_distanceToChaseTarget > MaxChaseDistance || CanSee(FollowTarget) == false) { // set our state to 1 - moving_looking_for_target SetAiState(AIState.MovingLookingForTarget); } break; // ----------------------------- case AIState.BackingUpLookingForTarget: // look for chase target if (FollowTarget != null) { LookAroundFor(FollowTarget); } // backing up MoveBack(); if (obstacleFinderResult == 0) { // now we've backed up, lets randomize whether to go left or right if (Random.Range(0, 100) > 50) { SetAiState(AIState.StoppedTurningLeft); } else { SetAiState(AIState.StoppedTurningRight); } } break; case AIState.StoppedTurningLeft: // look for chase target if (FollowTarget != null) { LookAroundFor(FollowTarget); } // stopped, turning left TurnLeft(); if (obstacleFinderResult == 0) { SetAiState(AIState.MovingLookingForTarget); } break; case AIState.StoppedTurningRight: // look for chase target if (FollowTarget != null) { LookAroundFor(FollowTarget); } // stopped, turning right TurnRight(); // check results from looking, to see if path ahead is clear if (obstacleFinderResult == 0) { SetAiState(AIState.MovingLookingForTarget); } break; case AIState.PausedLookingForTarget: // standing still, with looking for chase target // look for chase target if (FollowTarget != null) { LookAroundFor(FollowTarget); } break; case AIState.TranslateAlongWaypointPath: // following waypoints (moving toward them, not pointing at them) at the speed of // moveSpeed // make sure we have been initialized before trying to access waypoints if (!DidInit && !ReachedLastWaypoint) { return; } UpdateWaypoints(); // move the ship if (!IsStationary) { _targetMoveVec = Vector3.Normalize(CurrentWaypointTransform.position - MyTransform.position); _moveVec = Vector3.Lerp(_moveVec, _targetMoveVec, Time.deltaTime * PathSmoothing); MyTransform.Translate(_moveVec * MoveSpeed * Time.deltaTime); MoveForward(); if (FaceWaypoints) { TurnTowardTarget(CurrentWaypointTransform); } } break; case AIState.SteerToWaypoint: // make sure we have been initialized before trying to access waypoints if (!DidInit && !ReachedLastWaypoint) { return; } UpdateWaypoints(); if (CurrentWaypointTransform == null) { // it may be possible that this function gets called before waypoints have been set up, so we catch any nulls here return; } // now we just find the relative position of the waypoint from the car transform, // that way we can determine how far to the left and right the waypoint is. RelativeWaypointPosition = MyTransform.InverseTransformPoint(CurrentWaypointTransform.position); // by dividing the horz position by the magnitude, we get a decimal percentage of the turn angle that we can use to drive the wheels Horz = (RelativeWaypointPosition.x / RelativeWaypointPosition.magnitude); // now we do the same for torque, but make sure that it doesn't apply any engine torque when going around a sharp turn... if (Mathf.Abs(Horz) < 0.5f) { Vert = RelativeWaypointPosition.z / RelativeWaypointPosition.magnitude - Mathf.Abs(Horz); } else { NoMove(); } break; case AIState.SteerToTarget: // make sure we have been initialized before trying to access waypoints if (!DidInit) { return; } if (FollowTarget == null) { // it may be possible that this function gets called before a targer has been set up, so we catch any nulls here return; } // now we just find the relative position of the waypoint from the car transform, // that way we can determine how far to the left and right the waypoint is. RelativeWaypointPosition = transform.InverseTransformPoint(FollowTarget.position); // by dividing the horz position by the magnitude, we get a decimal percentage of the turn angle that we can use to drive the wheels Horz = (RelativeWaypointPosition.x / RelativeWaypointPosition.magnitude); // if we're outside of the minimum chase distance, drive! if (Vector3.Distance(FollowTarget.position, MyTransform.position) > MinChaseDistance) { MoveForward(); } else { NoMove(); } if (FollowTarget != null) { LookAroundFor(FollowTarget); } // the AvoidWalls function looks to see if there's anything in-front. If there is, // it will automatically change the value of moveDirection before we do the actual move if (obstacleFinderResult == 1) { // GO LEFT TurnLeft(); } if (obstacleFinderResult == 2) { // GO RIGHT TurnRight(); } if (obstacleFinderResult == 3) { // BACK UP MoveBack(); } break; case AIState.PausedNoTarget: // paused_no_target break; } }