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:
- The bike consists of the body, forks / suspensions (front and rear), wheels (front and rear), and a rider / character.
- 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 - The wheels are attached to their corresponding forks by joints, likewise with the forks and the body.
- 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)
- 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.
- The character / rider is attached on a node, has ragdoll that is configured with isKinematic turned on.
- The wheels are using SphereColliders that are rotated with a torque and give an acceleration to it as in real life situation.
- 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.
- The rigidbodies have the standart default drag values of 0 and 0.05 for linear and angular drag.
This is my MotorcycleController.cs file:
using UnityEngine;
using System.Collections;
public class MotorcycleController : MonoBehaviour
{
//The enum for the wheeldrive type
public enum eWheelDriveType
{
NONE,
REAR_WD,
FRONT_WD,
FOUR_WD
}
//The bike itself.
//Consisted of: the body frame, forks / suspensions, and wheels. All of these components will be attached via joints.
public Rigidbody body;
public Transform frontFork;
public Transform frontWheel;
public Transform rearFork;
public Transform rearWheel;
private GroundDetection rearWheelGroundDetect;
private GroundDetection frontWheelGroundDetect;
public eWheelDriveType wheelDriveType = eWheelDriveType.REAR_WD;
public float maxWheelAngularVelocity = 120.0f;
public float torque = 200.0f;
public float reverseTorque = 80.0f;
public float onGroundRotationTorque = 500.0f;
public float inAirRotationTorque = 700.0f;
//Center of mass of the bike.
public Transform centerOfMass;
//Character / rider attachment node
public Transform characterAttachPosition;
//-------------------------------------------
//Flag to determine whether we are in the air or not
private bool isInAir = false;
//Engine sound
private AudioSource engineSound;
private float pitch;
//Game inputs
private bool accelerate = false;
private bool reverse = false;
private bool left = false;
private bool right = false;
void Awake ()
{
}
void Start ()
{
//Ignoring collisions
Physics.IgnoreCollision (frontWheel.collider, body.collider);
Physics.IgnoreCollision (rearWheel.collider, body.collider);
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("Bike"),true);
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("Character"),true);
Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Bike"), LayerMask.NameToLayer ("CharacterCollider"),true);
//Audio source for the engine sound. Its pitch be changed according to the current angular velocity
engineSound = body.GetComponent<AudioSource>();
//setting rear wheel max angular rotation speed
//rearWheel.GetComponent<Rigidbody> ().maxAngularVelocity = speed;
if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
rearWheel.GetComponent<Rigidbody> ().maxAngularVelocity = maxWheelAngularVelocity;
}
if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
frontWheel.GetComponent<Rigidbody> ().maxAngularVelocity = maxWheelAngularVelocity;
}
frontWheelGroundDetect = frontWheel.GetComponent<GroundDetection>(); //Detect wheelie
rearWheelGroundDetect = rearWheel.GetComponent<GroundDetection>(); //Detect wheelie
frontWheelGroundDetect.Create(body.gameObject);
rearWheelGroundDetect.Create(body.gameObject);
body.rigidbody.centerOfMass = centerOfMass.localPosition;
}
void Update()
{
if ( GameManager.instance.GetGamePlayerManager().LifeStatus() == GamePlayerManager.eLifeStatus.ALIVE
GameInput.instance.isInputActive)
{
//GameInput is a singleton that will handle all inputs according to the platform and mode.
if(GameInput.instance.RightLeft > 0)
right = true;
else
right = false;
if(GameInput.instance.RightLeft < 0)
left = true;
else
left = false;
if(GameInput.instance.ForwardBackward > 0)
accelerate = true;
else
accelerate = false;
if(GameInput.instance.ForwardBackward < 0)
reverse = true;
else
reverse = false;
//----------------------------------
//Changing engine sound pitch depending on the wheel drive's (or the rear for 4WD) angular velocity
if(accelerate || reverse)
{
Rigidbody wheelRigidbody;
if (wheelDriveType == eWheelDriveType.FRONT_WD)
wheelRigidbody = frontWheel.rigidbody;
else
wheelRigidbody = rearWheel.rigidbody;
pitch = wheelRigidbody.angularVelocity.sqrMagnitude / maxWheelAngularVelocity;
pitch *= Time.deltaTime * 2;
pitch = Mathf.Clamp (pitch + 1, 0.5f,2.0f);
}
else
pitch = Mathf.Clamp (pitch - Time.deltaTime * 2, 0.5f, 2.0f);
}
//Clamping again. I'm paranoid. :P
pitch = Mathf.Clamp (pitch - Time.deltaTime * 2, 0.5f, 1.8f);
engineSound.pitch = pitch;
}
void FixedUpdate ()
{
if ( GameManager.instance.GetGamePlayerManager().LifeStatus() == GamePlayerManager.eLifeStatus.ALIVE
GameInput.instance.isInputActive)
{
if (accelerate)
{
if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
rearWheel.rigidbody.AddTorque (Vector3.right * torque * Time.deltaTime ,ForceMode.Impulse); //add rotational speed to rear wheel
}
if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
frontWheel.rigidbody.AddTorque (Vector3.right * torque * Time.deltaTime ,ForceMode.Impulse); //add rotational speed to front wheel
}
} //else dirt.Stop ();
else if(reverse)
{
if (wheelDriveType == eWheelDriveType.REAR_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
rearWheel.rigidbody.AddTorque (new Vector3 (-reverseTorque * Time.deltaTime, 0.0f, 0.0f),ForceMode.Impulse); //add rotational speed to rear wheel
}
if (wheelDriveType == eWheelDriveType.FRONT_WD || wheelDriveType == eWheelDriveType.FOUR_WD)
{
frontWheel.rigidbody.AddTorque (new Vector3 (-reverseTorque * Time.deltaTime, 0.0f, 0.0f),ForceMode.Impulse); //add rotational speed to front wheel
}
}
if (left)
{
if (!isInAir)
{
body.AddTorque (new Vector3 (-onGroundRotationTorque * Time.deltaTime, 0.0f, 0.0f ));
}
else
{
body.AddTorque (new Vector3 (-inAirRotationTorque * Time.deltaTime, 0.0f, 0.0f));
}
}
else if (right)
{
if (!isInAir)
{
body.AddTorque (new Vector3 (onGroundRotationTorque * Time.deltaTime, 0.0f, 0.0f));
}
else
{
body.AddTorque (new Vector3 (inAirRotationTorque * Time.deltaTime, 0, 0));
}
}
if(rearWheelGroundDetect.IsOnTerrain) //Check for ground
{
isInAir = false;
}
else
{
isInAir = true;
}
}
}
}
So, the problems I have right now are:
- 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.
- 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?
- 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.
- 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.
- 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?
