Unity 3D Code Snippet – Flight Script

Roll, yaw and pitch axis definition for an air...

Flying is a simple concept in games. An object that can move in 3 dimensions? I am all over that! But how about rotating to the forward vector? How about a constant velocity? Here is a quick way to get your game object up in the air (that joke hurt to type).

Set Up Your Player

There really isn’t much you have to do to set up you player object. Here’s a few simple steps:

  1. Create a GameObject (either Empty or a Primitive (cube, sphere, etc). If you pick empty, make sure you give it a model).
  2. Name it (something descriptive, like “PlayerPlane” or something).
  3. Give it a Rigidbody (Component->Physics->Rigidbody).
  4. Create an empty C# script.
  5. Attach the script to your new GameObject.
That’s pretty much it, except for one more thing: The Rigidbody. Your object has physics, now, and he’s going to have to be affected by other objects correctly. If you don’t set this up right, your flying object may get tapped by anything and start spiraling out of control.
Here are the settings I use. Feel free to mess around with your own.
I froze the rotation because every time I hit another object I lost control of my ship, having to lean on the arrow keys to keep it steady (it was actually a pretty cool effect, like phugoid or dutch rolling in aeronautics).
Now, the function for the script is pretty straight forward, but I’ll break it down bit-by-bit (full code available at the bottom).
    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 200.0f;

We give the script these two members. AmbientSpeed is minimum speed of the aircraft (in this example, the aircraft is always moving along its forward axis. You can remove this or change it so the object can move backwards and such). RotationSpeed is the speed at which the object turns. Simple enough to understand, right?

Now we’re getting into our UpdateFunction(). Why UpdateFunction() instead of using Update() or FixedUpdate()? Well, I’ve answered my own question: It could be used for either case. But, since I’m using a Rigidbody, it would make sense to use this for FixedUpdate(). I just like to keep code modular.

void UpdateFunction()
    {

        Quaternion AddRot = Quaternion.identity;
        float roll = 0;
        float pitch = 0;
        float yaw = 0;

This is initialization code. Obvious. AddRot is our temporary variable for storing the rotation value that we’ll be rotating by. roll, pitch and yaw are for storing our input values.

        roll = Input.GetAxis("Roll") * (Time.deltaTime * RotationSpeed);
        pitch = Input.GetAxis("Pitch") * (Time.deltaTime * RotationSpeed);
        yaw = Input.GetAxis("Yaw") * (Time.deltaTime * RotationSpeed);

Here, we’re getting our input (defined by “Roll,” “Pitch,” and “Yaw” which are defined in the Input Manager in Edit->Project Settings->Input), and multiplying it by (Δtime multiplied by our rotation speed). This gives us the angles at which we want to rotate.

        AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
        rigidbody.rotation *= AddRot;

We take those angle values, chuck them into a Vector3, and then directly modify our AddRot.eulerAngles member to rotate it to those values. We then multiply our rigidbody.rotation by AddRot and Viola! Rotation.

        Vector3 AddPos = Vector3.forward;
        AddPos = Ship.rigidbody.rotation * AddPos;
        rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
    }

Last, but not least, we create AddPos. AddPos will be used to define our velocity. We set it to the product of our rigidbody.rotation by Vector3.forward, and set the rigidbody.velocity to AddPos multiplied by (Δtime multiplied by our ambient speed). If you wanted to have a boost speed, it would be (Δtime multiplyed by (ambient speed plus boost speed)).

And there you go. A player controlled, flying… whatever. Keep in mind this is pretty basic, and you can probably go further to optimize and make it more robust. Any tips or modifications would be great in the comments.

Once again, here’s all the code together. Thanks for checking out the tutorial. Take care!

    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 200.0f;

void UpdateFunction()
    {        Quaternion AddRot = Quaternion.identity;
        float roll = 0;
        float pitch = 0;
        float yaw = 0;
        roll = Input.GetAxis("Roll") * (Time.deltaTime * RotationSpeed);
        pitch = Input.GetAxis("Pitch") * (Time.deltaTime * RotationSpeed);
        yaw = Input.GetAxis("Yaw") * (Time.deltaTime * RotationSpeed);
        AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
        rigidbody.rotation *= AddRot;
        Vector3 AddPos = Vector3.forward;
        AddPos = Ship.rigidbody.rotation * AddPos;
        rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
    }

You guys asked for it, here is a new and improved sample project set up using the flight script at GitHub. Enjoy.

Looking for something a bit more “game-y” and less “math-y”? Check out my quick tutorial on “All-Range Mode” Flight Controls!


59 thoughts on “Unity 3D Code Snippet – Flight Script

  1. thank you for this article. I am also learning Unity3d to make some games and your article has helped me get some insights and ideas. Thanks again.

      1. No other scripts!
        There is one object ?a cube, created three inputs used mouseX – rename to Yaw, mouseY -> Pitch and scrol mouse -> Roll
        here’s the script, which I attached to the cube:

        using UnityEngine;
        using System.Collections;

        public class playerplane : MonoBehaviour {
        public float AmbientSpeed = 100.0f;

        public float RotationSpeed = 200.0f;
        private playerplane Playerplane;
        // Use this for initialization
        void Start () {

        }

        void UpdateFunction()
        {

        Quaternion AddRot = Quaternion.identity;
        float roll = 1;
        float pitch = 1;
        float yaw = 1;
        roll = Input.GetAxis(“Roll”) * (Time.deltaTime * RotationSpeed);
        pitch = Input.GetAxis(“Pitch”) * (Time.deltaTime * RotationSpeed);
        yaw = Input.GetAxis(“Yaw”) * (Time.deltaTime * RotationSpeed);
        AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
        rigidbody.rotation *= AddRot;
        Vector3 AddPos = Vector3.forward;
        AddPos = Playerplane.rigidbody.rotation * AddPos;
        rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
        }
        }

      1. Hi!

        I called my Primitive Player, and I changed this line:
        AddPos = Ship.rigidbody.rotation * AddPos;

        To: AddPos = Player.rigidbody.rotation * AddPos;

      2. Ah! Ok. This is actually my-bad, in a way.

        Ship is a gameObject that I failed to mention. If, per se, your flight script was on a different object than what’s doing the actual flying, you would set Ship to that object.

        If this is NOT the case, just pop off that “Ship.” (Or, for you, “Player.”) And let the lovin’ happen right on your objects’ rigidbody.

        (All of that sounded so wrong…)

  2. My object fall down to the plane without do anyting… Maybe I’m doing something wrong.

    Could you upload the source files of the project, please?

  3. really thats wonderful code keith.bt i have issue i.e.,i dont know how to make input settings for the roll,pitch and yaw.i wanna move aircraft by using arrow keys.bt there are only two axis i.e.,horizontal and vertical..i dont know how to make the third one .ie., for roll.as i used pitch and yaw for two axis.how abt the third.so,plz help me in mapping the roll,pitch and yaw axis to the userdefines keys (keyboard arrow keys)am new to unity plz help me.thanks a lot keith

  4. You like to be more flexible with a generic UpDateFunction to be used in update or fixedupdate. But Time.deltaTime should be used in Update while in FixedUpdate you should use Time.fixedDeltaTime instead. I suggest to use a dt as parameter for your function…

      1. i want sample application so that i come to know how it works….I need it badly please help me.. i want to show flying object in space

        Thanks

  5. Hi, I desire to subscribe for this webpage to take latest updates, so where
    can i do it please help.My coder is trying to convince me to move to
    .net from PHP. I have always disliked the idea because of the
    expenses. But he’s tryiong none the less. I’ve been using Movable-type on numerous
    websites for about a year and am anxious about switching to another
    platform. I have heard good things about blogengine.

    net. Is there a way I can import all my wordpress posts into it?
    Any kind of help would be really appreciated!

  6. Hello Sir!
    I am getting an exception while i run my game it says “input axis roll is not setup”
    plz help me with it …

  7. Hello, I attached this script to the moving object:

    using UnityEngine;
    using System.Collections;

    public class FlightBasic : MonoBehaviour
    {

    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 200.0f;

    void FixedUpdateFunction()
    {
    Quaternion AddRot = Quaternion.identity;

    float roll = 0.0f;
    float pitch = 0.0f;
    float yaw = 0.0f;

    roll = Input.GetAxis(“Roll”) * (Time.deltaTime * RotationSpeed);
    pitch = Input.GetAxis(“Pitch”) * (Time.deltaTime * RotationSpeed);
    yaw = Input.GetAxis(“Yaw”) * (Time.deltaTime * RotationSpeed);

    AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);

    rigidbody.rotation *= AddRot;

    Vector3 AddPos = Vector3.forward;

    AddPos = rigidbody.rotation * AddPos;

    rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
    }
    }

    END SCRIPT

    …and renamed my inputs to Roll, Pitch and Yaw, but nothing I do moves the object. Any thoughts?

      1. Yes indeed! There is a rigid body, and I followed the instructions you laid out for it as well.

        Is there anything particular I need to do for the inputs? I kept everything at the default settings but simply renamed them to match your script.

  8. Hi, i love your work, you’re really saving my life.
    My problem is the following : what if the 3 axis are not defined in the inputs ?
    I know how to create input but i don’t know how to configure them to fit to this script.

    Please help

      1. Hi Keith

        This is working really well – however I’d really like more of a gravity feel so that when the throttle is reduced the plane begins to fall out of the sky.

        Turning gravity on in the rigidbody does help but the following line stops the plane from free falling:

        rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);

        How could we adjust this script so that as the throttle is reduced the plane begins to drop with gravity?

        Thanks

        Jeff

      2. Easy! Factor in the Physics gravity constant into the y of the rigidbodys’ velocity after we work AddPos into it. I’m on my phone, but pseudo code would be:

        rigidbody.velocity = (AddPos * (Time.deltaTime * AmbientSpeed)) + (Physics.gravity *Time.deltaTime);

        In theory, this should make you always fall when the throttle is kicked back, and give you a gradual dip when you’re not accelerating fast enough. You could work in a Stall feature if the engines aren’t pumping out enough thrust.

  9. Hi Keith — thanks for taking the time to post this script!

    I’m trying to get it working and I’ve done the following:
    1. Created game object (sphere) and named it “PlayerPlane”
    2. Setup the rigibody as shown above
    3. Created a new script and attached it to the sphere
    4. In Project Settings –> Input I rename Horizontal Axis to “Yaw” and Vertical Axes to “Pitch” … not sure where roll would be. I feel like I’m missing something with the input axes…

    No matter what I try based on the comments above, the sphere just falls…

    Here is my script:

    using UnityEngine;
    using System.Collections;

    public class NewBehaviourScript : MonoBehaviour {

    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 200.0f;

    void UpdateFunction()
    { Quaternion AddRot = Quaternion.identity;
    float roll = 0;
    float pitch = 0;
    float yaw = 0;
    roll = Input.GetAxis(“Roll”) * (Time.deltaTime * RotationSpeed);
    pitch = Input.GetAxis(“Pitch”) * (Time.deltaTime * RotationSpeed);
    yaw = Input.GetAxis(“Yaw”) * (Time.deltaTime * RotationSpeed);
    AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
    rigidbody.rotation *= AddRot;
    Vector3 AddPos = Vector3.forward;
    AddPos = rigidbody.rotation * AddPos;
    rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
    }
    }

    1. You can look in the example I posted. Pretty much, I copied the Horizontal Axis (or “Yaw”) and mapped it to the Q and E keys. You can ise whatever you like, though.

  10. {
    public GameObject asteroidPos;
    public GameObject asteroidPrefab;

    public float fieldRadius;
    public float size;
    public float movementSpeed;
    public float rotationSpeed;

    void Start()
    {
    StartCoroutine(loopFunc()); // Asteroid Timer is called
    }

    // Asteroid Timer for pupulating Asteroids in the Scene
    IEnumerator loopFunc()
    {
    while(true)
    {
    populateAsteroids();
    yield return new WaitForSeconds(3);// Asteroids are called for each (??) Seconds
    }
    while(false)
    {
    populateAsteroids();

    }
    }

    // Populating Asteroid
    void populateAsteroids()

    {
    for(int i = 0; i 50)

    {
    i = -5;

    }

    GameObject newAsteroid = (GameObject)Instantiate(asteroidPrefab, Random.onUnitSphere* fieldRadius,Random.rotation);

    float size = Random.Range(0.3f, 2);
    newAsteroid.transform.localScale = Vector3.one * size;

    newAsteroid.rigidbody.velocity = Random.insideUnitSphere * movementSpeed;
    newAsteroid.rigidbody.angularVelocity = Random.insideUnitSphere * rotationSpeed;

    }

    }

    }

    I have created this asteroid random populating script, after a deep research. The problem is , I need to destroy the object after few seconds, AM currently able to populate it for every few seconds.

    I do also want this asteroid to populate only in place where the spaceship moves how to do that. Please help, Thanks in advance.

    1. ONe thing I would suggest is to create two floats for minSeconds and maxSeconds then get a random between the two for more unpredictability. yield return new WaitForSeconds(3);
      yield return new WaitForSeconds(place random here);

      if your asteroids travel in a straight line I would let them get off the screen and then destroy.
      if (transform.position.y >= offScreenPosition.y)
      {
      destroy.gameobject:
      }

      or something like that if you get what I mean and I am understanding what you are wanting to do with this

      Hope I was some help, but I could be way off base.
      Mike

      1. Thanks a lot for your reply. Yeah asteroids will be spilled in the screen using onUnitSphere. Asteroids is currently spilled only in one point at screen, I want them to follow my spaceship and keep spilling asteroids for each few seconds and need to be killed after few seconds.

        I read your reply, I couldn’t understand the random. Sorry, am new to c# programming. I just want the asteroids to follow or spill only in the place where the spaceship moves as it is a 3d space and need to be killed after few seconds. Thanks in advance.

    2. If the asteroid has a timer and a destroyTime variables it would start the timer at spawn and destroy at destroyTime

      public float timer;
      public float destroyTime

      void start ()
      //this is what makes the timer tick and stores it in the timer variable
      {
      timer += Time.deltaTime;
      }

      void update ()
      //this is when the object gets destroyed
      {
      if (timer >= destroyTime)
      destroy this.GameObject
      }

      hope this is helpful I also am new to c# but have used this type of timer before with good results. I have no Idea how to help with your spawn but you could try this youtube link.

      http://www.youtube.com/channel/UCOIcO8Lsk1MERedhOnew73A

      1. Thanks any ways. I have tried a way to solve it.

        {
        public GameObject asteroidPos;
        public GameObject asteroidPrefab;

        public float fieldRadius;
        public float size;
        public float movementSpeed;
        public float rotationSpeed;
        public float destroyTime = 15;

        void Start()
        {
        StartCoroutine(populateTimer()); // Asteroid Timer is called
        }

        // Asteroid Populate Timer
        IEnumerator populateTimer()
        {
        while(true)
        {
        populateAsteroids();
        yield return new WaitForSeconds(5);// Asteroids are called for each (??) Seconds
        }
        }

        // Asteroid Destroy Timer
        IEnumerator DestroyAfterTime(GameObject asteroidTemp , float destroyTime)
        {
        yield return new WaitForSeconds(destroyTime);
        Destroy(asteroidTemp);
        }

        // Populating Asteroid
        void populateAsteroids()

        {
        for(int i = 0; i < 50; ++i)
        {
        GameObject newAsteroid = (GameObject)Instantiate(asteroidPrefab, Random.onUnitSphere* fieldRadius,Random.rotation);
        float size = Random.Range(1.0f, 50);

        newAsteroid.transform.parent = asteroidPos.transform;
        newAsteroid.transform.position = asteroidPos.transform.position;

        StartCoroutine(DestroyAfterTime(newAsteroid,10f));

        newAsteroid.transform.localScale = Vector3.one * size;
        newAsteroid.rigidbody.velocity = Random.insideUnitSphere * movementSpeed;
        newAsteroid.rigidbody.angularVelocity = Random.insideUnitSphere * rotationSpeed;
        }
        }

        }

  11. you may not answer this because this post is old. I am trying to limit the “roll” I have tried using mathf.clamp(roll, -45,45), if statements, anything I could think of. I dont get an error, but the object just keeps rotating. can you suggest how to limit the roll to 45 degrees in either direction.

    thank you for your time,

  12. Hey! I am working on a school project and would really appreciate if you could help me with this code! Thank you so much for providing this page and these assets!

    Here is the code I’m using so far: [I am getting error CS1525 unexpected symbol “internal”] Any and all help is SUPER appreciated!!!

    using UnityEngine;
    using System.Collections;

    public class playerplane : MonoBehaviour {
    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 200.0f;
    private playerplane Playerplane;
    void Start () {

    }

    void FixedUpdate()
    {

    Quaternion AddRot = Quaternion.identity;
    float roll = 1;
    float pitch = 1;
    float yaw = 1;
    roll = Input.GetAxis(”roll”) * (Time.deltaTime * RotationSpeed);
    pitch = Input.GetAxis(”pitch”) * (Time.deltaTime * RotationSpeed);
    yaw = Input.GetAxis(”yaw”) * (Time.deltaTime * RotationSpeed);
    AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
    rigidbody.rotation *= AddRot;
    Vector3 AddPos = Vector3.forward;
    AddPos = playerplane.rigidbody.rotation * AddPos;
    rigidbody.velocity = AddPos * (Time.deltaTime * AmbientSpeed);
    }
    }

    1. I think you should not mix physics (rigid body) with transform.
      Physics requires rigidbody.addforce or rigidbody.addtorque
      transform requires rotate and translate
      I think you should do a choice which system you use
      For starting I suggest you to use transform
      By the way 200 degrees/second is a very high rotation speed!
      I hope this will help…

      1. Thanks so much I’ll try and see if I can fix it haha 😛 I’m not a programmer but my team kind of elected me to be so I need to figure this out somehow xD Thanks again for responding I really appreciate it!

  13. Brilliant. Tried using physics (torque etc) but this is so much neater. I think the demo might need updating. Couldn’t find a project file it was expecting, tried opening the scene but nothing there, and the code includes obsolete calls. Doesn’t change that a simple copy and paste (and minor edits) got me up and running promptly. Thanks.

  14. In the latest version of Unity rigidbody.rotation *= AddRot; was getting spat out, turns out Unity likes to change how things works. Changing it to:

    GetComponent().rotation *= AddRot;

    fixed the error.

  15. using UnityEngine;
    using System.Collections;

    public class FlightScript : MonoBehaviour {

    public float AmbientSpeed = 100.0f;

    public float RotationSpeed = 100.0f;

    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }

    void FixedUpdate()
    {
    UpdateFunction();
    }

    void UpdateFunction()
    {

    Quaternion AddRot = Quaternion.identity;
    float roll = 0;
    float pitch = 0;
    float yaw = 0;
    roll = Input.GetAxis(“Roll”) * (Time.fixedDeltaTime * RotationSpeed);
    pitch = Input.GetAxis(“Pitch”) * (Time.fixedDeltaTime * RotationSpeed);
    yaw = Input.GetAxis(“Yaw”) * (Time.fixedDeltaTime * RotationSpeed);
    AddRot.eulerAngles = new Vector3(-pitch, yaw, -roll);
    GetComponent().transform.rotation *= AddRot;
    Vector3 AddPos = Vector3.forward;
    AddPos = GetComponent().transform.rotation * AddPos;
    GetComponent().velocity = AddPos * (Time.fixedDeltaTime * AmbientSpeed);
    }
    }

  16. Thnaks god youre my hero…I’ve struggled with 3d rotation problem for 2 days. Why I didn’t find this post ? How stupid…;D
    Below is my code, which adapts your algorithm

    private void Rotate()
    {
    float yaw = 0.0f;
    if(this.mYawLeft.pressed)
    {
    yaw -= 1.0f;
    }
    if(this.mYawRight.pressed)
    {
    yaw += 1.0f;
    }

    float roll = 0.0f;
    if(this.mRollLeft.pressed)
    {
    roll += 1.0f;
    }
    if(this.mRollRight.pressed)
    {
    roll -= 1.0f;
    }

    float pitch = 0.0f;
    if(this.mPitchUp.pressed)
    {
    pitch -= 1.0f;
    }
    if(this.mPitchDown.pressed)
    {
    pitch += 1.0f;
    }

    Quaternion addition = Quaternion.identity;
    addition.eulerAngles = new Vector3(pitch, yaw, roll);
    this.mPlayer.transform.rotation *= addition;
    }

    1. Hey man! Glad it could help! Don’t beat yourself up; if this stuff was trivial, we’d all be out of the job XD

      And thanks for posting your code. My code was written so long ago! Good to see it with a fresh coat of paint! Good job! Keep it up!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.