Search Unity

Two child transform collective forward direction

Discussion in 'Scripting' started by h0nka, Sep 19, 2017.

  1. h0nka

    h0nka

    Joined:
    Apr 7, 2013
    Posts:
    109
    Hi,

    I have a parent object with two children. One child rotates around its local y-axis and another around its local x-axis. I want to move the parent object in the forward direction of the two child object's collective forward direction. How can this be done?

    Thanks.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    It sounds like you're making a terrapin turtle!

    Rotating an object does not imply any distance unless you also have a radius in mind, i.e., the radius of the wheel.

    In that case, the motion would simply be the vector made up by the two axes coordinate values, and those values would be the rate of rotation times the radius. Post some code if you want some more specific pointers. Be sure to use code tags.
     
    h0nka likes this.
  3. h0nka

    h0nka

    Joined:
    Apr 7, 2013
    Posts:
    109
    Not so much a turtle as an aeroplane. I basically need to move the parent object forward, where forward is determined by the orientation of one (which is pitching) and another (which is yawing). Here is what I have now:

    Code (CSharp):
    1. void Start() {
    2.    
    3.         // Aircraft transform is comprised of a container (this.transform) and three child transforms
    4.         // to allow for independent local rotations.
    5.         yzTransform = this.gameObject.transform.GetChild(0);
    6.         xTransform = yzTransform.gameObject.transform.GetChild(0);
    7.         bodyTransform = xTransform.gameObject.transform.GetChild(0);
    8.     }
    9.  
    10.     void Update () {
    11.        
    12.         yaw = Input.GetAxis("Horizontal");
    13.         pitch = Input.GetAxis("Vertical");
    14.         roll = -yaw;
    15.  
    16.         if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
    17.         {
    18.             canRoll = true;
    19.         }
    20.         else
    21.             canRoll = false;
    22.  
    23.         RotateAircraft();
    24.         MoveAircraft();
    25.     }
    26.        
    27.     void RotateAircraft()
    28.     {
    29.         if (!canRoll)
    30.         {
    31.             // If roll-key is not pressed, yaw and pitch respective child transforms according to input.
    32.             yzTransform.Rotate(new Vector3(0, yaw * rotationSpeed * Time.deltaTime, 0));
    33.             xTransform.Rotate(new Vector3(pitch * rotationSpeed * Time.deltaTime, 0, 0));
    34.  
    35.             Debug.Log(roll);
    36.  
    37.             // Animate a slight tilt of the aircraft's body when yawing.
    38.             Quaternion modelRotation = bodyTransform.localRotation;
    39.             Quaternion toRotation = Quaternion.Euler(0f, 0f, roll * 30f);
    40.             bodyTransform.localRotation = Quaternion.Slerp(modelRotation, toRotation, Time.deltaTime * 10f);
    41.         }
    42.         else
    43.         {
    44.             // If roll-key is pressed allow only for rolling using horizontal input.
    45.             yzTransform.Rotate(new Vector3(0, 0, roll * rotationSpeed * Time.deltaTime));
    46.         }
    47.     }
    48.  
    49.     void MoveAircraft()
    50.     {
    51.         transform.position += // something...
    52.     }
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    That's even easier... just make your plane prefab so that forward is down the +Z axis... then when you move it, you just move it by transform.forward * airspeed and it will move correctly.

    In that sense, changes to pitch will be around the X axis, changes to roll will be around the Z axis, and yaw axis changes will be around the Y axis, and the Y axis is driven as a function of "how tight are you turning," which couples roll with nose pitch.

    It's a SUPER simple flight model, but it's fun on a touch screen with one finger. It's what I put in my Pilot Kurt game here:

    https://itunes.apple.com/us/app/pilot-kurt/id1153921946

    and

    https://play.google.com/store/apps/details?id=com.plbm.flight1

    It's not super-useful on its own, but here is the entire flight model Monobehavior if you wanna take a look:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FlightModelOriginal : FlightModel000
    6. {
    7.    FlightModelOriginalParameters fmop;
    8.  
    9.    public FlightControlInputs fci { get; private set; }
    10.  
    11.    float MaxAltitude = 100.0f;
    12.  
    13.    public static FlightModelOriginal AttachToStatePlayer ( FlightModelOriginalParameters fmop)
    14.    {
    15.        FlightModelOriginal fmo = STATE.pf.gameObject.AddComponent<FlightModelOriginal> ();
    16.        fmo.fmop = fmop;
    17.        return fmo;
    18.    }
    19.  
    20.    void Awake()
    21.    {
    22.        fci = FlightControlInputs.Attach (gameObject);
    23.  
    24.        TimeFilteredOutput = Vector3.zero;
    25.      
    26.        STATE.PlayerFlightSpeed = 10.0f;
    27.    }
    28.  
    29.    public void DestroyThyself()
    30.    {
    31.        fci.DestroyThyself ();
    32.        Destroy (this);
    33.    }
    34.  
    35.    Vector3 TimeFilteredOutput;
    36.  
    37.    IEnumerator NoseOverAndDown( GameObject player)
    38.    {
    39.        Quaternion q1 = player.transform.rotation;
    40.        Quaternion q2 = Quaternion.Euler (70, 0, 0);
    41.        float NoseOverTime = 1.0f;
    42.        for (float t = 0; t < NoseOverTime; t += Time.deltaTime)
    43.        {
    44.            float fr = t / NoseOverTime;
    45.            player.transform.rotation = Quaternion.Lerp ( q1, q2, fr);
    46.          
    47.            player.transform.position += player.transform.forward *
    48.                STATE.PlayerFlightSpeed * Time.deltaTime;
    49.          
    50.            yield return null;
    51.        }
    52.    }
    53.  
    54.    IEnumerator Start()
    55.    {
    56.        GameObject player = STATE.pf.gameObject;
    57.  
    58.        ServiceCeiling sc = FindObjectOfType<ServiceCeiling> ();
    59.        if (sc)
    60.        {
    61.            MaxAltitude = sc.transform.position.y;
    62.        }
    63.  
    64.        while(true)
    65.        {
    66.            STATE.UpdateCountersAndTimers ();
    67.          
    68.            if (GameModeManager.NeedSpeedIncreasing())
    69.            {
    70.                STATE.PlayerFlightSpeed += Time.deltaTime * 0.1f;
    71.            }
    72.          
    73.            Vector3 rawOutput =fci.GetOutputRaw();
    74.  
    75.            rawOutput += new Vector3( Input.GetAxis( "Horizontal"), Input.GetAxis ( "Vertical"));
    76.          
    77.            if (SETTINGS.InvertXControls)
    78.            {
    79.                rawOutput.x = -rawOutput.x;
    80.            }
    81.            if (SETTINGS.InvertYControls)
    82.            {
    83.                rawOutput.y = -rawOutput.y;
    84.            }
    85.          
    86.            TimeFilteredOutput = Vector3.Lerp(
    87.                TimeFilteredOutput, rawOutput,
    88.                fmop.ControlSnappiness * Time.deltaTime);
    89.          
    90.            float Roll = -TimeFilteredOutput.x;
    91.          
    92.            if (player.transform.position.y > MaxAltitude)
    93.            {
    94.                yield return StartCoroutine( NoseOverAndDown( player));
    95.            }
    96.          
    97.            Roll *= fmop.RollMultiplier;
    98.            Roll *= Time.deltaTime;
    99.            player.transform.Rotate ( new Vector3( 0, 0, Roll));
    100.          
    101.            float Turn = -player.transform.eulerAngles.z;
    102.            if (Turn < 180) Turn += 360;
    103.            if (Turn > 180) Turn -= 360;
    104.            Turn *= fmop.RollToTurnCoupling;
    105.            Turn *= Time.deltaTime;
    106.            player.transform.Rotate( new Vector3( 0, Turn, 0));
    107.          
    108.            float Pitch = TimeFilteredOutput.y;
    109.          
    110.            Pitch *= fmop.PitchMultiplier;
    111.            Pitch *= Time.deltaTime;
    112.  
    113.            if (fmop.LimitPitchEnabled)
    114.            {
    115.                float xangle = player.transform.eulerAngles.x;
    116.                if (xangle > 180) xangle -= 360.0f;
    117.                if ((xangle < -fmop.LimitPitchAngle) &&
    118.                    (Pitch < 0))
    119.                {
    120.                    Pitch = 0;
    121.                }
    122.                if ((xangle >  fmop.LimitPitchAngle) &&
    123.                    (Pitch > 0))
    124.                {
    125.                    Pitch = 0;
    126.                }
    127.            }
    128.  
    129.            player.transform.Rotate ( new Vector3( Pitch, 0, 0));
    130.          
    131.            player.transform.position += player.transform.forward *
    132.                STATE.PlayerFlightSpeed * Time.deltaTime;
    133.  
    134.            yield return null;
    135.        }
    136.    }
    137. }
    You can pretty much delete a lot of that code and stick it on your camera in a scene with your terrain and use the default Unity input axes to control your airplane.

    There is no notion of energy at this point. It just goes and goes, climbing or descending.
     
  5. h0nka

    h0nka

    Joined:
    Apr 7, 2013
    Posts:
    109
    Yes. I understand that I have to move the parent along a forward vector, the problem is that the parent itself does not actually yaw and pitch. One child yaws and the child of that child does the pitching. So my question is: how do I from the parent move the aircraft so that forward is determined by the rotation of the children collectively?
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Components of rotation are not commutative, that is, their order matters. Your keeping the axes of rotation as separate transforms is interesting, but they still need to be combined, generally by a quaternion multiply, to do something useful.

    But again, that is not commutative, except for identity values, which are trivial and irrelevant here.
     
  7. h0nka

    h0nka

    Joined:
    Apr 7, 2013
    Posts:
    109
    Oh ok. I guess I will go back to trying to achieve something similar to what i have within a single transform then. Thanks for the help!