Hey Unity community. This is my first post so bear with me if its horrible .
Ok, so I’m working on a flight sim (an air racing game to be exact) and I’m having a little trouble getting the air plane controller right. There are a couple things I’d like to do but can’t figure out:
Smooth out the throttle changes, right now it just jolts forward instantly; I’d like to delay the speed increase also
How to do lift so that if the player, for example, rolls the plane it will fall because of the airfoil or if the throttle/velocity forward changes, the plane drops and tends to point straight down (instead of drop while horizontal or straight up)
Here’s how the code looks currently:
var speed = 1.0;
var boostSpeed = 1.5;
var rollRate = 1.0;
var elevatorRate = 1.0;
var rudderRate = 1.0;
var lift = 1.2; //use these two later with throttle
var gravity = 1.0;
var tracktrigger : Transform;
var explosionPrefab : Transform; //vars for if the player exits the track
var planeModel : GameObject;
function OnTriggerExit (trackTrigger)
{
Destroy (planeModel);
// will put explosion stuff in here
}
function Update () //here's where the player controls are
{
transform.Translate(0, 0, speed * Time.deltaTime); //the thrust forward
if (Input.GetButton ("Boost"))
{
transform.Translate(0, 0, boostSpeed * speed * Time.deltaTime);
}
if (Input.GetButton ("Rollright"))
{
transform.Rotate(0, 0, rollRate * -1.0 * Time.deltaTime);
}
else if (Input.GetButton ("Rollleft"))
{
transform.Rotate(0, 0, rollRate * Time.deltaTime);
}
if (Input.GetButton ("Rise"))
{
transform.Rotate(elevatorRate * -1.0 * Time.deltaTime, 0, 0);
}
else if (Input.GetButton ("Dive"))
{
transform.Rotate(elevatorRate * Time.deltaTime, 0, 0);
}
if (Input.GetButton ("Rudderright"))
{
transform.Rotate(0, rudderRate * Time.deltaTime, -.07 * Time.deltaTime);
}
else if (Input.GetButton ("Rudderleft"))
{
transform.Rotate(0, rudderRate * -1.0 * Time.deltaTime, .07 * Time.deltaTime);
}
}
I’d appreciate any help/advice you guys can give me!
Make the player control a variable with the “desired thrust” - and have a second variable with the actual thrust. If “desired thrust” is larger than the actual thrust, increase the latter; if smaller, decrease. Use a constant multiplier and time.deltaTime with that - if the multiplier is large, the throttle response will be quick, if small, it’ll change slower.
This uses physics, thus the rigidbody; but the principle stays the same as in your approach - use your planes local vectors multiplied with whatever value and your plane will turn around its local orientation.
Thanks for the response on the first question, I’ll use that technique, but wouldn’t using relative torque only be good for like flat spins? Or do you mean I should use relative motion for my controls instead of just plain old transform.Rotate? What I want to do is somehow script stalling or emulate how lift works, depending on vars for wing-lift, the actual speed, and the rotation of the plane.
Sorry if I missing something, I’m not too experienced with scripting.
If you could, please give an example of how I would change my controller script so I can test it the way you suggested.
To simulate stalls and the like, you need to simulate the airflow over the wings. Enable gravity (obviously - and as a bonus, unity saves you the trouble of simulating it yourself ;)) and add a force pointing up depending on the airspeed. Something like this:
var velocity : float;
var rollRate : float = 10.0; //or whatever
FixedUpdate () {
velocity = rigidbody.velocity;
rigidbody.AddRelativeForce(Vector3.up * velocity);
rigidbody.AddRelativeTorque (Vector3.forward * -Input.GetAxis("Roll") * rollRate); //The "-" might not be necessary, depends on how your controls are set up
//Use something along these lines for pitch (Vector3.left) and yaw (Vector3.up)
}
This is very crude and very untested, proper airplane physics require a bit more. I found this with a quick google search, seems to give a proper overview:
Again, you’ll have to emulate the airflow and the resulting lift from the wings; then, you’d add the lift with rigidbody.AddRelativeForce(Vector3.up).
The physics engine is quite powerful. Of course, you’ll need to fine-tune quite a lot (drag, mass etc.) to make it work like you want it - but on the other hand, you won’t have to deal with quite a lot of other stuff (actually implementing drag and gravity, for once ;)).
I’m testing it in a brand new controller script. I like how the roll and elevator torque works, but the plane lift force uses the local direction instead of world, so it acts kinda like a helicopter (before I’ve added a force forward for thrust).
I’ve tried adding “, Space.World” to the end but it just returns an error.
Also, whenever I added the thrust force, the plane accelerates and whenever I try to turn, it just keeps going straight, but the plain rotates of course.
Here’s the new code so far:
var velocity = 5.0;
var speed = 10.0;
var desiredSpeed = 5.0;
var rollRate : float;
var elevatorRate : float;
var rudderRate : float;
var planeLift = 1.965;
function FixedUpdate ()
{
rigidbody.AddRelativeForce(Vector3.up * velocity * planeLift);
rigidbody.AddRelativeTorque(0, 0, -Input.GetAxis("Roll") * rollRate);
rigidbody.AddRelativeForce(0, 0, speed);
rigidbody.AddRelativeTorque(-Input.GetAxis("Elevator") * elevatorRate, 0, 0);
}
Use rigidbody.AddForce to use the world coordinates. However, that’d lead to unrealistic results, since p.e. the plane would still go skywards when it’s upside down. About the helicopter thing, maybe use an additional rotation that’d change the pitch of the plane a bit?
Another thing you might want to try - use rigidbody.AddRelativeForce only once, something like this: rigidbody.AddRelativeForce(0, lift, thrust);I don’t know, but maybe that’ll be smoother.
Unless you didn’t post it, you’re missing this bit:
Big tip for getting rid of artificial feel: The lift vector should not be perpendicular the the local forward direction, but to the local airflow around the ship.
There’s a bunch of other stuff. The best option I’ve found so far for modeling wings is the formula on from this page: Lift coefficient - Wikipedia. It takes quite a bit of study to really understand what’s going on there, but it works really well. The next step would probably be analysing a ships model using blade theory, like X-Plane does, but that might be a bit overboard.
Thanks for the help, I’ve modified the script a little more, but as is, the plane maneuvers with WAY too much inertia. How do I adjust the settings so that it’s a bit more snappy, but not completely linear like my old script (is it under the input, Physics, or rigidbody settings)? Also the thrust force isn’t quite as constant as I would like, for example the speed can be set to 50, but the plane can almost rotate in place, and whenever I start the game the plane has to slowly accelerate to get up to speed, and once its going fast enough I can hardly maneuver correctly. If you’d like I can upload a recording of how to plane flies on Youtube or Vimeo.
In my arcade-style spaceship game (with no gravity), I use the following settings for the rigidbody:
Mass 1
Drag 0.8
Angular Drag 1
The maximum thrust is set to 2000 (added with rigidbody.AddRelativeForce(Vector3.forward * thrust * Time.deltaTime)), the maximum roll/pitch/yaw rate is set to 75 (rigidbody.AddRelativeTorque(Vector3.x * rollRate * Time.deltaTime).
I’m not sure if the Time.deltaTime is actually doing anything since all that stuff is inside FixedUpdate(), I haven’t bothered to test that, to be honest. (My code kinda grew into its current shape, so that must have been in Update() before :))
These settings give me pretty snappy reactions and just a little bit of inertia. The thing is, I got this far with a lot of trial and error, and you should do the same; especially the rigidbody settings have a big impact on how the controls feel. Fool around with the settings until you’re satisfied. (Maybe create temporary GUI sliders to manipulate everything on the fly.)
That reminds me, there is one thing in my code you might want to try aswell:
function Start() {
rigidbody.inertiaTensor = Vector3 (1,1,1);
}
As far as I can work out, this kinda centers the center of the rotation in relation to the model. I think. Otherwise, Unity seems to calculate that for you depending on the model you’re using, which in my case resulted in unwanted behaviour.