Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to make a physically real,stable car with WheelColliders

Discussion in 'Editor & General Support' started by Edy, Jun 3, 2010.

  1. dagtholander

    dagtholander

    Joined:
    Oct 28, 2014
    Posts:
    19
    @Edy There's a fault in the wheelcolliders and i don't know how to solve it a good way, I'm making a car simulator and the engine torque is based on torque curves and gearratios and such. However i detected that if you for example assign 300 NM of torque to the wheels it keeps accelerating in infinity, but in real life a engine has a max output that the engine won't go any faster.
    Is there a way of solving this? I don't want to put a top speed that the car won't pass, it would be unrealistic.
     
  2. hemantp

    hemantp

    Joined:
    Feb 10, 2015
    Posts:
    15
    we have make a game like side wheel hero. how to setup the car lift on only two wheel like side wheel hero.

    please give your valuable suggestion
     
  3. Willy_2202

    Willy_2202

    Joined:
    Feb 19, 2015
    Posts:
    50
    Can you please make another version or an optional script we can add to our player so we can enter and exit the vehicle
     
  4. Elharter

    Elharter

    Joined:
    Sep 20, 2015
    Posts:
    58
    Hi,....big big big thanks to you for this amazing tutorial - ive searched around 3 weeks before i found this - and now are all questions answered! big big big thank you!
     
    Edy likes this.
  5. NyaNya

    NyaNya

    Joined:
    Oct 15, 2015
    Posts:
    1
    @Edy Hi~ I come from China.
    I want to know if i can bring this awesome article to my blog (http://blog.csdn.net/u011643833). Translate into Chinese to help more people just like me to make a physically real vehicel easily~
    Full credit to you of cours.

    Hope my poor English can express myself.
    Waiting for your reply. : D
     
  6. SuperUltraHyper

    SuperUltraHyper

    Joined:
    Sep 7, 2015
    Posts:
    112
    So, I have been messing with this script and have an issue. Basically in the instance that one of the wheels becomes ungrounded and the other is still grounded I was getting a weird jerking motion.

    Please help me check me sanity:
    I think this is because as one wheel becomes ungrounded the other exerts an uneven force over the entire vehicle that doesn't result in a twisting motion. This effectively makes the vehicle lighter. At all times you want a Twisting motion. In Order to accurately simulate an Anti-Swaybar you would need access to the vehicles WheelCollider.suspensionSpring function and dynamically adjust the springs tension based on the script's antiRollForce var. You can't manipulate that so so the next best thing is what we are doing. Anyway, in no case should the force make the vehicle lighter / not be a twisting one. Therefore the script should check for "if (groundedL || groundedR)"
    This still isn't ideal because in the instance that the wheel becomes ungrounded it doesn't necessarily mean the travel of the ungrounded wheel is fully extended. I think it's good enough though as the travel will be moving that way in a hurry.

    I'm I Right?

    Updated Script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AntiRollBar : MonoBehaviour {
    5.  
    6.     public WheelCollider WheelL;
    7.     public WheelCollider WheelR;
    8.     public float AntiRoll = 5000.0f;
    9.  
    10.     public void FixedUpdate()
    11.     {
    12.         WheelHit hit;
    13.         float travelL = 1.0f;
    14.         float travelR = 1.0f;
    15.  
    16.         bool groundedL = WheelL.GetGroundHit(out hit);
    17.         if (groundedL)
    18.             travelL = ( -WheelL.transform.InverseTransformPoint(hit.point).y - WheelL.radius) / WheelL.suspensionDistance;
    19.        
    20.         bool groundedR = WheelR.GetGroundHit(out hit);
    21.         if (groundedR)
    22.             travelR = ( -WheelR.transform.InverseTransformPoint(hit.point).y - WheelR.radius) / WheelR.suspensionDistance;
    23.  
    24.         float antiRollForce = (travelL - travelR) * AntiRoll;
    25.  
    26.         if (groundedL || groundedR)
    27.         {
    28.             GetComponent<Rigidbody>().AddForceAtPosition(WheelL.transform.up * -antiRollForce, WheelL.transform.position);
    29.             GetComponent<Rigidbody>().AddForceAtPosition(WheelR.transform.up * antiRollForce, WheelR.transform.position);
    30.         }
    31.     }
    32. }
    33.  
     
  7. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,497
    Sure, you have my permission. Thank you very much!

    Yes, you are right. This script was a preliminary version, but the version used in EVP4 (Edy's Vehicle Physics for Unity 4) included three operating modes. One of them is the one you're describing: applying both forces whenever any of the wheels are grounded. If fits very good with sports cars. Other mode was applying a force at the grounded wheel and the other at the position of the CoM if the other wheel is lifted.

    Modifying suspensionSpring dynamically wasn't possible in practice in Unity 4. In Unity 5, however, looks like it might work. I haven't tested it yet because EVP for Unity 5 uses a different technique and a single anti-roll setting is included directly in the Vehicle Controller. I plan to experiment with spring forces and anti-roll bars for my other simulation project, Vehicle Physics Pro.

    The anti-roll bar has two main effects on the vehicle:
    1- It translates part of the suspension force from the inner wheel to the outer wheel, reducing the roll angle in curves.
    2- It reduces the overall vehicle elevation in curves (as both suspensions get more compression), which has the effective effect of lowering the center of mass, thus improving stability on curves.

    Both effects might be simulated by modifying suspensionSpring in real time. The problem here is that you'll surely face the issues derived from the Unity 5 WheelCollider failures.

    Some time ago I tested an anti-roll bar implementation that modified the height of the CoM only, with great results. However this solution wouldn't be efficient in Unity 5: modifying the position of the CoM triggers a lot of internal calculations (inertia tensor, sprung masses), so modifying it on each frame would cause a big performance penalty.
     
  8. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,497
    The logic solution here would be applying the torque based on the actual angular velocity of the wheels.

    I can't give better advice, sorry. After some tests I was unable to find any logic on the WheelCollider friction, so I abandoned it and implemented my own friction simulation. I've also designed and implemented a correct engine and drivetrain simulation which applies applies torque + angular velocity correctly.

    I'm afraid that the "drive on two wheels" trick is not possible at this time with Unity 5 WheelCollider. Suspension force is always applied vertically with regards to the rigidbody, no matter the actual situation of the vehicle:

     
  9. Willy_2202

    Willy_2202

    Joined:
    Feb 19, 2015
    Posts:
    50
    I love edy's car physics demo, I cant buy the full version though, do you thing you could make a free version with like 1 car or some limitation?
     
    cholasimmons likes this.
  10. cholasimmons

    cholasimmons

    Joined:
    Dec 17, 2015
    Posts:
    3
    just thought I'd post an updated script, I converted this from java to C# myself, thought it was a big deal last night, lol (Unity 5.3.5f1)
    However this causes my car to rise up in the air off the ground when I steer left, right brings it back down to Earth.


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AntiRoll : MonoBehaviour {
    5.  
    6.     public WheelCollider WheelL;
    7.     public WheelCollider WheelR;
    8.     public float AntiRollValue = 3000;
    9.  
    10.     // Update is called once per frame
    11.     void FixedUpdate ()
    12.     {
    13.         WheelHit hit;
    14.         float travelL = 1.0F;
    15.         float travelR = 1.0F;
    16.  
    17.         bool groundedL = WheelL.GetGroundHit (out hit);
    18.         if (groundedL) {
    19.             travelL = (-WheelL.transform.InverseTransformPoint (hit.point).y - WheelL.radius) / WheelL.suspensionDistance;
    20.         }
    21.         bool groundedR = WheelR.GetGroundHit (out hit);
    22.         if (groundedR) {
    23.             travelR = (-WheelR.transform.InverseTransformPoint (hit.point).y - WheelR.radius) / WheelR.suspensionDistance;
    24.         }
    25.  
    26.         float antiRollForce = (travelL - travelR) * AntiRollValue;
    27.         if(groundedL){
    28.             GetComponent<Rigidbody>().AddForceAtPosition(WheelL.transform.up * -antiRollForce, WheelL.transform.position);
    29.         }
    30.         if(groundedR){
    31.             GetComponent<Rigidbody>().AddForceAtPosition(WheelR.transform.up * -antiRollForce, WheelR.transform.position);
    32.         }
    33.     }
    34. }
    35.  
     
    40detectives and Edy like this.
  11. ricardHagerman

    ricardHagerman

    Joined:
    May 26, 2014
    Posts:
    3
    this works in unity 5.5

    Code (CSharp):
    1.  
    2.  
    3. using UnityEngine;
    4.  
    5. public class SwayBar : MonoBehaviour
    6. {
    7.     public WheelCollider[] wheels;
    8.     Rigidbody rb;
    9.     WheelAxle frontAxle;
    10.     WheelAxle rearAxle;
    11.     public float antiRollFront = 3000f;
    12.     public float antiRollRear = 3000f;
    13.  
    14.     void Start()
    15.     {
    16.         frontAxle= new WheelAxel { LeftWheel = wheels[0], RightWheel = wheels[1], AntiRollForce = antiRollFront };
    17.         rearAxle = new WheelAxel { LeftWheel = wheels[2], RightWheel = wheels[3], AntiRollForce = antiRollRear };
    18.         rb = GetComponent<Rigidbody>();
    19.     }
    20.  
    21.     void FixedUpdate()
    22.     {
    23.         WheelHit hit;
    24.         foreach (var wheel in wheels)
    25.             if (wheel.GetGroundHit(out hit))
    26.                 rb.AddForceAtPosition(wheel.transform.up * AntiRollForce(wheel), wheel.transform.position);
    27.     }
    28.  
    29.     float AntiRollForce(WheelCollider wheel)
    30.     {
    31.         WheelAxle axle;
    32.         if (frontAxle.LeftWheel == wheel || frontAxle.RightWheel == wheel)
    33.             axle = frontAxle;
    34.         else
    35.             axle = rearAxle;
    36.         WheelHit hit;
    37.         var travelL = 1f;
    38.         var travelR = 1f;
    39.         if (axle.LeftWheel.GetGroundHit(out hit))
    40.             travelL = (-axle.LeftWheel.transform.InverseTransformPoint(hit.point).y - axle.LeftWheel.radius) / axle.LeftWheel.suspensionDistance;
    41.         if (axle.RightWheel.GetGroundHit(out hit))
    42.             travelR = (-axle.RightWheel.transform.InverseTransformPoint(hit.point).y - axle.RightWheel.radius) / axle.RightWheel.suspensionDistance;
    43.         if (wheel == axle.LeftWheel)
    44.             return -(travelL - travelR) * axel.AntiRollForce;
    45.         return (travelL - travelR) * axel.AntiRollForce;
    46.     }
    47. }
    48.  
    combined with this struct

    Code (CSharp):
    1.  
    2.  
    3. using UnityEngine;
    4.  
    5. struct WheelAxle
    6. {
    7.     public WheelCollider LeftWheel { get; set; }
    8.     public WheelCollider RightWheel { get; set; }
    9.     public float AntiRollForce { get; set; }
    10. }
    11.  
    NB: put the wheels in to the wheelColliderArray in the right order (FL,FR,RL,RR)
     
    Last edited: Dec 9, 2016
    40detectives, UnityLighting and Edy like this.
  12. UnityLighting

    UnityLighting

    Joined:
    Mar 31, 2015
    Posts:
    3,866
    Thank you. WheelAxel are WheelAxle in line 16 and 17. Also line 52-53 are axle.
     
  13. Banksy

    Banksy

    Joined:
    Mar 31, 2013
    Posts:
    376
    hhmm... so how do I save a struct ?

    Do i save it in a separate script or add to the top of my car's physics script ??
     
  14. UnityLighting

    UnityLighting

    Joined:
    Mar 31, 2015
    Posts:
    3,866
    Separate script is easier.
     
  15. AnupamSahu

    AnupamSahu

    Joined:
    May 16, 2015
    Posts:
    8
    hey, thanks for this wonderful tutorial..
    but, there's a tiny problem.. when you rapidly turn the steering left to right.. the car looses control, kind of oscillates and turns around..
    i know this is a realistic simulator, but it isn't desirable in a racing game where ease of control dominates realism..
    any ideas on how I can solve this problem?
    btw, i use Unity 5.6
     
  16. UnityLighting

    UnityLighting

    Joined:
    Mar 31, 2015
    Posts:
    3,866
    You can change sideways friction values to slide the car when turning on high
     
  17. nawash

    nawash

    Joined:
    Jan 29, 2010
    Posts:
    166
     
  18. RSRY

    RSRY

    Joined:
    Mar 15, 2017
    Posts:
    1
    Very useful, thank you.
     
  19. unity_neIDb-PA4Kmwdw

    unity_neIDb-PA4Kmwdw

    Joined:
    Apr 2, 2020
    Posts:
    9
    Hey Edy, I am trying to convert the Antiroll from the JS above to C#. But I get an error with my code that says
    Assets\AntiRoll.cs(10,7): error CS0542: 'AntiRoll': member names cannot be the same as their enclosing type
    What does this mean? Did I miss something?

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class AntiRoll : MonoBehaviour {
    6. WheelCollider WheelL;
    7. WheelCollider WheelR;
    8. float AntiRoll= 5000.0f;
    9. void  FixedUpdate (){
    10.     WheelHit hit;
    11.     float travelL= 1.0f;
    12.     float travelR= 1.0f;
    13.     float groundedL= WheelL.GetGroundHit(hit);
    14.     if (groundedL)
    15.         travelL = (-WheelL.transform.InverseTransformPoint(hit.point).y - WheelL.radius) / WheelL.suspensionDistance;
    16.     float groundedR= WheelR.GetGroundHit(hit);
    17.     if (groundedR)
    18.         travelR = (-WheelR.transform.InverseTransformPoint(hit.point).y - WheelR.radius) / WheelR.suspensionDistance;
    19.     float antiRollForce= (travelL - travelR) * AntiRoll;
    20.     if (groundedL)
    21.         rigidbody.AddForceAtPosition(WheelL.transform.up * -antiRollForce,
    22.                WheelL.transform.position);
    23.     if (groundedR)
    24.         rigidbody.AddForceAtPosition(WheelR.transform.up * antiRollForce,
    25.                WheelR.transform.position);
    26.     }
    27. }
     
  20. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,850
    Change AntiRoll to antiRoll in the class variables. BTW this is still the best vehicle physics thread on the forums.
     
  21. mukeshraj8e

    mukeshraj8e

    Joined:
    Dec 24, 2020
    Posts:
    2
    Sorry i was so late
    How to add Tyre burnout physics like gta4,i mean tyre pops when over heated and sparks come.
    Thank you
     
  22. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,850
    Create a variable that expresses a value derived from tire slippage and RPM that when exceeded will cause scaling and then a particle efx blowout. IOW the car usually travels so many meters per revolution. If the car wheel rotates and would have went so many meters but doesn't then find that ratio between supposed to travel and actually travelled and when the ratio is such that you want the effect to happen then trigger it when it reaches this value.
     
  23. theNfan

    theNfan

    Joined:
    Dec 30, 2020
    Posts:
    25
    Is it also possible to use WheelColliders for beam axle setups?
    I'm working on a monster truck and so far the wheels are set up with wheel colliders and work fine, but the chassis is just floating above them.
    I've been looking into connecting the WheelColliders to axles and the axles to the suspension using joints, but so far it all led to crazy physics. It does not have to be really physically accurate, it's mostly for optics.
    In another thread someone said that WheelColliders may not be the best choice for something like that, but to go with standard colliders on the wheels and just turning them.