129 lines
4.5 KiB
C#
129 lines
4.5 KiB
C#
using UnityEngine;
|
||
|
||
public enum DriveType { FWD, RWD, AWD } // Передний, Задний, Полный привод
|
||
|
||
[RequireComponent(typeof(Rigidbody))]
|
||
public class CarController : MonoBehaviour
|
||
{
|
||
public float SpeedKmH => rb.linearVelocity.magnitude * 3.6f;
|
||
|
||
[Header("Drive Settings")]
|
||
public DriveType driveType = DriveType.AWD;
|
||
[SerializeField] private float motorForce = 1500f;
|
||
[SerializeField] private float brakeForce = 3000f;
|
||
[SerializeField] private float maxSteerAngle = 30f;
|
||
|
||
[Header("Wheel Colliders")]
|
||
[SerializeField] private WheelCollider frontLeftCollider;
|
||
[SerializeField] private WheelCollider frontRightCollider;
|
||
[SerializeField] private WheelCollider rearLeftCollider;
|
||
[SerializeField] private WheelCollider rearRightCollider;
|
||
|
||
[Header("Wheel Meshes (для визуализации)")]
|
||
[SerializeField] private Transform frontLeftMesh;
|
||
[SerializeField] private Transform frontRightMesh;
|
||
[SerializeField] private Transform rearLeftMesh;
|
||
[SerializeField] private Transform rearRightMesh;
|
||
|
||
[Header("Arcade Braking")]
|
||
[SerializeField] private float brakingDrag = 2f;
|
||
|
||
private float defaultDrag;
|
||
private Rigidbody rb;
|
||
private float currentMotorForce;
|
||
private float currentBrakeForce;
|
||
private float currentSteerAngle;
|
||
|
||
private void Start()
|
||
{
|
||
rb = GetComponent<Rigidbody>();
|
||
defaultDrag = rb.linearDamping;
|
||
}
|
||
|
||
// Метод вызывается из другого скрипта (ввода)
|
||
public void ProcessInput(float verticalInput, float horizontalInput, bool isBraking)
|
||
{
|
||
currentSteerAngle = maxSteerAngle * horizontalInput;
|
||
currentMotorForce = verticalInput * motorForce;
|
||
currentBrakeForce = isBraking ? brakeForce : 0f;
|
||
}
|
||
|
||
private void FixedUpdate()
|
||
{
|
||
HandleMotor();
|
||
HandleSteering();
|
||
ApplyBraking();
|
||
UpdateWheelPoses();
|
||
ApplyArcadeDrag();
|
||
}
|
||
|
||
private void HandleMotor()
|
||
{
|
||
// Распределяем крутящий момент в зависимости от типа привода
|
||
switch (driveType)
|
||
{
|
||
case DriveType.FWD: // Передний (недостаточная поворачиваемость, стабилен)
|
||
frontLeftCollider.motorTorque = currentMotorForce;
|
||
frontRightCollider.motorTorque = currentMotorForce;
|
||
break;
|
||
case DriveType.RWD: // Задний (склонен к заносам / дрифту)
|
||
rearLeftCollider.motorTorque = currentMotorForce;
|
||
rearRightCollider.motorTorque = currentMotorForce;
|
||
break;
|
||
case DriveType.AWD: // Полный (отличный старт и сцепление)
|
||
float halfForce = currentMotorForce / 2f;
|
||
frontLeftCollider.motorTorque = halfForce;
|
||
frontRightCollider.motorTorque = halfForce;
|
||
rearLeftCollider.motorTorque = halfForce;
|
||
rearRightCollider.motorTorque = halfForce;
|
||
break;
|
||
}
|
||
}
|
||
|
||
private void HandleSteering()
|
||
{
|
||
frontLeftCollider.steerAngle = currentSteerAngle;
|
||
frontRightCollider.steerAngle = currentSteerAngle;
|
||
}
|
||
|
||
private void ApplyBraking()
|
||
{
|
||
float frontBrake = currentBrakeForce;
|
||
float rearBrake = currentBrakeForce * 0.4f;
|
||
|
||
frontLeftCollider.brakeTorque = frontBrake;
|
||
frontRightCollider.brakeTorque = frontBrake;
|
||
rearLeftCollider.brakeTorque = rearBrake;
|
||
rearRightCollider.brakeTorque = rearBrake;
|
||
}
|
||
|
||
private void UpdateWheelPoses()
|
||
{
|
||
UpdateWheelPose(frontLeftCollider, frontLeftMesh);
|
||
UpdateWheelPose(frontRightCollider, frontRightMesh);
|
||
UpdateWheelPose(rearLeftCollider, rearLeftMesh);
|
||
UpdateWheelPose(rearRightCollider, rearRightMesh);
|
||
}
|
||
|
||
private void ApplyArcadeDrag()
|
||
{
|
||
// Если нажали тормоз и машина едет быстрее 1 м/с
|
||
if (currentBrakeForce > 0 && rb.linearVelocity.magnitude > 1f)
|
||
{
|
||
rb.linearDamping = brakingDrag;
|
||
}
|
||
else
|
||
{
|
||
rb.linearDamping = defaultDrag;
|
||
}
|
||
}
|
||
|
||
private void UpdateWheelPose(WheelCollider collider, Transform mesh)
|
||
{
|
||
if (mesh == null) return;
|
||
|
||
collider.GetWorldPose(out Vector3 pos, out Quaternion rot);
|
||
mesh.position = pos;
|
||
mesh.rotation = rot;
|
||
}
|
||
} |