using UnityEngine; public enum DriveType { FWD, RWD, AWD } // Передний, Задний, Полный привод [RequireComponent(typeof(Rigidbody))] public class CarController : MonoBehaviour { [Header("Drive Settings")] public DriveType driveType = DriveType.AWD; [SerializeField] private float motorForce = 1500f; [SerializeField] private float brakeForce = 3000f; [SerializeField] private float maxSteerAngle = 30f; [Header("Arcade Feel")] [SerializeField] private Transform centerOfMass; // Заниженный центр тяжести [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 currentMotorForce; private float currentBrakeForce; private float currentSteerAngle; private void Start() { rb = GetComponent(); if (centerOfMass != null) { rb.centerOfMass = centerOfMass.localPosition; // Смещаем центр масс вниз для аркадности } } // Метод вызывается из другого скрипта (ввода) 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(); } 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() { frontLeftCollider.brakeTorque = currentBrakeForce; frontRightCollider.brakeTorque = currentBrakeForce; rearLeftCollider.brakeTorque = currentBrakeForce; rearRightCollider.brakeTorque = currentBrakeForce; } 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; } }