Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.InputSystem;
- //using Lofelt.NiceVibrations; //Remove this when all haptics have been moved to RumbleController
- public struct HitInfo
- {
- public bool isFrontWheel;
- public Vector3 wheelHitPoint;
- public Vector3 wheelHitNormal;
- }
- public class ArcadeVehicleController : MonoBehaviour
- {
- [SerializeField] private bool ShowDebugRays;
- Transform[] allWheelHolders = new Transform[4];
- [field: SerializeField] public LayerMask DrivableSurfaceMask { get; private set; }
- private PlayerStatus playerStatus;
- private DeliveryVFXHandler vFXHandler;
- private CarVisualsHandler carVisualsHandler;
- private RumbleController rumbleController;
- [SerializeField] private bool useWheelRotationForDrag;
- [Header("Speed")]
- public float DefaultMaxSpeed;
- public float CurrentMaxSpeed; // Initialized to DefaultMaxSpeed on start
- [SerializeField] private float MaxZVelocity; // Initialized to DefaultMaxSpeed on start
- [SerializeField] private float OffRoadMaxSpeed;
- [SerializeField] private float reverseMaxSpeed = 50f;
- [SerializeField] private float currentAcceleration = 250f;
- [SerializeField] private float defaultAcceleration;
- [SerializeField] private float brakeAcceleration;
- [SerializeField] private float reverseAcceleration;
- [SerializeField] private float forwardTurnMultiplier;
- [SerializeField] private float reverseTurnMultiplier;
- [SerializeField] private float reverseDriftTurnMultiplier;
- [Range(50, 500)]
- [SerializeField] private float dragMultiplier = 250f;
- [SerializeField] private float slipStreamMaxSpeed = 100f;
- [Header("Positioning")]
- public Vector3 StartRayOffset;
- [SerializeField] float centerGroundedDistance = 3f;
- [SerializeField] float wheelGroundedDistance = 3f;
- [SerializeField] float YOffset = 1.5f;
- [SerializeField] float maxSteepness = 55f;
- [Header("DownForces")]
- [SerializeField] private float downForceInAirAfterApex = 120f;
- [SerializeField] private float downForceInAirBeforeApex = 100f;
- [Header("Rigidbodies")]
- [SerializeField] public Rigidbody carRigidbody;
- [Header("AirControl")]
- [SerializeField] private float airAcceleration = 5f;
- [SerializeField] private float airMaxSidewaysSpeed = 50f;
- [Header("AnimationCurves")]
- [SerializeField] private AnimationCurve turnCurve;
- [SerializeField] private AnimationCurve driftInputCurve;
- [Tooltip("-0.5 is going down 45 degrees, 0.5 is going up 45 degrees")]
- [SerializeField] private AnimationCurve slopeMultiplierCurve;
- [SerializeField] private AnimationCurve driftTorqueMultiplierCurve;
- [SerializeField] private AnimationCurve driftSidewaysMultiplierCurve;
- [Header("J_Turn")]
- public float jTurnDriftThreshold = 0.5f;
- public float spinForce = 100f;
- [SerializeField] private float jturnspeed;
- [Header("Drifting")]
- [SerializeField] private float driftTurnTorque = 25f;
- [SerializeField] private float driftSidewaysForce = 350f;
- [SerializeField] private float[] driftBoostThresholds;
- [SerializeField] private float[] driftBoostSpeeds;
- [SerializeField] private float[] driftBoostAccelerations;
- [SerializeField] private float[] driftBoostDurations;
- [Header("SpeedBoosts")]
- [SerializeField] private float boostPanelSpeedIncrease;
- [SerializeField] private float boostPanelAccelerationIncrease;
- [SerializeField] private float boostDefualtAccelerationIncrease;
- [SerializeField] private float boostPanelDuration;
- [SerializeField] private float powerUpBoostSpeedIncrease;
- [SerializeField] private float powerUpBoostAccelerationIncrease;
- [SerializeField] private float powerUpBoostDuration;
- private float initialPowerUpBoostTime;
- bool bumpedWhilstDrifting;
- private float driftTimer;
- private float steeringSign;
- List<Vector3> groundhits = new List<Vector3>();
- public bool[] WheelIsGrounded = new bool[4];
- public RaycastHit[] WheelRayHits = new RaycastHit[4];
- Vector3[] wheelHitPositions = new Vector3[4];
- bool canHorn = true;
- [SerializeField] float hornDelay = 1.5f;
- [HideInInspector]
- public Vector3 carRelativeVelocity;
- [Header("SpeedBoost")]
- private bool isBoosting;
- CarAudioHandler carAudioHandler;
- [SerializeField] Transform carBodyHolder;
- public float CurrentSpeed { get; private set; }
- public float SteerInput { get; private set; }
- public float AccelerationInput { get; private set; }
- public float BrakeInput { get; private set; }
- public bool HandBrakeInput { get; private set; }
- public bool LockedIntoDrift { get; private set; }
- public float DriftSteerInput { get; private set; }
- public bool IsGrounded { get; private set; }
- public int CurrentBoostLevel; // Indicates current boost level, if any
- public bool IsEmmittingTrail { get; set; }
- public bool IsStunned { get; private set; }
- public int PlayerID { get; private set; }
- public bool isSlipstreamed;
- public float slipStreamTimer;
- private void Start()
- {
- // Initialize references to various components
- vFXHandler = GetComponentInChildren<DeliveryVFXHandler>();
- carAudioHandler = GetComponentInChildren<CarAudioHandler>();
- carVisualsHandler = GetComponentInChildren<CarVisualsHandler>();
- rumbleController = GetComponent<RumbleController>();
- // Assign specific references needed for functionality
- carBodyHolder = carVisualsHandler.transform;
- allWheelHolders = carVisualsHandler.AllWheelHolders;
- playerStatus = GetComponent<PlayerStatus>();
- }
- public void OnSteerInput(InputAction.CallbackContext context)
- {
- // Read and assign steer input if controls are enabled
- if (InputManager.instance.controlsEnabled)
- {
- SteerInput = context.ReadValue<float>();
- }
- }
- public void OnAccelerateButton(InputAction.CallbackContext context)
- {
- // Read and assign accelerate input if controls are enabled; otherwise set to 0
- AccelerationInput = InputManager.instance.controlsEnabled ? context.ReadValue<float>() : 0;
- }
- public void OnBrakeInput(InputAction.CallbackContext context)
- {
- // Read and assign brake input if controls are enabled; otherwise set to 0
- BrakeInput = InputManager.instance.controlsEnabled ? context.ReadValue<float>() : 0;
- }
- public void OnHandBrakeButton(InputAction.CallbackContext context)
- {
- // Activate handbrake input and trigger visuals if controls are enabled
- if (InputManager.instance.controlsEnabled)
- {
- HandBrakeInput = context.action.WasPressedThisFrame();
- carVisualsHandler.BodyScaleSpring(new Vector3(3f, 0.8f, 3f));
- }
- }
- public void OnHornButton(InputAction.CallbackContext context)
- {
- // Trigger horn sound and delay functionality if controls are enabled and horn can be used
- if (context.action.WasPressedThisFrame() && canHorn)
- {
- canHorn = false;
- carAudioHandler.PlayHornSound();
- StartCoroutine(HornDelay());
- }
- }
- RaycastHit centreHit;
- float driftTorqueMulitplier = 0.5f;
- float driftSidewaysForceMultiplier = 1.5f; // Start at 1.5 of itself
- private void Update()
- {
- timeSinceLastCollision += Time.deltaTime;
- CurrentSpeed = carRelativeVelocity.z;
- DriftInputHandling();
- }
- void FixedUpdate()
- {
- // Perform ground checks
- GroundCheck();
- GroundCheckWheels();
- // Rotate car to align with surface normal
- RotateToSurface();
- // Calculate relative velocity in local space
- carRelativeVelocity = carRigidbody.transform.InverseTransformDirection(carRigidbody.velocity);
- // Handle grounded state
- if (IsGrounded)
- {
- // Reset y velocity if grounded
- carRigidbody.velocity = transform.TransformDirection(new Vector3(carRelativeVelocity.x, 0, carRelativeVelocity.z));
- }
- else
- {
- // Adjust physics settings for air control
- carRigidbody.drag = 0.2f;
- carRigidbody.MoveRotation(Quaternion.Slerp(carRigidbody.rotation, Quaternion.FromToRotation(carRigidbody.transform.up, Vector3.up) * carRigidbody.transform.rotation, 0.05f));
- carRigidbody.velocity = Vector3.Lerp(carRigidbody.velocity, transform.forward * carRelativeVelocity.z, airAcceleration * Time.deltaTime);
- // Apply downward force based on current y velocity
- carRigidbody.AddForce(Vector3.down * (carRigidbody.velocity.y < 5 ? downForceInAirAfterApex : downForceInAirBeforeApex));
- }
- // Return if stunned
- if (IsStunned)
- {
- return;
- }
- // Air control when not grounded and return
- if (!IsGrounded)
- {
- AirControl();
- return;
- }
- // Reset drag when grounded
- carRigidbody.drag = 1f;
- // Handle Slipstream effect
- if (isSlipstreamed)
- {
- vFXHandler.PlaySpeedLines();
- CurrentMaxSpeed = slipStreamMaxSpeed;
- slipStreamTimer -= Time.deltaTime;
- if (slipStreamTimer <= 0)
- {
- vFXHandler.StopSpeedLines();
- CurrentMaxSpeed = DefaultMaxSpeed;
- isSlipstreamed = false;
- }
- }
- // Ensure CurrentMaxSpeed does not drop below DefaultMaxSpeed
- if (CurrentMaxSpeed < DefaultMaxSpeed)
- {
- CurrentMaxSpeed = DefaultMaxSpeed;
- }
- // Reset velocity if below minimum threshold
- if (carRigidbody.velocity.magnitude < 2.5f)
- {
- carRigidbody.velocity = Vector3.zero;
- }
- // Apply driving logic and limit maximum forward speed
- DrivingLogic();
- LimitMaxForwardSpeed();
- }
- private void DrivingLogic()
- {
- UpdateMaxSpeed();
- TurningLogic();
- ForwardBackwardLogic();
- }
- private void ForwardBackwardLogic()
- {
- // print(carRelativeVelocity.z);
- if (Mathf.Abs(AccelerationInput) > 0.1f || isBoosting)
- {
- // If is boosting from drift, set speed strait to 1, else allow the player to feather the joystick to get and accel input between 0 and 1
- float _speed = (isBoosting) ? 1 : AccelerationInput;
- // Multiply speed by current max speed
- _speed *= CurrentMaxSpeed;
- // Multiply speed depending on the steepness of the slope the car is on
- _speed *= SlopeMultiplier();
- // Calculate the time it takes to reach the target speed
- float timeToMaxSpeed = _speed / currentAcceleration;
- // Calculate the fraction of time that has passed towards reaching the target speed
- // Clamp so t is always between 0 and 1.
- float t = Mathf.Clamp01(Time.deltaTime / timeToMaxSpeed);
- // Interpolate the current velocity towards the target velocity using Lerp with t as time between
- carRigidbody.velocity = Vector3.Lerp(carRigidbody.velocity, transform.forward * _speed, t);
- }
- //reverse logic
- if (Mathf.Abs(BrakeInput) > 0.1f)
- {
- if (!LockedIntoDrift)
- {
- float _speed = BrakeInput;
- // Multiply speed by reverse max speed
- _speed *= reverseMaxSpeed;
- float timeToMaxSpeed = carRelativeVelocity.z > 0 ? reverseMaxSpeed / brakeAcceleration : reverseMaxSpeed / reverseAcceleration;
- float t = Mathf.Clamp01(Time.deltaTime / timeToMaxSpeed);
- carRigidbody.velocity = Vector3.Lerp(carRigidbody.velocity, -transform.forward * _speed, t);
- }
- }
- //friction simulation (velocity dampening)
- Vector3 carVelocityXZ = new Vector3(carRigidbody.velocity.x, 0, carRigidbody.velocity.z).normalized;
- Vector3 carRightXZ = new Vector3(transform.right.x, 0, transform.right.z).normalized;
- float dot = Vector3.Dot(carVelocityXZ, carRightXZ);
- carRigidbody.AddForce(transform.right * -dot * dragMultiplier);
- }
- private void TurningLogic()
- {
- float _turnCurveMultiplier = turnCurve.Evaluate(Mathf.Abs(carRelativeVelocity.z / CurrentMaxSpeed)); // divide by CurrentMaxSpeed so it goes between 0 and 1
- //_turnCurveMultiplier *= Mathf.Abs(carRelativeVelocity.z);
- _turnCurveMultiplier *= 100f;
- //if driving forwards
- if (carRelativeVelocity.z > 2.5f)
- {
- //if drifting
- if (LockedIntoDrift)
- {
- // Add torque based on the DriftSteerInput and the driftTurnMultiplier
- carRigidbody.AddTorque(Vector3.up * DriftSteerInput * driftTurnTorque * driftTorqueMulitplier * _turnCurveMultiplier);
- // Add sideways force against the player to make them slide out whilst drifting
- carRigidbody.AddForce(transform.right * -steeringSign * driftSidewaysForce * driftSidewaysForceMultiplier * carRelativeVelocity.z, ForceMode.Acceleration);
- }
- else
- {
- carRigidbody.AddTorque(Vector3.up * SteerInput * forwardTurnMultiplier * _turnCurveMultiplier);
- }
- }
- //driving backwards
- else if(carRelativeVelocity.z < -2.5f)
- {
- // Check if the player initiated the J-turn
- if (LockedIntoDrift)
- {
- // Reverse the car's movement
- float _speed = BrakeInput * reverseMaxSpeed;
- // Multiply speed by reverse max speed
- float timeToMaxSpeed = reverseMaxSpeed / reverseAcceleration;
- float t = Mathf.Clamp01(Time.deltaTime / timeToMaxSpeed);
- // Apply steering input
- carRigidbody.AddTorque(Vector3.up * -1 * SteerInput * reverseTurnMultiplier * _turnCurveMultiplier);
- // Check if the car is drifting
- if (carRigidbody.angularVelocity.magnitude > jTurnDriftThreshold)
- {
- //isDriftingReverse = true;
- _speed = BrakeInput * jturnspeed;
- carRigidbody.AddTorque(Vector3.up * -1 * spinForce * 100f * SteerInput);
- }
- carRigidbody.velocity = Vector3.Lerp(carRigidbody.velocity, -transform.forward * _speed, t);
- }
- else
- {
- carRigidbody.AddTorque(Vector3.up * -1 * SteerInput * reverseTurnMultiplier * _turnCurveMultiplier);
- }
- }
- }
- private void DriftInputHandling()
- {
- //If holding drift input and turning and hasn't been bumped whilst drifting
- if (HandBrakeInput && Mathf.Abs(SteerInput) > 0.1f && !bumpedWhilstDrifting && IsGrounded)
- {
- //If not locked into drift, locked into drift is true so this is called once
- if (!LockedIntoDrift)
- {
- LockedIntoDrift = true;
- //steering directional sign is locked and can't be changed until the player starts a new drift
- steeringSign = Mathf.Sign(SteerInput);
- rumbleController.PlayRumble(0.5f, 1f, 0.5f);
- }
- }
- if (LockedIntoDrift)
- {
- driftSidewaysForceMultiplier = driftSidewaysMultiplierCurve.Evaluate(driftTimer);
- driftTorqueMulitplier = driftTorqueMultiplierCurve.Evaluate(driftTimer);
- //increase drift timer (used for speed boosts) if grounded
- if (IsGrounded && (AccelerationInput > 0.1f || BrakeInput > 0.1f))
- {
- //Increase drift timer
- IncreaseDriftTimer();
- }
- //evaluate the drift curve
- //-1 steer input corresponds to 0.5 on the curve so if the player is drifting right but holding left, the driftSteeringInput will be 0.5 not -1
- //1 steer input corresponds to 1.5, on the curve so if the player is drifting right and holding right, the driftSteeringInput will be 1.5 not 1
- //evaluating the curve with the steer input multiplied by the sign will invert these results
- DriftSteerInput = driftInputCurve.Evaluate(SteerInput * steeringSign);
- //multiplying the results by the steering sign will make the car drift
- DriftSteerInput *= steeringSign;
- }
- //If player is not holding drift button
- if (!HandBrakeInput)
- {
- if (LockedIntoDrift)
- {
- DriftComplete();
- }
- driftTimer = 0f;
- steeringSign = 0f;
- DriftSteerInput = 0f;
- LockedIntoDrift = false;
- bumpedWhilstDrifting = false;
- }
- }
- private void GroundCheck()
- {
- //the start of the ray will be above the car to prevent going through the floor, since were apllying a down force
- //ray shoots worldspace down, if it hits, the cars position will be offset in world space up
- Vector3 rayStartPosition = transform.position + StartRayOffset;
- Vector3 rayDirection = -Vector3.up;
- float rayDistance = centerGroundedDistance + StartRayOffset.y;
- Debug.DrawRay(rayStartPosition, rayDirection * rayDistance, Color.red);
- if (Physics.Raycast(rayStartPosition, rayDirection, out centreHit, rayDistance, DrivableSurfaceMask))
- {
- if (Vector3.Angle(centreHit.normal, Vector3.up) < maxSteepness)
- {
- // Get the layer of the hit object
- //IsOffRoading = centreHit.collider.CompareTag("OffRoad");
- IsGrounded = true;
- return;
- }
- }
- IsGrounded = false;
- }
- void GroundCheckWheels()
- {
- //each wheel cast a ray locally down from it's centre (or higher)
- //if the ray hits a surface the wheel will be driving on that point
- //an invisible plane will be made with all the points
- //the car will be rotated to the normal of that plane (if 4 wheels are grounded?)
- groundhits.Clear();
- for (int i = 0; i < 4; i++)
- {
- Vector3 startPos = allWheelHolders[i].position + transform.up * StartRayOffset.y;
- Vector3 rayDirection = -transform.up; // shoot ray down from car locally
- float rayDistance = wheelGroundedDistance + StartRayOffset.y;
- //Debug.DrawRay(startPos, rayDirection * rayDistance, Color.blue);
- if (Physics.Raycast(startPos, rayDirection, out WheelRayHits[i], rayDistance, DrivableSurfaceMask))
- {
- if (Vector3.Angle(WheelRayHits[i].normal, Vector3.up) < maxSteepness)
- {
- groundhits.Add(WheelRayHits[i].point);
- WheelIsGrounded[i] = true;
- }
- else
- {
- WheelIsGrounded[i] = false;
- }
- }
- else
- {
- WheelIsGrounded[i] = false;
- }
- }
- }
- Vector3 normalFromPlaneUnderWheels;
- // Adjusts the car's orientation to match the surface beneath the wheels
- private void RotateToSurface()
- {
- // Store hit points below each grounded wheel or local point down from the wheel if not grounded
- for (int i = 0; i < 4; i++)
- {
- if (WheelIsGrounded[i])
- {
- wheelHitPositions[i] = WheelRayHits[i].point; // Store hit point below the grounded wheel
- }
- else
- {
- wheelHitPositions[i] = allWheelHolders[i].position + (transform.up * -wheelGroundedDistance); // Use local point down from the wheel if not grounded
- }
- }
- // Create a plane using points locally down from the wheels
- Vector3 a = wheelHitPositions[0];
- Vector3 b = wheelHitPositions[1];
- Vector3 c = wheelHitPositions[2];
- Vector3 d = wheelHitPositions[3];
- Vector3 x = c - a + d - b;
- Vector3 y = c - d + a - b;
- // Calculate the normal vector from the plane
- normalFromPlaneUnderWheels = Vector3.Cross(x, y);
- // Rotate the car to match the calculated surface normal
- carRigidbody.MoveRotation(Quaternion.Slerp(transform.rotation, Quaternion.FromToRotation(transform.up, normalFromPlaneUnderWheels) * transform.rotation, rotateToSurfaceSpeed));
- // Set the car's position to the ray cast hit below + an offset if grounded
- if (IsGrounded)
- {
- transform.position = new Vector3(transform.position.x, centreHit.point.y + YOffset, transform.position.z);
- }
- }
- float rotateToSurfaceSpeed = 0.2f; // used to be 0.8 but 0.2 is ssooooooo much smoother
- private void AirControl()
- {
- // Reset the car's rotation from it's local up vector to the world's up vector
- // Soesn't need to slerp by a time delta time value because it is in fixed update
- float sidewayVelocity = carRelativeVelocity.x + SteerInput * airAcceleration;
- carRelativeVelocity.x = Mathf.Clamp(sidewayVelocity, -airMaxSidewaysSpeed, airMaxSidewaysSpeed);
- carRigidbody.velocity = transform.TransformDirection(carRelativeVelocity);
- }
- private float SlopeMultiplier()
- {
- // Calculate the y-component product of the transform's up and forward vectors
- // Backforce depending on slopes (cars transform up is rotated to) and which way the car is facing
- // If the car is on a 45 degree slope and driving up, this number will be 0.5
- // If it's driving down it will be -0.5
- // If its driving parallel, it'll be 0
- float _yProduct = transform.up.y * transform.forward.y;
- return slopeMultiplierCurve.Evaluate(_yProduct);
- }
- private void IncreaseDriftTimer()
- {
- driftTimer += Time.deltaTime;
- // Iterate through the timesForDifferentDriftBoosts array to find the maximum BoostLevel
- for (int i = 0; i < driftBoostThresholds.Length; i++)
- {
- // If the driftTimer is greater than the current boost threshold's time, update BoostLevel
- if (driftTimer > driftBoostThresholds[i])
- {
- CurrentBoostLevel = i + 1; // BoostLevel is one more than the current index, since arrays are zero-indexed
- //GamepadRumbler.SetCurrentGamepad(PlayerID);
- //HapticPatterns.PlayConstant(CurrentBoostLevel * 0.1f, 0.75f, 1.3f);
- rumbleController.PlayRumble((CurrentBoostLevel + 1) * 0.1f, (-1 + 2 * CurrentBoostLevel), 1.3f); //Change this so one shot is played every certain number of frames instead
- }
- }
- }
- private void DriftComplete()
- {
- if (CurrentBoostLevel > 0)
- {
- float speed_increase = driftBoostSpeeds[CurrentBoostLevel - 1];
- float accel_increase = boostDefualtAccelerationIncrease;
- float duration = driftBoostDurations[CurrentBoostLevel - 1];
- driftType = CurrentBoostLevel-1;
- initialDriftTime = Time.time;
- }
- // Reset values
- driftTimer = 0;
- CurrentBoostLevel = 0;
- /*
- HapticController.Loop(false);
- HapticController.clipLevel = 0.25f;
- HapticController.clipFrequencyShift = 0.0f;
- HapticController.Stop();
- */
- }
- private void DriftCancel()
- {
- //reset values
- bumpedWhilstDrifting = true;
- LockedIntoDrift = false;
- driftTimer = 0;
- CurrentBoostLevel = 0;
- }
- public void BoostPanelEnter()
- {
- initialBoostPanelTime = Time.time;
- }
- // Method to update the current and maximum speed of the car based on various conditions
- private void UpdateMaxSpeed()
- {
- // Reset to default values
- currentAcceleration = defaultAcceleration;
- CurrentMaxSpeed = DefaultMaxSpeed;
- // Check for slipstream effect
- if (isSlipstreamed)
- {
- vFXHandler.PlaySpeedLines(); // Play speed lines visual effect
- CurrentMaxSpeed = slipStreamMaxSpeed; // Set maximum speed to slipstream maximum
- slipStreamTimer -= Time.deltaTime;
- // Disable slipstream effect if timer expires
- if (slipStreamTimer <= 0)
- {
- if (!isBoosting) // Check if no other boost is active
- {
- vFXHandler.StopSpeedLines(); // Stop speed lines visual effect
- }
- CurrentMaxSpeed = DefaultMaxSpeed; // Reset maximum speed to default
- isSlipstreamed = false; // Disable slipstream flag
- }
- }
- bool checkBoosting = false; // Flag to check if any boost is active
- // Check for boosts from boost panels
- if (initialBoostPanelTime + boostPanelDuration > Time.time)
- {
- currentAcceleration += boostPanelAccelerationIncrease;
- CurrentMaxSpeed += boostPanelSpeedIncrease;
- checkBoosting = true;
- }
- // Check for boosts from power-up items
- if (initialPowerUpBoostTime + powerUpBoostDuration > Time.time)
- {
- currentAcceleration += powerUpBoostAccelerationIncrease;
- CurrentMaxSpeed += powerUpBoostSpeedIncrease;
- checkBoosting = true;
- }
- // Check for boosts from drifting (based on drift type)
- if (driftType >= 0 && driftType <= 3)
- {
- if (initialDriftTime + driftBoostDurations[driftType] > Time.time)
- {
- currentAcceleration += driftBoostAccelerations[driftType];
- CurrentMaxSpeed += driftBoostSpeeds[driftType];
- checkBoosting = true;
- }
- }
- // Disable speed boost visuals if no boost is active
- if (!checkBoosting && isBoosting)
- {
- SpeedBoostVisualDisable();
- }
- // Enable speed boost visuals if any boost is active
- else if (checkBoosting && !isBoosting)
- {
- SpeedBoostVisualEnable();
- }
- }
- // Method to initialize the power-up boost, recording the start time
- public void BoostPowerUpFunction()
- {
- initialPowerUpBoostTime = Time.time;
- }
- // Coroutine to handle the speed boost power-up, increasing speed and acceleration for a duration
- IEnumerator SpeedBoost(float speedIncreaseAmount, float accelIncreaseAmount, float boostDuration)
- {
- currentBoosts++; // Increment the current number of boosts
- CurrentMaxSpeed += speedIncreaseAmount; // Increase maximum speed
- currentAcceleration += accelIncreaseAmount; // Increase acceleration
- SpeedBoostVisualEnable(); // Enable speed boost visuals
- yield return new WaitForSeconds(boostDuration); // Wait for the boost duration
- currentBoosts--; // Decrement the current number of boosts
- currentAcceleration -= accelIncreaseAmount; // Revert acceleration increase
- CurrentMaxSpeed -= speedIncreaseAmount; // Revert speed increase
- // If no more active boosts, disable boost visuals
- if (currentBoosts == 0)
- {
- SpeedBoostVisualDisable();
- }
- }
- // Method to enable visual effects for speed boost
- private void SpeedBoostVisualEnable()
- {
- isBoosting = true;
- GetComponentInChildren<CameraManager>().IncreaseFieldOfView(); // Increase camera field of view
- vFXHandler.PlaySpeedLines(); // Play speed lines effect
- vFXHandler.PlayBoostExhaustFlame(); // Play boost exhaust flame effect
- carVisualsHandler.BodyScaleSpring(new Vector3(5.0f, 0.5f, 5.0f)); // Apply visual scaling effect to car body
- }
- // Method to disable visual effects for speed boost
- private void SpeedBoostVisualDisable()
- {
- isBoosting = false;
- vFXHandler.StopSpeedLines(); // Stop speed lines effect
- vFXHandler.StopBoostExhaustFlame(); // Stop boost exhaust flame effect
- }
- // Public method to initiate the stunned action coroutine
- public void StunnedActionFunction(bool spin, Vector3 stunDirection, float duration)
- {
- StartCoroutine(StunnedAction(spin, stunDirection, duration));
- }
- // Coroutine to handle the stunned action, including spinning and duration
- IEnumerator StunnedAction(bool spin, Vector3 stunDirection, float duration)
- {
- if (!playerStatus.Invincible)
- {
- // Reduce the car's velocity by half
- carRigidbody.velocity = carRigidbody.velocity / 2;
- IsStunned = true;
- // Play rumble effect to indicate the stun
- rumbleController.PlayOneShot(0.5f, 0.5f);
- // If spin is true, apply stun force and rotate the car
- if (spin)
- {
- carRigidbody.AddForce(stunDirection * stunForce, ForceMode.Impulse);
- float numberOfRotations = 3;
- float elapsedTime = 0.0f;
- carVisualsHandler.BodyScaleSpring(new Vector3(8, 0.1f, 8));
- vFXHandler.PlayStunEffect();
- // Rotate the car over the duration of the stun
- while (elapsedTime < duration)
- {
- elapsedTime += Time.deltaTime;
- float angle = Mathf.Lerp(0.0f, 360.0f * numberOfRotations, elapsedTime / duration);
- carBodyHolder.localRotation = Quaternion.Euler(transform.GetChild(0).rotation.x, angle, transform.GetChild(0).rotation.z);
- yield return null;
- }
- carBodyHolder.localRotation = Quaternion.Euler(transform.GetChild(0).rotation.x, 0, transform.GetChild(0).rotation.z);
- }
- // If not spinning, simply wait for the duration
- else
- {
- yield return new WaitForSeconds(duration);
- }
- IsStunned = false;
- }
- }
- // Public method to initiate the slow to stop coroutine
- public void SlowToStopFunction()
- {
- StartCoroutine(SlowToStop());
- }
- // Coroutine to gradually slow the car to a complete stop
- IEnumerator SlowToStop()
- {
- // Disable speed boost visuals and cancel drift
- SpeedBoostVisualDisable();
- DriftCancel();
- playerStatus.IsStopping = true;
- Vector3 startVelocity = carRigidbody.velocity;
- Vector3 targetVelocity = carRigidbody.velocity * 0f;
- float elapsedTime = 0.0f;
- float slowDownDuration = 1.5f;
- // Gradually reduce the car's velocity to zero
- while (elapsedTime < slowDownDuration)
- {
- elapsedTime += Time.deltaTime;
- carRigidbody.velocity = Vector3.Lerp(startVelocity, targetVelocity, elapsedTime / slowDownDuration);
- yield return null;
- }
- // Ensure the car's velocity is exactly zero
- carRigidbody.velocity = Vector3.zero;
- playerStatus.IsStopping = false;
- }
- // Method to handle behavior when the car stays in a trigger
- private void OnTriggerStay(Collider other)
- {
- // Check if the car is in the slipstream of another vehicle
- if (other.CompareTag("SlipStreamTrigger") && other.transform.root.GetComponent<ArcadeVehicleController>().IsEmmittingTrail == true)
- {
- isSlipstreamed = true;
- slipStreamTimer = 1f;
- }
- }
- // Method to limit the car's maximum forward speed
- void LimitMaxForwardSpeed()
- {
- if (carRelativeVelocity.z > MaxZVelocity)
- {
- carRigidbody.velocity = transform.TransformDirection(new Vector3(carRelativeVelocity.x, carRelativeVelocity.y, MaxZVelocity));
- }
- }
- float initialBoostPanelTime;
- int driftType = 0;
- float initialDriftTime = 0;
- int currentBoosts = 0;
- [SerializeField] float stunForce = 50f;
- [SerializeField] float UTurnDuration = 0.8f;
- [SerializeField] float UTurnTargetSpeed = 15f;
- [SerializeField] float backForceFromSpringyObstacle = 75f;
- [SerializeField] float timeSinceLastCollision = 0f;
- [SerializeField] float minCarSpeed = 20f;
- private void OnCollisionEnter(Collision collision)
- {
- Transform collisionTransform = collision.transform;
- // Play the appropriate collision audio based on the collision object
- PlayCollisionAudio(collisionTransform);
- // Determine if drift and boost should be cancelled based on collision
- bool shouldCancelDrift = false;
- bool shouldCancelBoost = false;
- // Check if the collision object is an obstacle and if it's a springy obstacle
- if (collisionTransform.TryGetComponent<ObstacleManager>(out ObstacleManager obstacle))
- {
- if (obstacle.type == ObstacleManager.ObjectType.springy)
- {
- HitSpringyObstacle(collision);
- }
- }
- // Cancel drift if applicable
- if (shouldCancelDrift)
- {
- DriftCancel();
- }
- // Disable speed boost visual if applicable
- if (shouldCancelBoost)
- {
- SpeedBoostVisualDisable();
- }
- }
- private void PlayCollisionAudio(Transform collisionTransform)
- {
- // Return early if the time since the last collision is less than 1 second
- // or if the car's relative velocity is below the minimum speed threshold
- if (timeSinceLastCollision < 1f || carRelativeVelocity.z < minCarSpeed)
- {
- return;
- }
- // Check the type of object collided with and play the appropriate sound
- if (collisionTransform.CompareTag("PedestrianCar"))
- {
- carAudioHandler.PlayPedestrianCarSound();
- }
- else if (collisionTransform.root.CompareTag("Player"))
- {
- carAudioHandler.PlayOtherPlayerCarSound();
- }
- else
- {
- carAudioHandler.PlayDefaultCrashSound();
- }
- // Reset the timer for collision
- timeSinceLastCollision = 0f;
- }
- private void HitSpringyObstacle(Collision collision)
- {
- // Initiate the stunned action coroutine
- StartCoroutine(StunnedAction(false, Vector3.zero, 0.2f));
- // Get the car's velocity, ignoring the y-axis, and normalize it
- Vector3 carVelocity = new Vector3(carRigidbody.velocity.x, 0, carRigidbody.velocity.z).normalized;
- // Calculate the reflected vector based on the car's velocity and the collision normal
- Vector3 newDir = Vector3.Reflect(carVelocity, collision.GetContact(0).normal);
- // Calculate the angle between the car's forward direction and the negative collision normal
- float angle = Mathf.Deg2Rad * Vector3.Angle(transform.forward, -collision.GetContact(0).normal);
- // Compute the cosine of the angle and take its absolute value
- // This will be 1 if the car hits the obstacle head-on, and 0 if it hits from the side
- float x = Mathf.Abs(Mathf.Cos(angle));
- // Optional debug visualizations for car velocity, reflected direction, and collision normal
- // Debug.DrawRay(transform.position, carVelocity, Color.blue, 7);
- // Debug.DrawRay(collision.contacts[0].point, newDir, Color.red, 7);
- // Debug.DrawRay(collision.contacts[0].point, collision.contacts[0].normal, Color.green, 7);
- // Reset the car's velocity to zero
- carRigidbody.velocity = Vector3.zero;
- // Apply a force to the car in the direction of the reflected vector,
- // scaled by the collision's relative velocity and a back force multiplier
- carRigidbody.AddForce(x * newDir * (collision.relativeVelocity.magnitude * backForceFromSpringyObstacle));
- }
- private IEnumerator HornDelay()
- {
- yield return new WaitForSeconds(hornDelay);
- canHorn = true;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement