Home > Blockchain >  Unity3d script applying rotation twice?
Unity3d script applying rotation twice?

Time:06-02

I have been working on a simple space vehicle controller that allows for movement, yaw, roll, and pitch. it works great on each axis individually, but when I both yaw and roll, pitch and move, etc. the rotations are incorrct. I believe something is happening twice, because when the vehicle is at a 90 degree angle of pitch it moves horizontally when it should move vertically (90 degrees off at 90 degrees rotation). AT 45 it is somwhere in the middle. At 0 it works as expected.

My full code is below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player_Input : MonoBehaviour
{

    private Rigidbody rb;
    public float moveAcceleration = 50f;
    public float maxMoveSpeed = 500f;
    public float turnAcceleration = 30f;
    public float maxTurnSpeed = 100f;
    public float rotAcceleration = 30f;
    public float maxRotSpeed = 100f;

    private float moveSpeed = 0;
    private float pitchSpeed = 0;
    private float yawSpeed = 0;
    private float rollSpeed = 0;
    private Vector3 angle = new Vector3 (0, 0, 0);

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey("w")) {
            moveSpeed  = moveAcceleration * Time.deltaTime;
        } else if(Input.GetKey("s")) {
            moveSpeed -= moveAcceleration * Time.deltaTime;
        }

        if(moveSpeed > 10f) {
            moveSpeed -= 5f * Time.deltaTime;
        }else if(moveSpeed < -10f) {
            moveSpeed  = 5f * Time.deltaTime;
        } else if(!Input.GetKey("w") && !Input.GetKey("s")) {
            moveSpeed = 0f;
        }

        moveSpeed = Mathf.Clamp(moveSpeed, -maxMoveSpeed, maxMoveSpeed);


        if(Input.GetKey("a")) {
            yawSpeed  = turnAcceleration * Time.deltaTime;
        } else if(Input.GetKey("d")) {
            yawSpeed -= turnAcceleration * Time.deltaTime;
        }       

        if(yawSpeed > 10f) {
            yawSpeed -= 5f * Time.deltaTime;
        }else if(yawSpeed < -10f) {
            yawSpeed  = 5f * Time.deltaTime;
        } else if(!Input.GetKey("a") && !Input.GetKey("d")) {
            yawSpeed = 0f;
        }

        yawSpeed = Mathf.Clamp(yawSpeed, -maxTurnSpeed, maxTurnSpeed);

        if(Input.GetKey("left")) {
            rollSpeed  = rotAcceleration * Time.deltaTime;
        } else if(Input.GetKey("right")) {
            rollSpeed -= rotAcceleration * Time.deltaTime;
        }        

        if(rollSpeed > 10f) {
            rollSpeed -= 5f * Time.deltaTime;
        }else if(rollSpeed < -10f) {
            rollSpeed  = 5f * Time.deltaTime;
        } else if(!Input.GetKey("left") && !Input.GetKey("right")) {
            rollSpeed = 0f;
        }

        rollSpeed = Mathf.Clamp(rollSpeed, -maxRotSpeed, maxRotSpeed);

        if(Input.GetKey("up")) {
            pitchSpeed  = turnAcceleration * Time.deltaTime;
        } else if(Input.GetKey("down")) {
            pitchSpeed -= turnAcceleration * Time.deltaTime;
        }        

        if(pitchSpeed > 10f) {
            pitchSpeed -= 5f * Time.deltaTime;
        }else if(pitchSpeed < -10f) {
            pitchSpeed  = 5f * Time.deltaTime;
        } else if(!Input.GetKey("up") && !Input.GetKey("down")) {
            pitchSpeed = 0f;
        }

        pitchSpeed = Mathf.Clamp(pitchSpeed, -maxTurnSpeed, maxTurnSpeed);


        this.transform.Translate(moveSpeed * transform.forward * Time.deltaTime);
        angle  = Time.deltaTime * ((pitchSpeed * transform.right)   (rollSpeed * transform.forward)   (yawSpeed * transform.up));
        //Debug.Log(transform.forward);
        this.transform.eulerAngles = angle;

    }
}

The relevant bit is at the end (acceleration and such work as intended), just where the angles are set. The transforms are correct (I have checked), but the movements applied are not. Do you see the issue?

Thanks, I apreciate it!

Edit: there is also only 1 instance of the script on the GameObject, just to narrow it down a little more.

Edit 2: I found this forum post that seems to have the same issue, but I don't think I have done the same thing that this person has. Maybe a good starting place?

Edit 3: I feel like the "angle = ..." line is the culprit, but I can't tell why. Maybe look there.

CodePudding user response:

Use the Quaterion class to avoid gimbal lock and multiply the current rotation with the new additional rotation. I've modified the last few lines of your script:

> angle = new Vector3(pitchSpeed, yawSpeed, rollSpeed);
> transform.rotation *= Quaternion.Euler(angle);
> transform.Translate(moveSpeed * transform.forward * Time.deltaTime, Space.World);

You'll want to greatly reduce these, I divided them by 10 which seemed pretty smooth:

public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;

Not sure if you wanted the yaw to be in the direction pressed or inverted, currently if you press left it yaws right, you can invert these if required:

if(Input.GetKey("a")) {
   yawSpeed  = turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
   yawSpeed -= turnAcceleration * Time.deltaTime;
}  

If you're making a space game you might want to consider smoothing out moveSpeed , pitchSpeed, yawSpeed, rollSpeed with https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html or https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html to make the motions more realistic.

  • Related