288 lines
10 KiB
C#
288 lines
10 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace ArcadeVP
|
|
{
|
|
public class ArcadeVehicleController : MonoBehaviour
|
|
{
|
|
public enum GroundCheckType { RayCast, SphereCast };
|
|
public enum MovementMode { Velocity, AngularVelocity };
|
|
|
|
public MovementMode movementMode;
|
|
|
|
[FormerlySerializedAs("GroundCheck")]
|
|
public GroundCheckType groundCheck;
|
|
|
|
public LayerMask drivableSurface;
|
|
|
|
[FormerlySerializedAs("MaxSpeed")]
|
|
public float maxSpeed;
|
|
|
|
[FormerlySerializedAs("accelaration")]
|
|
public float acceleration;
|
|
|
|
public float turn;
|
|
public float gravity = 7f;
|
|
public float downforce = 5f;
|
|
|
|
[FormerlySerializedAs("AirControl")]
|
|
[Tooltip("if true : can turn vehicle in air")]
|
|
public bool airControl = false;
|
|
|
|
[Tooltip("if true : vehicle will drift instead of brake while holding space")]
|
|
public bool kartLike = false;
|
|
|
|
[Tooltip("turn more while drifting (while holding space) only if kart Like is true")]
|
|
public float driftMultiplier = 1.5f;
|
|
|
|
public Rigidbody rb;
|
|
public Rigidbody carBody;
|
|
|
|
[HideInInspector]
|
|
public RaycastHit hit;
|
|
|
|
public AnimationCurve frictionCurve;
|
|
public AnimationCurve turnCurve;
|
|
public PhysicsMaterial frictionMaterial;
|
|
|
|
[Header("Visuals")]
|
|
[FormerlySerializedAs("BodyMesh")]
|
|
public Transform bodyMesh;
|
|
|
|
[FormerlySerializedAs("FrontWheels")]
|
|
public Transform[] frontWheels = new Transform[2];
|
|
|
|
[FormerlySerializedAs("RearWheels")]
|
|
public Transform[] rearWheels = new Transform[2];
|
|
|
|
[HideInInspector]
|
|
public Vector3 carVelocity;
|
|
|
|
[Range(0, 10)]
|
|
[FormerlySerializedAs("BodyTilt")]
|
|
public float bodyTilt;
|
|
|
|
[Header("Audio settings")]
|
|
public AudioSource engineSound;
|
|
|
|
[Range(0, 1)]
|
|
public float minPitch;
|
|
|
|
[Range(1, 3)]
|
|
[FormerlySerializedAs("MaxPitch")]
|
|
public float maxPitch;
|
|
|
|
[FormerlySerializedAs("SkidSound")]
|
|
public AudioSource skidSound;
|
|
|
|
[HideInInspector]
|
|
public float skidWidth;
|
|
|
|
private float radius, steeringInput, accelerationInput, brakeInput;
|
|
private Vector3 origin;
|
|
private bool isGrounded;
|
|
|
|
private void Start()
|
|
{
|
|
radius = rb.GetComponent<SphereCollider>().radius;
|
|
if (movementMode == MovementMode.AngularVelocity)
|
|
{
|
|
Physics.defaultMaxAngularSpeed = 100;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
Visuals();
|
|
AudioManager();
|
|
}
|
|
|
|
public void ProvideInputs(float _steeringInput, float _accelerationInput, float _brakeInput)
|
|
{
|
|
steeringInput = _steeringInput;
|
|
accelerationInput = _accelerationInput;
|
|
brakeInput = _brakeInput;
|
|
}
|
|
|
|
public void AudioManager()
|
|
{
|
|
engineSound.pitch = Mathf.Lerp(minPitch, maxPitch, Mathf.Abs(carVelocity.z) / maxSpeed);
|
|
if (Mathf.Abs(carVelocity.x) > 10 && grounded())
|
|
{
|
|
skidSound.mute = false;
|
|
}
|
|
else
|
|
{
|
|
skidSound.mute = true;
|
|
}
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
UpdateGroundedState();
|
|
|
|
carVelocity = carBody.transform.InverseTransformDirection(carBody.linearVelocity);
|
|
|
|
if (Mathf.Abs(carVelocity.x) > 0)
|
|
{
|
|
frictionMaterial.dynamicFriction = frictionCurve.Evaluate(Mathf.Abs(carVelocity.x / 100));
|
|
}
|
|
|
|
if (grounded())
|
|
{
|
|
float sign = Mathf.Sign(carVelocity.z);
|
|
float TurnMultiplyer = turnCurve.Evaluate(carVelocity.magnitude / maxSpeed);
|
|
if (kartLike && brakeInput > 0.1f)
|
|
{
|
|
TurnMultiplyer *= driftMultiplier;
|
|
}
|
|
|
|
if (accelerationInput > 0.1f || carVelocity.z > 1)
|
|
{
|
|
carBody.AddTorque(Vector3.up * steeringInput * sign * turn * 100 * TurnMultiplyer);
|
|
}
|
|
else if (accelerationInput < -0.1f || carVelocity.z < -1)
|
|
{
|
|
carBody.AddTorque(Vector3.up * steeringInput * sign * turn * 100 * TurnMultiplyer);
|
|
}
|
|
|
|
if (!kartLike)
|
|
{
|
|
if (brakeInput > 0.1f)
|
|
{
|
|
rb.constraints = RigidbodyConstraints.FreezeRotationX;
|
|
}
|
|
else
|
|
{
|
|
rb.constraints = RigidbodyConstraints.None;
|
|
}
|
|
}
|
|
|
|
if (movementMode == MovementMode.AngularVelocity)
|
|
{
|
|
if (Mathf.Abs(accelerationInput) > 0.1f && brakeInput < 0.1f && !kartLike)
|
|
{
|
|
rb.angularVelocity = Vector3.Lerp(rb.angularVelocity, carBody.transform.right * accelerationInput * maxSpeed / radius, acceleration * Time.deltaTime);
|
|
}
|
|
else if (Mathf.Abs(accelerationInput) > 0.1f && kartLike)
|
|
{
|
|
rb.angularVelocity = Vector3.Lerp(rb.angularVelocity, carBody.transform.right * accelerationInput * maxSpeed / radius, acceleration * Time.deltaTime);
|
|
}
|
|
}
|
|
else if (movementMode == MovementMode.Velocity)
|
|
{
|
|
if (Mathf.Abs(accelerationInput) > 0.1f && brakeInput < 0.1f && !kartLike)
|
|
{
|
|
rb.linearVelocity = Vector3.Lerp(rb.linearVelocity, carBody.transform.forward * accelerationInput * maxSpeed, acceleration / 10 * Time.deltaTime);
|
|
}
|
|
else if (Mathf.Abs(accelerationInput) > 0.1f && kartLike)
|
|
{
|
|
rb.linearVelocity = Vector3.Lerp(rb.linearVelocity, carBody.transform.forward * accelerationInput * maxSpeed, acceleration / 10 * Time.deltaTime);
|
|
}
|
|
}
|
|
|
|
rb.AddForce(-transform.up * downforce * rb.mass);
|
|
|
|
carBody.MoveRotation(Quaternion.Slerp(carBody.rotation, Quaternion.FromToRotation(carBody.transform.up, hit.normal) * carBody.transform.rotation, 0.12f));
|
|
}
|
|
else
|
|
{
|
|
if (airControl)
|
|
{
|
|
float TurnMultiplyer = turnCurve.Evaluate(carVelocity.magnitude / maxSpeed);
|
|
carBody.AddTorque(Vector3.up * steeringInput * turn * 100 * TurnMultiplyer);
|
|
}
|
|
|
|
carBody.MoveRotation(Quaternion.Slerp(carBody.rotation, Quaternion.FromToRotation(carBody.transform.up, Vector3.up) * carBody.transform.rotation, 0.02f));
|
|
rb.linearVelocity = Vector3.Lerp(rb.linearVelocity, rb.linearVelocity + Vector3.down * gravity, Time.deltaTime * gravity);
|
|
}
|
|
}
|
|
|
|
public void Visuals()
|
|
{
|
|
foreach (Transform FW in frontWheels)
|
|
{
|
|
FW.localRotation = Quaternion.Slerp(FW.localRotation, Quaternion.Euler(FW.localRotation.eulerAngles.x,
|
|
30 * steeringInput, FW.localRotation.eulerAngles.z), 0.7f * Time.deltaTime / Time.fixedDeltaTime);
|
|
FW.GetChild(0).localRotation = rb.transform.localRotation;
|
|
}
|
|
rearWheels[0].localRotation = rb.transform.localRotation;
|
|
rearWheels[1].localRotation = rb.transform.localRotation;
|
|
|
|
if (carVelocity.z > 1)
|
|
{
|
|
bodyMesh.localRotation = Quaternion.Slerp(bodyMesh.localRotation, Quaternion.Euler(Mathf.Lerp(0, -5, carVelocity.z / maxSpeed),
|
|
bodyMesh.localRotation.eulerAngles.y, bodyTilt * steeringInput), 0.4f * Time.deltaTime / Time.fixedDeltaTime);
|
|
}
|
|
else
|
|
{
|
|
bodyMesh.localRotation = Quaternion.Slerp(bodyMesh.localRotation, Quaternion.Euler(0, 0, 0), 0.4f * Time.deltaTime / Time.fixedDeltaTime);
|
|
}
|
|
|
|
if (kartLike)
|
|
{
|
|
if (brakeInput > 0.1f)
|
|
{
|
|
bodyMesh.parent.localRotation = Quaternion.Slerp(bodyMesh.parent.localRotation,
|
|
Quaternion.Euler(0, 45 * steeringInput * Mathf.Sign(carVelocity.z), 0),
|
|
0.1f * Time.deltaTime / Time.fixedDeltaTime);
|
|
}
|
|
else
|
|
{
|
|
bodyMesh.parent.localRotation = Quaternion.Slerp(bodyMesh.parent.localRotation,
|
|
Quaternion.Euler(0, 0, 0),
|
|
0.1f * Time.deltaTime / Time.fixedDeltaTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateGroundedState()
|
|
{
|
|
origin = rb.position + radius * Vector3.up;
|
|
Vector3 direction = -transform.up;
|
|
float maxdistance = radius + 0.2f;
|
|
|
|
if (groundCheck == GroundCheckType.RayCast)
|
|
{
|
|
isGrounded = Physics.Raycast(rb.position, Vector3.down, out hit, maxdistance, drivableSurface);
|
|
}
|
|
else if (groundCheck == GroundCheckType.SphereCast)
|
|
{
|
|
isGrounded = Physics.SphereCast(origin, radius + 0.1f, direction, out hit, maxdistance, drivableSurface);
|
|
}
|
|
else
|
|
{
|
|
isGrounded = false;
|
|
}
|
|
}
|
|
|
|
public bool grounded()
|
|
{
|
|
return isGrounded;
|
|
}
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (rb == null || Application.isPlaying) return;
|
|
|
|
SphereCollider sphere = rb.GetComponent<SphereCollider>();
|
|
if (sphere == null) return;
|
|
|
|
float rad = sphere.radius;
|
|
float width = 0.02f;
|
|
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawWireCube(rb.transform.position + ((rad + width) * Vector3.down), new Vector3(2 * rad, 2 * width, 4 * rad));
|
|
|
|
BoxCollider box = GetComponent<BoxCollider>();
|
|
if (box != null)
|
|
{
|
|
Gizmos.color = Color.green;
|
|
Gizmos.DrawWireCube(transform.position, box.size);
|
|
}
|
|
}
|
|
}
|
|
}
|