Perekyp/Assets/Scripts/Car/CarController.cs

192 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("Grip Settings (Friction Stiffness)")]
[Tooltip("Сцепление для переднего привода (FWD)")]
[SerializeField] private float fwdFrontGrip = 1.2f;
[SerializeField] private float fwdRearGrip = 2.0f;
[Tooltip("Сцепление для заднего привода (RWD)")]
[SerializeField] private float rwdFrontGrip = 2.0f;
[SerializeField] private float rwdRearGrip = 1.2f;
[Tooltip("Сцепление для полного привода (AWD)")]
[SerializeField] private float awdFrontGrip = 2.5f;
[SerializeField] private float awdRearGrip = 2.5f;
[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;
private Rigidbody rb;
// Входящие данные от игрока
private float inputVertical;
private float inputHorizontal;
private bool inputHandbrake;
private void Start()
{
rb = GetComponent<Rigidbody>();
}
public void ProcessInput(float vertical, float horizontal, bool handbrake)
{
inputVertical = vertical;
inputHorizontal = horizontal;
inputHandbrake = handbrake;
}
private void FixedUpdate()
{
HandleSteering();
HandleMotorAndBrakes();
UpdateWheelPoses();
}
private void HandleSteering()
{
float steerAngle = maxSteerAngle * inputHorizontal;
frontLeftCollider.steerAngle = steerAngle;
frontRightCollider.steerAngle = steerAngle;
}
private void HandleMotorAndBrakes()
{
float currentMotorTorque = 0f;
float currentBrakeTorque = 0f;
// Определяем, куда физически движется машина (вперед или назад)
float localVelocityZ = transform.InverseTransformDirection(rb.linearVelocity).z;
// ЛОГИКА ГАЗА (W)
if (inputVertical > 0)
{
if (localVelocityZ < -1f) // Если катимся назад, а жмем W -> Тормозим
currentBrakeTorque = brakeForce;
else // Иначе едем вперед
currentMotorTorque = inputVertical * motorForce;
}
// ЛОГИКА ТОРМОЗА И ЗАДНЕГО ХОДА (S)
else if (inputVertical < 0)
{
if (localVelocityZ > 1f) // Если едем вперед, а жмем S -> Тормозим
currentBrakeTorque = brakeForce;
else // Иначе сдаем назад (inputVertical отрицательный, поэтому момент тоже отрицательный)
currentMotorTorque = inputVertical * motorForce;
}
// ЛОГИКА РУЧНИКА (Пробел)
if (inputHandbrake)
{
currentMotorTorque = 0f; // Глушим газ
currentBrakeTorque = brakeForce * 2f; // Ручник хватает сильнее обычного тормоза
}
ApplyBrakes(currentBrakeTorque, inputHandbrake);
ApplyMotor(currentMotorTorque);
}
private void ApplyMotor(float torque)
{
// Получаем базовые настройки трения
WheelFrictionCurve frontFriction = frontLeftCollider.sidewaysFriction;
WheelFrictionCurve rearFriction = rearLeftCollider.sidewaysFriction;
switch (driveType)
{
case DriveType.FWD:
frontLeftCollider.motorTorque = torque;
frontRightCollider.motorTorque = torque;
rearLeftCollider.motorTorque = 0;
rearRightCollider.motorTorque = 0;
frontFriction.stiffness = fwdFrontGrip;
rearFriction.stiffness = fwdRearGrip;
break;
case DriveType.RWD:
frontLeftCollider.motorTorque = 0;
frontRightCollider.motorTorque = 0;
rearLeftCollider.motorTorque = torque;
rearRightCollider.motorTorque = torque;
frontFriction.stiffness = rwdFrontGrip;
rearFriction.stiffness = rwdRearGrip;
break;
case DriveType.AWD:
float halfTorque = torque / 2f;
frontLeftCollider.motorTorque = halfTorque;
frontRightCollider.motorTorque = halfTorque;
rearLeftCollider.motorTorque = halfTorque;
rearRightCollider.motorTorque = halfTorque;
frontFriction.stiffness = awdFrontGrip;
rearFriction.stiffness = awdRearGrip;
break;
}
// Применяем измененное трение к колесам
frontLeftCollider.sidewaysFriction = frontFriction;
frontRightCollider.sidewaysFriction = frontFriction;
rearLeftCollider.sidewaysFriction = rearFriction;
rearRightCollider.sidewaysFriction = rearFriction;
}
private void ApplyBrakes(float brake, bool isHandbrake)
{
if (isHandbrake)
{
// Ручник блокирует только задние колеса (эффект заноса)
frontLeftCollider.brakeTorque = 0;
frontRightCollider.brakeTorque = 0;
rearLeftCollider.brakeTorque = brake;
rearRightCollider.brakeTorque = brake;
}
else
{
// Обычный тормоз (S) срабатывает на все колеса, передок сильнее
frontLeftCollider.brakeTorque = brake;
frontRightCollider.brakeTorque = brake;
rearLeftCollider.brakeTorque = brake * 0.5f;
rearRightCollider.brakeTorque = brake * 0.5f;
}
}
private void UpdateWheelPoses()
{
UpdateWheelPose(frontLeftCollider, frontLeftMesh);
UpdateWheelPose(frontRightCollider, frontRightMesh);
UpdateWheelPose(rearLeftCollider, rearLeftMesh);
UpdateWheelPose(rearRightCollider, rearRightMesh);
}
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;
}
}