How can I improve my Jet Plane controls

I have a jet plane model with rigidbody and I created a simple controller

    void FixedUpdate()
    {
        //default velocity of aircraft velocity
         rb.velocity=transform.TransformDirection(defaultVelocity*Time.deltaTime);
        if(isMovementPressed)
        {
           
            //Rotating aircraft
            playerRotation = new Vector3(Movement.z, Movement.x, 0);
            rb.AddRelativeTorque(playerRotation * rotationSpeed * Time.deltaTime);

            //creating a turn during rotation

            rotationTurn = new Vector3(0, 0, -Movement.x);
            rb.transform.localEulerAngles += rotationTurn * rotationTurnSpeed * Time.deltaTime;
           
            //changing angular velocity to 0
            rb.angularVelocity = new Vector3(0,0,0);

           
        }
 

    }

How can I improve the controller

I forked and used this controller and it was pretty awesome:

https://github.com/kurtdekker/Aircraft-Physics

Comes with full source and handy editor extensions to edit your airplane.

But I want to learn to create my own and I don’t want that much complex!
Is my code okay? or could there be improvements?
Thank you

I would not recommend using eulerAngles… here’s why:

https://starmanta.gitbooks.io/unitytipsredux/content/second-question.html

But hey, if it plays well for you, go with it!

Here was my solution for ultra-simple-one-finger on phone.

You can play it in the Coinstorming modes of Pilot Kurt.

https://www.youtube.com/watch?v=RarIdj5DBN8

using UnityEngine;
using System.Collections;

public class FlightModelOriginal : FlightModel000
{
    FlightModelOriginalParameters fmop;

    public FlightControlInputs fci { get; private set; }

    float MaxAltitude = 100.0f;

    public static FlightModelOriginal AttachToStatePlayer ( FlightModelOriginalParameters fmop)
    {
        FlightModelOriginal fmo = STATE.pf.gameObject.AddComponent<FlightModelOriginal> ();
        fmo.fmop = fmop;
        return fmo;
    }

    public void DestroyThyself()
    {
        fci.DestroyThyself ();
        Destroy (this);
    }

    Vector3 TimeFilteredOutput;

    IEnumerator NoseOverAndDown( GameObject player)
    {
        Quaternion q1 = player.transform.rotation;
        Quaternion q2 = Quaternion.Euler (70, 0, 0);
        float NoseOverTime = 1.0f;
        for (float t = 0; t < NoseOverTime; t += Time.deltaTime)
        {
            float fr = t / NoseOverTime;
            player.transform.rotation = Quaternion.Lerp ( q1, q2, fr);
           
            player.transform.position += player.transform.forward *
                STATE.PlayerFlightSpeed * Time.deltaTime;
           
            yield return null;
        }
    }
   
    IEnumerator Start()
    {
        fci = FlightControlInputs.Attach (gameObject);

        TimeFilteredOutput = Vector3.zero;

        STATE.PlayerFlightSpeed = 10.0f;

        GameObject player = STATE.pf.gameObject;

        ServiceCeiling sc = FindObjectOfType<ServiceCeiling> ();
        if (sc)
        {
            MaxAltitude = sc.transform.position.y;
        }

// actual cheese main loop

        while(true)
        {
            STATE.UpdateCountersAndTimers ();
           
            if (GameModeManager.NeedSpeedIncreasing())
            {
                STATE.PlayerFlightSpeed += Time.deltaTime * 0.1f;
            }
           
            Vector3 rawOutput = fci.GetOutputRaw();

            rawOutput += new Vector3( Input.GetAxis( "Horizontal"), Input.GetAxis ( "Vertical"));
           
            if (SETTINGS.InvertXControls)
            {
                rawOutput.x = -rawOutput.x;
            }
            if (SETTINGS.InvertYControls)
            {
                rawOutput.y = -rawOutput.y;
            }
           
            TimeFilteredOutput = Vector3.Lerp(
                TimeFilteredOutput, rawOutput,
                fmop.ControlSnappiness * Time.deltaTime);
           
            float Roll = -TimeFilteredOutput.x;
           
            if (player.transform.position.y > MaxAltitude)
            {
                yield return StartCoroutine( NoseOverAndDown( player));
            }
           
            Roll *= fmop.RollMultiplier;
            Roll *= Time.deltaTime;
            player.transform.Rotate ( new Vector3( 0, 0, Roll));
           
            float Turn = -player.transform.eulerAngles.z;
            if (Turn < 180) Turn += 360;
            if (Turn > 180) Turn -= 360;
            Turn *= fmop.RollToTurnCoupling;
            Turn *= Time.deltaTime;
            player.transform.Rotate( new Vector3( 0, Turn, 0));
           
            float Pitch = TimeFilteredOutput.y;
           
            Pitch *= fmop.PitchMultiplier;
            Pitch *= Time.deltaTime;

            if (fmop.LimitPitchEnabled)
            {
                float xangle = player.transform.eulerAngles.x;
                if (xangle > 180) xangle -= 360.0f;
                if ((xangle < -fmop.LimitPitchAngle) &&
                   (Pitch < 0))
                {
                    Pitch = 0;
                }
                if ((xangle >  fmop.LimitPitchAngle) &&
                   (Pitch > 0))
                {
                    Pitch = 0;
                }
            }

            player.transform.Rotate ( new Vector3( Pitch, 0, 0));
           
            player.transform.position += player.transform.forward *
                STATE.PlayerFlightSpeed * Time.deltaTime;

            yield return null;
        }
    }
}

Here’s the necessary stuff from STATE:

    public static int score { get; private set; }
    public static int wave { get; private set; }
    public static float WaveTimer;
    public static int multiplier { get; private set; }
    public static int coinCount;
    public static float playTime;

    public static float MissionChronometer;
    public static float MissionOdometer;

    public static int MissionShotsFired;
    public static int MissionShotsHit;
    public static int MissionThingsDestroyed;

    public static float PlayerFlightSpeed;

This is the flight model params:

using UnityEngine;
using System.Collections;

public class FlightModelOriginalParameters
{
    public float ControlSnappiness;

    public float RollMultiplier;

    public float RollToTurnCoupling;

    public float PitchMultiplier;

    public bool LimitPitchEnabled;
    public float LimitPitchAngle;

    // <WIP> New stuff to implement:
    // Roll limit
    // Pitch limit

    public void ConfigureOriginal()
    {
        ControlSnappiness = 4.0f;
        RollMultiplier = 70.0f;
        RollToTurnCoupling = 0.5f;
        PitchMultiplier = 50.0f;
    }

    public void ConfigureFTUECanyon()
    {
        ConfigureOriginal ();

        RollMultiplier = 0.0f;
        RollToTurnCoupling = 0.0f;
        LimitPitchEnabled = true;
        LimitPitchAngle = 15.0f;
    }
}

Thank you so much :slight_smile:

1 Like

You’re welcome… arcade flight controls are easy enough to write, I’ve probably made like 100 of them.

Here’s an even-cheesier controller I made two weeks ago to fly around a PSX shader world I found from some random Youtube channel comment, I don’t even remember where the content was from.

using UnityEngine;

// @kurtdekker
// ultra-cheeseball flight control
// stick it on a blank GameObject in your scene
// make sure there is a MainCamera in the scene

public class PSFlight : MonoBehaviour
{
    float speed = 10;
    float roll = -80;
    float pitch = 60;

    Rigidbody rb;

    void Start()
    {
        rb = gameObject.AddComponent<Rigidbody>();
        rb.useGravity = false;

// will hijack the camera
        var cam = Camera.main;
        cam.transform.SetParent( transform);
        cam.transform.localPosition = Vector3.zero;
        cam.transform.localRotation = Quaternion.identity;
    }

    void FixedUpdate ()
    {
        float step = speed * Time.deltaTime;

        float xm = Input.GetAxis("Horizontal");
        float ym = Input.GetAxis("Vertical");

        var rot = rb.rotation;

        rot = rot * Quaternion.Euler( 0, 0, roll * xm * Time.deltaTime);
        rot = rot * Quaternion.Euler( pitch * ym * Time.deltaTime, 0, 0);

        rb.MoveRotation( rot);

        var pos = rb.position + transform.forward * step;

        rb.MovePosition( pos);
    }
}

This one’s better than mine ( Works better than rigidbody Torque and euler angles )
Thank you so much xD

Again, of course you’re welcome! I actually threw that one controller above into my Proximity Buttons project, along with a test procedurally-generated city to fly around.

There is also a first-person lunar lander controller in there, where you control a ship that has one giant rocket engine below it, and it can tilt itself to direct the jet. Here’s a video of it:

https://www.youtube.com/watch?v=Psks7SNj01U

Full source and demo scenes here:

https://bitbucket.org/kurtdekker/proximity_buttons

https://github.com/kurtdekker/proximity_buttons

https://gitlab.com/kurtdekker/proximity_buttons

https://sourceforge.net/projects/proximity-buttons/

1 Like