ryzerrr's picture
Upload folder using huggingface_hub
40c0886 verified
Raw
History Blame Contribute Delete
4.73 kB
using UnityEngine;
namespace UnityAgent
{
/// <summary>
/// Arcade car physics: motor torque, steering, braking and a simple
/// four-wheel raycast suspension. Place this on a root GameObject with
/// a Rigidbody and four wheel transforms.
/// </summary>
[RequireComponent(typeof(Rigidbody))]
public class VehicleController : MonoBehaviour
{
[System.Serializable]
public class Wheel
{
public Transform transform;
public bool isSteering;
public bool isPowered;
public bool isBraking;
[HideInInspector] public bool isGrounded;
[HideInInspector] public float suspensionOffset;
}
[Header("Wheels")]
public Wheel[] wheels = new Wheel[4];
[Header("Engine")]
public float motorTorque = 1500f;
public float brakeTorque = 3000f;
public float maxSteerAngle = 30f;
public float maxSpeedKph = 180f;
[Header("Suspension")]
public float suspensionRestLength = 0.5f;
public float suspensionSpring = 35000f;
public float suspensionDamper = 4500f;
public float wheelRadius = 0.35f;
public LayerMask wheelMask = ~0;
[Header("Aerodynamics")]
public float downforce = 100f;
public float centerOfMassOffset = -0.5f;
private Rigidbody _rb;
private float _throttle;
private float _steer;
private float _brake;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
_rb.centerOfMass += Vector3.up * centerOfMassOffset;
_rb.interpolation = RigidbodyInterpolation.Interpolate;
}
private void Update()
{
_throttle = Input.GetAxis("Vertical");
_steer = Input.GetAxis("Horizontal");
_brake = Input.GetKey(KeyCode.Space) ? 1f : 0f;
}
private void FixedUpdate()
{
UpdateWheels();
ApplySuspension();
ApplyDrive();
ApplyDownforce();
}
private void UpdateWheels()
{
foreach (var w in wheels)
{
if (w.transform == null) continue;
Vector3 origin = w.transform.position;
bool hit = Physics.Raycast(
origin, -transform.up, out RaycastHit r,
suspensionRestLength + wheelRadius, wheelMask,
QueryTriggerInteraction.Ignore);
w.isGrounded = hit;
w.suspensionOffset = hit ? r.distance - wheelRadius : suspensionRestLength;
}
}
private void ApplySuspension()
{
foreach (var w in wheels)
{
if (!w.isGrounded) continue;
float force = (suspensionRestLength - w.suspensionOffset) * suspensionSpring;
Vector3 velocity = _rb.GetPointVelocity(w.transform.position);
float upwardVel = Vector3.Dot(transform.up, velocity);
force -= upwardVel * suspensionDamper;
_rb.AddForceAtPosition(transform.up * Mathf.Max(0f, force), w.transform.position);
}
}
private void ApplyDrive()
{
float kph = _rb.velocity.magnitude * 3.6f;
float speedFactor = Mathf.Clamp01(1f - kph / maxSpeedKph);
foreach (var w in wheels)
{
if (!w.isGrounded) continue;
if (w.isPowered)
{
Vector3 force = transform.forward * (_throttle * motorTorque * speedFactor);
_rb.AddForceAtPosition(force, w.transform.position, ForceMode.Force);
}
if (w.isBraking && _brake > 0.01f)
{
Vector3 brakeForce = -transform.forward * (_brake * brakeTorque);
_rb.AddForceAtPosition(brakeForce, w.transform.position, ForceMode.Force);
}
if (w.isSteering)
{
// Rotate the visual wheel and apply a small yaw torque.
w.transform.localRotation = Quaternion.Euler(0f, _steer * maxSteerAngle, 0f);
}
}
// Steering yaw torque.
if (Mathf.Abs(_steer) > 0.01f)
{
float turn = _steer * maxSteerAngle * 0.02f;
_rb.AddTorque(transform.up * turn * (_rb.velocity.magnitude + 1f), ForceMode.Force);
}
}
private void ApplyDownforce()
{
_rb.AddForce(-transform.up * downforce * _rb.velocity.magnitude);
}
}
}