/* * author: ryan lin * date: 30/7/2024 * description: making the car go to a game object's position */ using System.Collections; using UnityEngine; /// /// making the car go to a game object's position /// public class AICar : MonoBehaviour { /// /// reference to the car model /// [SerializeField] private Transform carPosition; /// /// the radius of which the car can stop in /// [SerializeField] private float stoppingDistance; /// /// the speed of which the car needs to be at/under to when it is in the slowed state /// [SerializeField] private float slowingSpeed; /// /// the radius that the car switches to the slowed state /// [SerializeField] private float slowingDistance; /// /// the distance that the car is allowed to reverse /// [SerializeField] private float reverseDist; /// /// the acceleration input for the car script /// private float _accelerationInput; /// /// the angular input for the car script /// private float _angularDirection; /// /// reference to the car script /// private CarController _car; /// /// the current state the car is in for fsm /// private string _currentState; /// /// the distance that the car is from the target /// private float _distanceToTarget; /// /// the transform of the target /// private Transform _driveTarget; private NextState _nextState; /// /// the turn input for the car script /// private float _turnInput; /// /// the car is in front or behind the target, a positive will be returned if the car is in front /// private float _verticalDirection; /// /// initialise values /// private void Awake() { var hasChild = false; var i = 0; while (!hasChild) { var test = gameObject.transform.GetChild(i).gameObject; if (test.name == "Target") { _driveTarget = test.transform; hasChild = true; } else { i++; } } _car = GetComponent(); _nextState = NextState.Stopped; _currentState = "Stopped"; StartCoroutine(_currentState); } /// /// to update the next state value when it changes /// private void Update() { if (_nextState == NextState.Stopped) _currentState = "Stopped"; else if (_nextState == NextState.Slowed) _currentState = "Slowed"; else _currentState = "Driving"; } /// /// is called at the end of states to call the next state /// private void ChangeState() { StartCoroutine(_currentState); } /// /// a function that allows the car to steer /// private void Steering() { _angularDirection = Vector3.SignedAngle(carPosition.transform.forward, (_driveTarget.position - carPosition.transform.position).normalized, Vector3.up); if (_angularDirection < 0) _turnInput = -1; else _turnInput = 1; } /// /// to put the car in a stopped state /// private IEnumerator Stopped() { while (_nextState != NextState.Stopped) { _distanceToTarget = Vector3.Distance(carPosition.position, _driveTarget.position); _car.braking = true; _accelerationInput = 0f; _turnInput = 0f; if (_distanceToTarget > stoppingDistance) _nextState = NextState.Slowed; yield return new WaitForSeconds(1); } ChangeState(); } /// /// to put the car in a slowed state /// private IEnumerator Slowed() { _car.braking = false; while (_nextState != NextState.Slowed) { _verticalDirection = Vector3.Dot(carPosition.transform.forward, (_driveTarget.position - carPosition.transform.position).normalized); _distanceToTarget = Vector3.Distance(carPosition.position, _driveTarget.position); if (_verticalDirection > 0) { if (carPosition.GetComponent().velocity.magnitude > slowingSpeed) _accelerationInput = -1; else _accelerationInput = 1; } else { if (_distanceToTarget < reverseDist) _accelerationInput = -1; else _accelerationInput = 1; } Steering(); SlowedCheck(); _car.SetInputs(_accelerationInput, _turnInput); yield return new WaitForEndOfFrame(); } ChangeState(); } /// /// to put the car in a driving state /// private IEnumerator Driving() { _car.braking = false; while (_nextState != NextState.Driving) { _verticalDirection = Vector3.Dot(carPosition.transform.forward, (_driveTarget.position - carPosition.transform.position).normalized); _distanceToTarget = Vector3.Distance(carPosition.position, _driveTarget.position); _accelerationInput = 1; Steering(); if (_distanceToTarget < slowingDistance) _nextState = NextState.Slowed; _car.SetInputs(_accelerationInput, _turnInput); yield return new WaitForEndOfFrame(); } ChangeState(); } /// /// a function to check if the car should be a slowed state /// private void SlowedCheck() { if (_distanceToTarget < stoppingDistance) _nextState = NextState.Stopped; if (_distanceToTarget > slowingDistance) _nextState = NextState.Driving; } /// /// enum of states that the car can be in /// private enum NextState { Slowed, Stopped, Driving } }