Search Unity

A little help for making a semi-realistic motorbike physics

Discussion in 'Scripting' started by bawenang, Oct 11, 2013.

  1. bawenang

    bawenang

    Joined:
    Aug 18, 2012
    Posts:
    119
    Hi,

    I'm trying to build a motorbike game ala Bike Barron or Motoheroz. I've build a somewhat working game, but the physics is not exactly sufficient. These are what I've made so far:

    1. The bike consists of the body, forks / suspensions (front and rear), wheels (front and rear), and a rider / character.
    2. The rigidbody of all objects are constrained like this:
    -- freeze position: x
    -- freeze rotation: y, z
    Meaning: It can move along the y z plane and rotate only by its x axis
    3. The wheels are attached to their corresponding forks by joints, likewise with the forks and the body.
    4. The joints linking the wheels and forks are configurable joints with locked x,y,z motion and locked x y angular motion, and a free z angular motion (so that it can rotate to move the bike)
    5. The joints linking the forks and body are also configurable with a limited y motion and locked all other motions, and also some spring and damper to simulate suspensions.
    6. The character / rider is attached on a node, has ragdoll that is configured with isKinematic turned on.
    7. The wheels are using SphereColliders that are rotated with a torque and give an acceleration to it as in real life situation.
    8. The wheels are using a physics material with both dynamic and static friction to 1 so to avoid skidding /slipping, and will generate the needed traction to move the bike.
    9. The rigidbodies have the standart default drag values of 0 and 0.05 for linear and angular drag.

    This is my MotorcycleController.cs file:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class MotorcycleController : MonoBehaviour
    5. {
    6.     //The enum for the wheeldrive type
    7.     public enum eWheelDriveType
    8.     {
    9.         NONE,
    10.         REAR_WD,
    11.         FRONT_WD,
    12.         FOUR_WD
    13.     }
    14.    
    15.    
    16.     //The bike itself.
    17.     //Consisted of: the body frame, forks / suspensions, and wheels. All of these components will be attached via joints.
    18.     public Rigidbody body;
    19.     public Transform frontFork;
    20.     public Transform frontWheel;
    21.     public Transform rearFork;
    22.     public Transform rearWheel;
    23.    
    24.     private GroundDetection rearWheelGroundDetect;
    25.     private GroundDetection frontWheelGroundDetect;
    26.    
    27.     public eWheelDriveType wheelDriveType = eWheelDriveType.REAR_WD;
    28.     public float maxWheelAngularVelocity = 120.0f;
    29.     public float torque = 200.0f;
    30.     public float reverseTorque = 80.0f;
    31.     public float onGroundRotationTorque = 500.0f;
    32.     public float inAirRotationTorque = 700.0f;
    33.    
    34.     //Center of mass of the bike.
    35.     public Transform centerOfMass;
    36.    
    37.     //Character / rider attachment node
    38.     public Transform characterAttachPosition;
    39.     //-------------------------------------------
    40.            
    41.     //Flag to determine whether we are in the air or not
    42.     private bool isInAir = false;      
    43.    
    44.     //Engine sound
    45.     private AudioSource engineSound;
    46.     private float pitch;
    47.    
    48.    
    49.     //Game inputs  
    50.     private bool accelerate = false;
    51.     private bool reverse = false;  
    52.     private bool left = false;
    53.     private bool right = false;    
    54.    
    55.     void Awake ()
    56.     {
    57.  
    58.     }
    59.    
    60.     void Start ()
    61.     {
    62.        
    63.         //Ignoring collisions
    64.         Physics.IgnoreCollision (frontWheel.collider, body.collider);
    65.         Physics.IgnoreCollision (rearWheel.collider, body.collider);
    66.        
    67.         Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("Bike"),true);
    68.         Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("Character"),true);
    69.         Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("CharacterCollider"),true);
    70.        
    71.         //Audio source for the engine sound. Its pitch be changed according to the current angular velocity
    72.         engineSound = body.GetComponent<AudioSource>();    
    73.        
    74.         //setting rear wheel max angular rotation speed
    75.         //rearWheel.GetComponent<Rigidbody> ().maxAngularVelocity = speed; 
    76.        
    77.         if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    78.         {
    79.             rearWheel.GetComponent<Rigidbody> ().maxAngularVelocity = maxWheelAngularVelocity;
    80.         }
    81.        
    82.         if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    83.         {
    84.             frontWheel.GetComponent<Rigidbody> ().maxAngularVelocity = maxWheelAngularVelocity;
    85.         }
    86.        
    87.         frontWheelGroundDetect = frontWheel.GetComponent<GroundDetection>(); //Detect wheelie
    88.         rearWheelGroundDetect = rearWheel.GetComponent<GroundDetection>(); //Detect wheelie
    89.        
    90.         frontWheelGroundDetect.Create(body.gameObject);
    91.         rearWheelGroundDetect.Create(body.gameObject);
    92.        
    93.         body.rigidbody.centerOfMass = centerOfMass.localPosition;      
    94.     }
    95.    
    96.     void Update()
    97.     {
    98.         if ( GameManager.instance.GetGamePlayerManager().LifeStatus() == GamePlayerManager.eLifeStatus.ALIVE
    99.                      GameInput.instance.isInputActive)
    100.         {
    101.                
    102.             //GameInput is a singleton that will handle all inputs according to the platform and mode.
    103.             if(GameInput.instance.RightLeft > 0)
    104.                 right = true;
    105.             else
    106.                 right = false;
    107.            
    108.             if(GameInput.instance.RightLeft < 0)
    109.                 left = true;
    110.             else
    111.                 left = false;
    112.                
    113.             if(GameInput.instance.ForwardBackward > 0)
    114.                 accelerate = true;
    115.             else
    116.                 accelerate = false;            
    117.                
    118.             if(GameInput.instance.ForwardBackward < 0)
    119.                 reverse = true;
    120.             else
    121.                 reverse = false;               
    122.                 //----------------------------------
    123.        
    124.            
    125.             //Changing engine sound pitch depending on the wheel drive's (or the rear for 4WD) angular velocity
    126.             if(accelerate || reverse)
    127.             {
    128.                 Rigidbody wheelRigidbody;
    129.                 if (wheelDriveType == eWheelDriveType.FRONT_WD)
    130.                     wheelRigidbody = frontWheel.rigidbody;
    131.                 else
    132.                     wheelRigidbody = rearWheel.rigidbody;
    133.                
    134.                 pitch = wheelRigidbody.angularVelocity.sqrMagnitude / maxWheelAngularVelocity;
    135.                 pitch *= Time.deltaTime * 2;
    136.                 pitch = Mathf.Clamp (pitch + 1, 0.5f,2.0f);        
    137.             }
    138.             else
    139.                 pitch = Mathf.Clamp (pitch - Time.deltaTime * 2, 0.5f, 2.0f);                                                              
    140.         }      
    141.  
    142.  
    143.        
    144.         //Clamping again. I'm paranoid. :P
    145.         pitch = Mathf.Clamp (pitch - Time.deltaTime * 2, 0.5f, 1.8f);
    146.         engineSound.pitch = pitch;
    147.        
    148.     }
    149.    
    150.  
    151.     void FixedUpdate ()
    152.     {          
    153.         if ( GameManager.instance.GetGamePlayerManager().LifeStatus() == GamePlayerManager.eLifeStatus.ALIVE
    154.                      GameInput.instance.isInputActive)
    155.         {      
    156.             if (accelerate)
    157.             {
    158.                 if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    159.                 {
    160.                     rearWheel.rigidbody.AddTorque (Vector3.right * torque * Time.deltaTime ,ForceMode.Impulse); //add rotational speed to rear wheel
    161.                 }
    162.                
    163.                 if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    164.                 {
    165.                     frontWheel.rigidbody.AddTorque (Vector3.right * torque * Time.deltaTime ,ForceMode.Impulse);    //add rotational speed to front wheel
    166.                 }
    167.                
    168.                
    169.             } //else dirt.Stop ();
    170.             else if(reverse)
    171.             {
    172.                 if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    173.                 {
    174.                     rearWheel.rigidbody.AddTorque (new Vector3 (-reverseTorque * Time.deltaTime, 0.0f, 0.0f),ForceMode.Impulse);    //add rotational speed to rear wheel
    175.                 }
    176.                    
    177.                 if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
    178.                 {
    179.                     frontWheel.rigidbody.AddTorque (new Vector3 (-reverseTorque * Time.deltaTime, 0.0f, 0.0f),ForceMode.Impulse);   //add rotational speed to front wheel
    180.                 }
    181.  
    182.             }
    183.  
    184.                
    185.             if (left)
    186.             {
    187.                 if (!isInAir)
    188.                 {
    189.                     body.AddTorque (new Vector3 (-onGroundRotationTorque * Time.deltaTime, 0.0f, 0.0f ));
    190.                 }
    191.                 else
    192.                 {
    193.                     body.AddTorque (new Vector3 (-inAirRotationTorque * Time.deltaTime, 0.0f, 0.0f));    
    194.                 }
    195.    
    196.             }
    197.             else if (right)
    198.             {
    199.                 if (!isInAir)
    200.                 {
    201.                     body.AddTorque (new Vector3 (onGroundRotationTorque * Time.deltaTime, 0.0f, 0.0f));            
    202.                 }
    203.                 else
    204.                 {
    205.                     body.AddTorque (new Vector3 (inAirRotationTorque * Time.deltaTime, 0, 0));  
    206.                 }
    207.    
    208.             }
    209.                    
    210.             if(rearWheelGroundDetect.IsOnTerrain) //Check for ground
    211.             {      
    212.                 isInAir = false;                                   
    213.             }
    214.             else
    215.             {
    216.                 isInAir = true;
    217.             }
    218.            
    219.         }
    220.     }
    221. }
    So, the problems I have right now are:
    1. The bike accelerates so slowly, even with a very big torque and a very big max angular velocity like 1000000. I know it's probably because of the physics material settings of the wheels, but even when I changed it into a smaller value (like 0.6 or 0.4) it didn't change a lot. And a value of 0.2 or less even gave me worse result as the wheels are slipping and couldn't generate any movement force.
    2. If the bike jumps in the air, the wheel rotates faster. And when it lands, the bike runs faster like on a boost or nitro or something. Again, quite probably because of the drag values and combined with the maxAngularVelocity value. Can anybody give me a somewhat correct formula to determine a wheel's max rotation speed based on its torque?
    3. The levels of my game often have a combination of small platforms, each with its own box colliders. I used copies of the same prefab of the objects for this. And I don't know why but the torque wasn't applied correctly to my drive wheel because of these platforms. It's as if you throttled / de-throttled the gas every time the wheels hit a collider.
    4. If I release the throttle / acceleration, the bike won't slow down and came to a halt. I know that it's probably because of the drags of the rigidbodies, but I assumed that the deceleration from the wheel's frictions will be sufficient for this. And also, I was afraid that defining drag values will make the bike accelerate even slower.
    5. I plan to use a wheelie / balancing with only one wheel for bonus points. But I have no idea about how to do this. Can you guys help me with this?

    Can you guys help me here? I'm stuck. Thanks a lot in advance.

    EDIT: I just realized that the title is not exactly correct. It should've been "A little help needed for..." How do you edit the title?
     
    Last edited: Oct 11, 2013
  2. bawenang

    bawenang

    Joined:
    Aug 18, 2012
    Posts:
    119
    Anyone? *bump*
     
  3. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    NECRO BUMP ALERT:

    If you still need help bro, i can give you a hand. I simply steered clear of wheel colliders and used a velocity-based physics model instead. Here is a web demo:
    Bike Physics Example
    And here is my code. Note that this requires that your bike has colliders on the wheels and bike body ONLY. the script also has some particle code commented out, but feel free to use it if your motorbike has particles for exhausts, skiddies, etc:
    Code (csharp):
    1.  
    2. #pragma strict
    3.  
    4. //engine
    5. var speed : float;
    6. private var accel : float;
    7. @range(0,10)
    8. var acceleration : float;
    9. //var exhaustSystem : ParticleSystem;
    10. //var exhaustSystem2 : ParticleSystem;
    11. //var Smoke : ParticleSystem;
    12. //control
    13. var brakePower : float;
    14. var steer : float;
    15. var FrontWheel : GameObject;
    16. var BackWheel : GameObject;
    17.  
    18. function Start () {
    19.     rigidbody.centerOfMass.y = 0.25;
    20. //  Smoke.Stop();
    21. }
    22.  
    23. function FixedUpdate () {
    24.     var movement : Vector3;
    25.     movement = transform.TransformDirection(Vector3.forward) * Mathf.Lerp(0,speed,accel);
    26.     movement.y = rigidbody.velocity.y;
    27.     if (Input.GetButton("Gas")) {
    28.         accel += acceleration/100;
    29.         if (accel >= 1){
    30.         accel = 1;
    31.         }
    32.         rigidbody.velocity = movement;
    33. //      exhaustSystem.Play();
    34. //      exhaustSystem2.Play();
    35.     }
    36.     else {
    37.         accel = 0;
    38. //      exhaustSystem.Stop();
    39. //      exhaustSystem2.Stop();
    40.     }
    41.    
    42.     if (Input.GetButton("Brake")) {
    43.         rigidbody.drag = brakePower;
    44.     }
    45.     else {
    46.         rigidbody.drag = 0;
    47.     }
    48.    
    49.     var spinSpeed : int = rigidbody.velocity.magnitude;
    50.     if (spinSpeed <= 0.001){
    51.         spinSpeed = 0;
    52.     }
    53.    
    54.     //controls
    55.     if (Physics.Raycast(FrontWheel.transform.position,-Vector3.up,1.5)){
    56.         FrontWheel.transform.Rotate(0,-spinSpeed,0);
    57.     }
    58.     if (Input.GetButton("Gas")){
    59.         BackWheel.transform.Rotate(0,Mathf.Lerp(-acceleration*20,-spinSpeed,accel),0);
    60.     }
    61.     else {
    62.         BackWheel.transform.Rotate(0,-spinSpeed,0);
    63.     }
    64.    
    65.     transform.rotation.eulerAngles.z = -Input.GetAxis("X") * 12;
    66.     if (Input.GetAxis("X")  rigidbody.velocity.magnitude > speed/100){
    67.         transform.Rotate(transform.up  * Input.GetAxis("X") * steer);
    68.     }
    69. //  if (Input.GetButton("Gas")  rigidbody.velocity.magnitude < speed / 4  acceleration >= 1){
    70. //      Smoke.Emit(acceleration*10);
    71. //  }  
    72. }
    73.  
    Note that this bike, although it aims to be realistic, is more of an arcade bike than a realism bike. and this doesn't quite work wioth slopes yet...
     
  4. cheng-peng

    cheng-peng

    Joined:
    Mar 14, 2014
    Posts:
    1
    Hi,I am buliding a motorBike Project. The Physics I use is the same as you. the front connect with body using ConfigurationJoint and allow the Y move motion. the rear connect whit body using hingeJoint.
    .But I have a problem. see the picture. When the bike run into the collider with high speed. The body stops,but the wheel move because of its speed. After a while , the wheel resume normal position . Even I use joint ,but the move power is very big ,then rigidbody could move out of my bounds.
    What can I do?
     

    Attached Files: