- Home /
Issue using wheelColliders around sphere
Hello guys, I hope you're doing well. I need your help on the following issue.
I aim to create a small prototype where you could drive a car around a sphere. The drive style is semi-realistic, meaning that I will use wheelColliders. For now, the car is only going forward at a reasonable speed. Here's a quick shot of the issue :
-->Issue right here <---
As you can see, when the car reaches a certain speed, it loses gravity strength. It is a normal behavior considering physical laws but in this case it's happening very quickly (way too fast actually...). Here's some datas to get an idea of what I am doing (wrong?) :
I also tried to apply a LOT of forces to my car to be sure that it stays on the ground but when there is too much forces applied on the wheels, the car is going crazy.
As you can see, I tried also to add joints to force the car to not fly. I actually tried a bunch of various ways to achieve this but it is not precise. Often, I end up with jittery wheel effects or similar behavior that I cannot accept.
Here is the only 2 scripts I use :
sCarManager on the car
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class sCarManager : MonoBehaviour {
//WheelColliders
[SerializeField] private WheelCollider[] wcWheels;
//Floats
[SerializeField] private float fMotorTorque;
private float fCurrentSpeed;
private float fInitialSpringStrenght;
//Script
private sGravityManager sGM;
//SpringJoint
private SpringJoint sjJoint;
//Rigidbody
private Rigidbody rbRigid;
public static sCarManager instance = null;
private void Awake() {
if (!instance) { instance = this; }
}
private void Start() {
//Initialize script type variables
sGM = sGravityManager.instance;
//Initialize the array at 4 and get the wheels from the car
wcWheels = new WheelCollider[4];
GameObject goWheelsParent = GameObject.FindGameObjectWithTag("WheelColliders");
for (int i = 0; i < 4; i++) {
//Get each wheelCollider from the car
wcWheels[i] = goWheelsParent.transform.GetChild(i).GetComponent<WheelCollider>();
}
//Initialization of Rigidbody
rbRigid = gameObject.GetComponent<Rigidbody>();
//Initialization of variable joint
sjJoint = gameObject.GetComponent<SpringJoint>();
fInitialSpringStrenght = sjJoint.spring;
}
//Called every fixed frame
public void FixedUpdate() {
//Apply a torque to all wheels
ApplyMotorTorque(wcWheels, fMotorTorque);
//Get the current speed of the car
fCurrentSpeed = rbRigid.velocity.magnitude;
//Increase joint strenght based on speed
sjJoint.spring = fCurrentSpeed * fInitialSpringStrenght;
}
//Apply torque to specific wheels
private void ApplyMotorTorque(WheelCollider[] wcs, float trq) {
for(int i = 0; i < 4; i++) {
wcs[i].motorTorque = trq;
}
}
}
sGravityManager on the planet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class sGravityManager : MonoBehaviour {
//Scripts
private sCarManager sCM;
//Rigidbodies
private Rigidbody rbCar;
private Rigidbody rbPlanet;
//Transforms
private Transform trCOM;
//Vector3
public Vector3 v3GravityForceToApply;
//Instance of this script
public static sGravityManager instance = null;
//Launch the very first frame
private void Awake() {
if(!instance) { instance = this; }
}
private void Start() {
//Initialize script variables
sCM = sCarManager.instance;
//Increase fixed timestep pace
Time.fixedDeltaTime = 0.01f;
//Get the car and planet RigidBodys
rbCar = GameObject.FindGameObjectWithTag("Car").GetComponent<Rigidbody>();
rbPlanet = transform.GetComponent<Rigidbody>();
//Initialize transforms and script variables
trCOM = GameObject.FindGameObjectWithTag("COM").transform;
}
private void FixedUpdate() {
#region Constant gravity force
//Get gravity force based on car and planet positions
v3GravityForceToApply = GravitySimulation(rbCar, rbPlanet);
//Apply the force to the RigidBody
rbCar.AddForce(v3GravityForceToApply);
#endregion
}
//Method returning the direction in which the car is being pulled
private Vector3 GravitySimulation(Rigidbody rbc, Rigidbody rbp) {
//rbc -> RigidBodyCar and rbp -> RigidBodyPlanet
Vector3 v3Direction = rbp.position - trCOM.position;
float fDistance = v3Direction.magnitude;
float fForceMagnitude = (rbc.mass * rbp.mass) / Mathf.Pow(fDistance, 2);
Vector3 v3Force = v3Direction.normalized * fForceMagnitude;
return (v3Force);
}
}
So, do I need to calculate a force to apply, based on car's velocity, at each frame? Did I miss another inventive way to ground the car for a bit longer? What are your thoughts in this situation guys?
(For those who will suggest to not use wheelColliders, this is not related to this topic. Thank you for your understanding. No offense.)
Thanks for the time spent reading this post, it is a long one!
Rhony
Answer by Shameness · Jun 14, 2019 at 11:03 PM
Gravity force lingers towards the direction when the first time it applied. If you can, tilt whole velocity towards center of the sphere before applying new one. ( as you mentioned )
float magnitude = rbc.velocity.magnitude;
float degToRadian = (Mathf.PI / 180);
float x_rotation = transform.eulerAngles.x;
float x_rotation_in_radian = x_rotation * degToRadian;
rbc.velocity = new Vector3(0, magnitude * Mathf.sin( x_rotation_in_radian ), Mathf.cos( x_rotation_in_radian ) );
Documentation suggest to not modify velocity directly, b/c unrealistic physics behavior, its your call.
Or you can make car body fixed and make the sphere rotate under the wheels ? Like the first car race games, road moves. Then rotate camera reverse of the sphere's rotation for gravity illusion.
Hi @Shameness, thanks for the help!
I just gave a shot at your code. I tried that before and after adding force toward center but it got worse. The car was shaking, and the wheels were spinning in place with the same amount of torque. I guess it follows what you mentioned, that modifying rigidBody.velocity directly is not wise.
The idea of rotating the sphere is a clever one but I do want to make use of wheelColliders properties to take advantage of physical based behaviors. I will give it a shot aswell though, it might be good enough.
Is adjusting force strength based on current velocity a bad idea at all?