Ashby Issac c466e28d6c AI FSM changes.
- 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.
2026-01-07 19:38:03 +05:30

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);
}
}
}