Veering car (using WheelCollider)

Hello, I recently created a new Unity project. I created a car object and gave it four children Objects with wheel colliders and one box collider child. The Car parent object itself has a Rigidbody of course.

I created a script that steers the wheels and adds torque to them.

I’d like you to look at this before I’m gonna explain further:

As you can see in the video, the car is veering. The reason for this is that one of the wheels (the front left in this case [the left one right in front of the camera]) somehow has no grip - while the other wheels slowly start to roll, the front left instantly has a massive rpm count. This isn’t a problem of the WheelCollider though, since all four share the same stats. I noticed that this wheelspin always happens with the first WheelCollider the motor torque gets applied to.

I tried finding the problem within my script, yet I couldn’t find anything that could be the reason for this.
Here is the class that applies the forces to the car. I know it’s a bit of a mess but I can’t find the reason why the first wheel the forces get applied to always does this wheelspin:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WheelManager : MonoBehaviour
{
    [Header("Stats:")]
    [SerializeField] float maxMotorTorque = 100;
    [SerializeField] float backwardsTorque = 50;
    [SerializeField] float brakeForce = 90;
    [SerializeField] float maxSteerAngle = 45f;
    [SerializeField, Tooltip("The steering angle range at the top speed.")] float steerAngleMaxSpeed = 5;

    [Header("Acceleration details:")]
    [SerializeField] AnimationCurve curve;
    [SerializeField, Tooltip("Needed to calculate velocity of the car.")] float wheelRadius;
    [SerializeField, Tooltip("In meters per second (m/s).")] float topSpeed;
    private float currentSpeed;
    private float currentRpm;

    [Header("Wheels")]
    [SerializeField] Wheel[] wheels;

    [Header("Input Variables:"), Tooltip("Only can be used to manuever the car if no input script is conrtolling it.")]
    public bool forwards;
    public bool backwards;
    public bool braking;
    [Range(-1, 1)] public float steerAngle;

    void Start()
    {
        
    }

    void FixedUpdate()
    {
        currentRpm = GetCurrentRpm(wheels);
        currentSpeed = VelocityInMetersPerSecond(currentRpm, wheelRadius);

        AccelerationManager();
        SteeringAngles();
    }

    private void AccelerationManager()
    {
        // this state manager is built like a hierachy
        // each if statement has return; at its end, so that e.g. braking overwrites accelerating and accelerating overwrites driving backwards
        // this means that if the player hits the backwards and forwards key at the same time, the car will drive forwards, but if he brakes now, the car will brake instead of accelerating
        foreach (Wheel wheel in wheels)
        {
            if (braking)
            {
                // brake, do not accelerate more
                // if(braking) is put here so that it overwrites the acceleration

                Brake(wheel);
                return;
            }
            if(forwards && currentSpeed < topSpeed)
            {
                // drive forwards
                // is put here so that braking can overwrite it, but that it still is handled above driving backwards

                Accelerate(wheel);
                return;
            }
            if(backwards)
            {
                // the last statement, will be overwritten by all other statements

                BwAcceleration(wheel);
                return;
            }

            wheel.wheelCol.motorTorque = 0f;
            wheel.wheelCol.brakeTorque = 0f;
        }
    }

    private void SteeringAngles()
    {
        foreach (Wheel wheel in wheels)
        {
            if (wheel.canSteer)
            {
                float normalizedSpeed = Mathf.Clamp01(Mathf.Abs(currentSpeed) / topSpeed);
                float currentSteerRange = Mathf.Lerp(maxSteerAngle, steerAngleMaxSpeed, normalizedSpeed);
                wheel.wheelCol.steerAngle = currentSteerRange * steerAngle;
            }
        }
    }

    #region Acceleration & Braking Functions

    private void Accelerate(Wheel wheel)
    {
        wheel.wheelCol.brakeTorque = 0;
        wheel.wheelCol.motorTorque = TorqueToAdd(currentSpeed, maxMotorTorque);
    }

    private void BwAcceleration(Wheel wheel)
    {
        wheel.wheelCol.brakeTorque = 0;
        wheel.wheelCol.motorTorque = -TorqueToAdd(currentSpeed, backwardsTorque);
    }

    private void Brake(Wheel wheel)
    {
        wheel.wheelCol.motorTorque = 0;
        wheel.wheelCol.brakeTorque = brakeForce;
    }

    #endregion

    #region Miscellanios Functions

    private float VelocityInMetersPerSecond(float tireRpm, float tireRadius)
    {
        return (((Mathf.PI * 2) * tireRadius) / 60) * tireRpm;
    }

    private float GetCurrentRpm(Wheel[] wheel)
    {
        float addedSpeeds = 0;

        foreach (Wheel wheelItem in wheel)
        {
            addedSpeeds += wheelItem.wheelCol.rpm;
        }

        float averageSpeeds = addedSpeeds / wheels.Length;
        return  averageSpeeds;
    }

    private float TorqueToAdd(float currentSpeed, float maxTourque)
    {
        float normalizedSpeed = Mathf.Clamp01(Mathf.Abs(currentSpeed) / topSpeed);
        return curve.Evaluate(normalizedSpeed) * maxTourque;
    }

    #endregion
}

The “Wheel” class referenced in the script is a class I made just for storing some variables:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]

public class Wheel
{
    public bool canSteer;
    public WheelCollider wheelCol;
    public GameObject wheelMesh;
}

As mentioned earlier, all WheelColliders share the same stats.
I am really clueless to what the issue is. I know some people advise to making your own car system, but I do not have the knowledge to make one myself, so if you could help that’d be awesome.

Thanks in advance and I’ll try to answer questions as good as I can.

Okay I found the solution!

I don’t know how this was the issue but the following was the problem:

As you can see in my script, in the AccelerationManager() function, if you want to accelerate, this happens:
foreach function gets all wheels > checks if player is braking > checks if player is accelerating > accelerates

However, the problem was that each frame the foreach function gets called, and then the if statements get asked for each wheel seperately.
The now fixed procedure to accelerate would look like this:
checks if player is braking > checks if player is accelerating > calls foreach function and accelerates the wheels

I genuinely have no idea how and why this works, but it does, and that’s enough for me.