- Protoyped on the AI movement, found solutions for turns and moving after impacting the player. - Created a full base for AI state machine. - Worked on binding the core AI logic with the finite state machine.
144 lines
5.9 KiB
C#
144 lines
5.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using UnityEngine;
|
|
|
|
public class PlayerCarSystem : ICarComponents
|
|
{
|
|
[Category("Global Attributes")] private Rigidbody carRigidbody;
|
|
private PlayerCarSpecs carSpecs;
|
|
|
|
[Category("Animation Curves")] private AnimationCurve steerLeftAnimCurve;
|
|
[Category("Animation Curves")] private AnimationCurve steerRightAnimCurve;
|
|
private AnimationCurve accelAnimCurve;
|
|
|
|
[Category("SuspensionForce Attributes")]
|
|
private float force;
|
|
|
|
private float springOffset;
|
|
private float velocitySpeed;
|
|
private Vector3 springDir = default;
|
|
private Vector3 pointVelocity = default;
|
|
|
|
[Category("SteeringForce Attributes")] private float accel;
|
|
private float steeringVel;
|
|
private float changeInVel;
|
|
private Vector3 tirePointVel;
|
|
|
|
[Category("AccelerationForce Attributes")]
|
|
private Vector3 accelForce;
|
|
|
|
private Transform[] frontTireTransforms;
|
|
private PlayerCarController gameplayControllerInst;
|
|
|
|
public PlayerCarSystem(PlayerCarController gameplayController, Rigidbody carRigidbody = null, PlayerCarSpecs carSpecs = null, Transform[] frontTireTransforms = null,
|
|
AnimationCurve steerLeftAnimCurve = null, AnimationCurve steerRightAnimCurve = null, AnimationCurve accelAnimCurve = null)
|
|
{
|
|
gameplayControllerInst = gameplayController;
|
|
this.carRigidbody = carRigidbody;
|
|
this.carSpecs = carSpecs;
|
|
this.frontTireTransforms = frontTireTransforms;
|
|
this.steerLeftAnimCurve = steerLeftAnimCurve;
|
|
this.steerRightAnimCurve = steerRightAnimCurve;
|
|
this.accelAnimCurve = accelAnimCurve;
|
|
|
|
gameplayControllerInst.OnApplyForce += ApplyCarForces;
|
|
gameplayControllerInst.OnCarRotate += CarRotation;
|
|
}
|
|
|
|
/* Force that makes the rigidbody float on
|
|
* the ground using the raycast-based approach */
|
|
public void SuspensionForce(float distance = 0, Transform tireTransform = null)
|
|
{
|
|
springDir = tireTransform.up;
|
|
pointVelocity = carRigidbody.GetPointVelocity(tireTransform.position);
|
|
|
|
// Debug.Log($"Suspension({tireTransform.name}): suspensionRestDist: {carSpecs.suspensionRestDist}, distance: {distance}");
|
|
springOffset = carSpecs.suspensionRestDist - distance; // 0.4
|
|
velocitySpeed = Vector3.Dot(springDir, pointVelocity);
|
|
|
|
// also dependent on the mass of the object.
|
|
force = (springOffset * carSpecs.strength) - (velocitySpeed * carSpecs.dampingForce);
|
|
|
|
// Debug.LogWarning($":: springOffset: {springOffset} :: velocitySpeed: {velocitySpeed} :: force: {force}");
|
|
|
|
carRigidbody.AddForceAtPosition(springDir * force, tireTransform.position);
|
|
}
|
|
|
|
/* Force required to avoid unnecessary slipping for the car
|
|
* Can reduce traction using gripFactor
|
|
*/
|
|
public void SteeringForce(Transform tireTransform = null)
|
|
{
|
|
tirePointVel = carRigidbody.GetPointVelocity(tireTransform.position);
|
|
steeringVel = Vector3.Dot(tirePointVel, tireTransform.right);
|
|
|
|
var clampedVelOnX = Mathf.Abs(Mathf.Clamp01(steeringVel));
|
|
var horizontalAxisVal = Input.GetAxis("Horizontal");
|
|
var gripFactor = 0f;
|
|
|
|
if (horizontalAxisVal < 0)
|
|
{
|
|
gripFactor = steerLeftAnimCurve.Evaluate(clampedVelOnX);
|
|
Debug.Log($"### Steering: horizontalAxisVal < 0 :: HorizontalAxisVal: {horizontalAxisVal}");
|
|
Debug.Log($"### Steering: horizontalAxisVal < 0 :: gripFactor: {horizontalAxisVal}");
|
|
}
|
|
else if (horizontalAxisVal > 0)
|
|
{
|
|
gripFactor = steerRightAnimCurve.Evaluate(clampedVelOnX);
|
|
Debug.Log($"### Steering: horizontalAxisVal > 0 :: gripFactor: {horizontalAxisVal}");
|
|
Debug.Log($"### Steering: horizontalAxisVal > 0 :: HorizontalAxisVal: {horizontalAxisVal}");
|
|
}
|
|
else
|
|
{
|
|
gripFactor = 0.2f; // custom for now, need to change later
|
|
}
|
|
|
|
changeInVel = -steeringVel * gripFactor;
|
|
accel = changeInVel / Time.fixedDeltaTime;
|
|
var forceToApply = accel * carSpecs.tireMass;
|
|
|
|
carRigidbody.AddForceAtPosition(tireTransform.right * forceToApply, tireTransform.position);
|
|
}
|
|
|
|
/* Forward/Backward force for the car's rigidbody */
|
|
public void AccelerationForce(float accelInput = 0, Transform tireTransform = null, Transform tireMesh = null)
|
|
{
|
|
if (accelInput != 0.0f)
|
|
{
|
|
float speed = Vector3.Dot(tireTransform.forward, carRigidbody.velocity);
|
|
float clampedSpeed = Mathf.Clamp01(speed / carSpecs.totalSpeed);
|
|
|
|
float accelSpeed = accelAnimCurve.Evaluate(clampedSpeed) * carSpecs.speedValue;
|
|
|
|
accelForce = accelSpeed * accelInput * carRigidbody.transform.forward;
|
|
carRigidbody.AddForceAtPosition(accelForce, tireTransform.position);
|
|
|
|
}
|
|
if (carRigidbody.velocity.magnitude > 0)
|
|
tireMesh.Rotate(Vector3.right, carSpecs.speedValue * 50f);
|
|
}
|
|
|
|
/* Apply force for Suspension, Steering, and Acceleration */
|
|
private void ApplyCarForces(float distance = 0, Transform tireTransform = null, float accelInput = 0, Transform tireMesh = null)
|
|
{
|
|
SuspensionForce(distance, tireTransform);
|
|
SteeringForce(tireTransform);
|
|
AccelerationForce(accelInput, tireTransform, tireMesh);
|
|
}
|
|
|
|
/* Rotate the front wheel transforms */
|
|
private void CarRotation(float steeringInput = 0)
|
|
{
|
|
float inputRotY = steeringInput * carSpecs.tireRotationAngle;
|
|
|
|
foreach (Transform frontTire in frontTireTransforms)
|
|
{
|
|
Quaternion updatedRotation = Quaternion.Euler(frontTire.localEulerAngles.x, inputRotY,
|
|
frontTire.localEulerAngles.z);
|
|
|
|
frontTire.localRotation = steeringInput == 0 ? new Quaternion(0, 0, 0, 1) : Quaternion.Slerp(frontTire.localRotation, updatedRotation,
|
|
Time.deltaTime * carSpecs.rotationSpeed);
|
|
}
|
|
}
|
|
} |