0
\$\begingroup\$

I have made a drone script that allows user to move in four directions and ascend/descend.
I found a nice tilt snippet which makes the thing bank when it moves. However, when I include this, the rotation I input using "f" and "h" keys works but the drone snaps back to it's original orientation (not position in space, but the angle of the object on the Y axis).

I would like to be able to bank and also rotate the drone, what should I change?
Here is the C# script attached to the drone:

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour 
{
    public float speed;
    public float tilt;
    public float power;

    /** 
     * Every update perform tranlations and rotations based on user input.
     * */
    void FixedUpdate () 
    {
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
        rigidbody.velocity = movement * speed;

        // Add the tilt. (When this line is left out, rotation performs as expected)
        // When it is left in, the drone rotates but snaps back to it's original orientation on key release.
        rigidbody.rotation = Quaternion.Euler (rigidbody.velocity.z, 0.0f, rigidbody.velocity.x * -tilt);

        // Ascend.
        if (Input.GetKey ("t"))
        {
            rigidbody.AddRelativeForce (Vector3.up * power);
        }

        // Descend.
        if (Input.GetKey ("g")) {
            rigidbody.AddRelativeForce (Vector3.down * power);
        }

        // Rotate clockwise.
        if (Input.GetKey ("h")) 
        {
            transform.Rotate(0, 5, 0, Space.Self);
        }

        // Rotate anti-clockwise.
        if (Input.GetKey ("f")) 
        {
            transform.Rotate(0, -5, 0, Space.Self);
        }
    }
}

Maybe also worth noting that when I leave the tilt line in, any rotation I apply to the drone in transform properties is not applied, when taken out, I can set the starting orientation fine.

\$\endgroup\$
  • \$\begingroup\$ Do you mean the drone "snaps back to its original position" as in it translates through space back to the place where it started, or that it snaps back to its original orientation, meaning that it stays where it is but snaps back upright? \$\endgroup\$ – DMGregory Jan 21 '15 at 15:06
  • \$\begingroup\$ The position in space stays the same, but the translation on the Y axis (the one I rotate on) snaps back to the direction the drone was facing upon releasing the key. Has it something to do with the 0.0f in the "tilt" line? When I release h or f, I want the drone to remain still, not snap back to it's starting angle. \$\endgroup\$ – Ḟḹáḿíṅḡ Ⱬỏḿƀíé Jan 21 '15 at 15:17
  • \$\begingroup\$ You have to be very careful with your terminology when talking about transformations in space. "Translation" and "position" refer to where an object is in space. "Rotation" and "orientation" refer to the way an object is facing. Flipping these terms will get you unhelpful answers. ;) \$\endgroup\$ – DMGregory Jan 21 '15 at 15:19
  • \$\begingroup\$ Sorry, good points, I have updated my question \$\endgroup\$ – Ḟḹáḿíṅḡ Ⱬỏḿƀíé Jan 21 '15 at 15:24
1
\$\begingroup\$

Your tilt line is stomping over whatever rotation the drone had and applying a new one. Just like writing:

variable_a = 42;

will replace whatever value was in variable_a before, the same happens with rotations, unless you use some type of combining operator like multiplication or Lerp.

To fix this, you can build a rotation that takes both inputs into account and apply it once.

But I think the clearest way to do it is with a transform hierarchy. In your hierarchy view, parent some objects so that it looks like this:

Drone (Contains rigidbody and control script)
 -> DroneBody (Contains rendered geometry, colliders...)

Modify your script so that in Start() you store a reference to the DroneBody object...

_droneBody = transform.Find("DroneBody");

Then change your tilt line to....

Vector3 localVelocity = transform.InverseTransformDirection(rigidbody.velocity);
_droneBody.localRotation = Quaternion.Euler (localVelocity.z, 0.0f, localVelocity.x * -tilt);

This way your yaw code (on the "f" and "h" keys) isn't fighting over the same rotation that your tilt is modifying. Yaw happens at the parent level, and tilt happens at the child level. (This will still stomp any inspector rotation you use at the child level, mind)

(The addition of localVelocity ensures that the drone bank direction changes correctly as the drone yaws around, rather than being backwards after the drone has made a U-turn)

\$\endgroup\$
  • \$\begingroup\$ This concept worked very well for me and I will remember the concepts for the future, thank you. I also had to declare public Transform _droneBody; for it to work. \$\endgroup\$ – Ḟḹáḿíṅḡ Ⱬỏḿƀíé Jan 21 '15 at 16:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.