AddRelativeForce introduces rotation

Hi,

I have a simple function to move my spaceship:

public class ShipMovement : MonoBehaviour {
    public float shipDensity = 1.1f;
    public float thrustMainEngine = 100f;
    public int engineCountMain = 3;
    public float warmupTimeMainEngine = 5;

    private IEnumerator startCoroutineForward;
    private float thrustCurrentForward = 0f;
    KeyCode kcForward = KeyCode.W;

    void Start () {
        rb = GetComponent<Rigidbody> ();
        controlsEnabled = true;
        rb.SetDensity (shipDensity);
    }

    void Update {
            if (Input.GetKeyDown (kcForward)) {
                startCoroutineForward = StartForward ();
                StartCoroutine (startCoroutineForward);
            }
            if (Input.GetKeyUp (kcForward)) {
                StopCoroutine (startCoroutineForward);
                thrustCurrentForward = 0f;
            }
    }

    void FixedUpdate () {
            if (Input.GetKey (kcForward)) {
                rb.AddRelativeForce (Vector3.forward * thrustCurrentForward);
            }

    }

    private IEnumerator StartForward () {
        float thrustMaxForward = thrustMainEngine * engineCountMain;
        var passedTimeForward = 0.0f;
        while (passedTimeForward < warmupTimeMainEngine) {
            passedTimeForward += Time.deltaTime;
            thrustCurrentForward = thrustMaxForward * passedTimeForward / warmupTimeMainEngine;
            yield return null;
        }
    }
}

Every now and then, when I press W, the ship starts rotating, instead of just accelerating forward.

Any idea why would that be?

Not code issue, this will not turn your ship by itself.

Anyway this code has some errors, but it wont fix the rotation since it doesn’t rotate the object :slight_smile:

1.- startCoroutineForward field is useless. Just call directly StartCoroutine(StartForward());, and StopCoroutine(StartForward());

2.- Never use Input on FixedUpdate, you have an explanation of why you can’t use it here .

We need more info, for help with the rotation issue.

Did you change the center of mass on the rigidbody or anything?, I don’t see why this script will rotate the ship.
What’s the rest of the setup?, maybe you have some colliders overlapping and creating a phantom force or something.

Using GetKey in fixed update is fine, the problem is the the Up/Down variants.

1 Like

Ye completely logic, didn’t though about. TY

You guys are awesome. @SparrowsNest what is with Up/Down variants? I present just forward movement, as it’s the only one causing the rotation, I have identical functions moving and rotating ship in all other axes, but it’s only forward which is misbehaving. Also, I have tried to remove all colliders but one box, and it didn’t help.
@rubcc95 thank you for the note on Coroutines!

Another issue is, the behaviour is not predictable. I can press W multiple times, and it just accelerates, and once in a while, it’ll kick in the rotation :confused:

GetKey will return true as long as the key is held down
GetKeyDown will return true only on the main Update() frame after the button was pressed
GetKeyUp will return true only on the main Update() frame after the button was released

because the Up/Down are updated based on the normal Update you can miss a call if you look for them in the FixedUpdate

Or so you think, post the full script.
Maybe one of your rotation functions listens for the forward key by accident?

From what you posted this shouldn’t happen, but you can see what’s going on by scattering Debug.Logs everywhere to see what you code is actually doing (instead of what you’re thinking it’s doing)

@SparrowsNest if you’d be so kind as to have a look at the file, I’ll be grateful.
I’m not gonna pretend I’m a professional programmer, also, I’m a Pythonista, so C# is not my weapon of choice.
If you’ll notice any obvious (or not so obvious, for that matter) idiocy I did, I’ll happily correct my ways.

7104403–847057–ShipMovement.cs (16.4 KB)

First of all remove “idiotic” coroutines.
Second your update should look something like this

    void Update {
IsMovingForward =  Input.GetKeyDown (kcForward));

   }


  void FixedUpdate () {
          If(IsMovingForward){
            rb.AddRelativeForce (Vector3.forward * acceleration,ForceMode.Acceleration);
           }

   }

@koirat what problem is with my coroutines, I wonder? As you can see, I removed the coroutine in the forward movement, and it didn’t stop the rotation. The buildup of the thrust is in agreement with the physics of the rocket engine, I thought it would be fun to have it implemented.
Also, would you mind pointing me to some explanation as to what is the benefit of introducing the “IsMovingForward” variable?

Is your spaceship made out of multiple rigidbodies connected with joints this may change the center of gravity.
The fact is that your movement code and input code should be separated.
In ShipMovement there should be no Input of any kind only variables that are stating current movement process like MoveForward etc.

I’ll be happy to take a look, but post the code like you did before, nobody wants to download random scripts from the internet.
While you’re at it show us the full setup of the ship.

Like @koirat said, the coroutines are pretty “non-optimal”, I guess
I didn’t say anything because they’re logically correct, but they’re just a waste of resources, there is no actual need for them here.

Is your ship made of multiple rigidbodies or multiple colliders?
Show the full setup of the ship (snap a screenshot of the editor with the ships hierarchy open)

Looks like there is a lot of learning for me to do a simple thing like moving the ship forward :slight_smile:
Thank you guys for taking your time to help me.

@koirat - is there anywhere available setup as you describe it? With input defined in the script other than one driving forces?
@SparrowsNest The script (with coroutines already removed - so it’s shorter):

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

// Acceleration = Force / Mass
// Angular Acceleration = Torque / Inertia
/* Ensure that your ship contains a collider or set of colliders resembling all its volume,
or configure the inertia manually in Rigidbody.inertiaTensor and Rigidbody.inertiaTensorRotation. */

public class ShipMovement : MonoBehaviour {

    Rigidbody rb;

    [Header ("Ship density")]
    public float shipDensity = 1.1f;

    [Header ("Available thrust")]
    public float thrustMainEngine = 100f;
    public float thrustManeuveringJet = 10f;

    [Header ("Engine count")]
    public int engineCountMain = 3;
    public int engineCountManeuveringTopAndBottom = 4;
    public int engineCountManeuveringSide = 2;

    [Header ("Engine warmup time")]
    public float warmupTimeMainEngine = 5;
    public float warmupTimeManeuvringEngine = 1;

    /*---------------- Translation -------------------*/
    //Forward
    private float thrustCurrentForward = 0f;
    KeyCode kcForward = KeyCode.W;

    //Backward
    private float thrustCurrentBack = 0f;
    KeyCode kcBackward = KeyCode.S;

    //Strife Left
    private float thrustCurrentLeft = 0f;
    KeyCode kcStrifeLeft = KeyCode.A;

    //Strife Right
    private float thrustCurrentRight = 0f;
    KeyCode kcStrifeRight = KeyCode.D;

    //Strife Up
    private float thrustCurrentUp = 0f;
    KeyCode kcStrifeUp = KeyCode.Space;

    //Strife Down
    private float thrustCurrentDown = 0f;
    KeyCode kcStrifeDown = KeyCode.Keypad0;

    /*---------------- Rotation -------------------*/
    //Yaw Clock
    private float torqueCurrentYawClock = 0f;
    KeyCode kcYawClock = KeyCode.E;

    //Yaw Anti Clock
    private float torqueCurrentYawAntiClock = 0f;
    KeyCode kcYawAntiClock = KeyCode.Q;

    //Roll Clock
    private float torqueCurrentRollClock = 0f;
    KeyCode kcRollClock = KeyCode.Keypad6;

    //Roll Anti Clock
    private float torqueCurrentRollAntiClock = 0f;
    KeyCode kcRollAntiClock = KeyCode.Keypad4;

    //Pitch Up
    private float torqueCurrentPitchUp = 0f;
    KeyCode kcPitchUp = KeyCode.Keypad5;

    //Pitch Down
    private float torqueCurrentPitchDown = 0f;
    KeyCode kcPitchDown = KeyCode.Keypad8;

    public bool controlsEnabled;

    // Start is called before the first frame update
    void Start () {
        rb = GetComponent<Rigidbody> ();
        controlsEnabled = true;
        rb.SetDensity (shipDensity);
    }

    void Update () {
        if (controlsEnabled) {
            /* ------------------- THRUST CONTROL---------------------- */
            // Forward
            if (Input.GetKeyDown (kcForward)) {
                thrustCurrentForward = thrustMainEngine * engineCountMain;
            }
            if (Input.GetKeyUp (kcForward)) {
                thrustCurrentForward = 0f;
            }

            // Backward
            if (Input.GetKeyDown (kcBackward)) {
                thrustCurrentBack = thrustManeuveringJet * engineCountManeuveringSide;
            }
            if (Input.GetKeyUp (kcBackward)) {
                thrustCurrentBack = 0f;
            }

            // Strife Left
            if (Input.GetKeyDown (kcStrifeLeft)) {
                thrustCurrentLeft = thrustManeuveringJet * engineCountManeuveringSide;
            }
            if (Input.GetKeyUp (kcStrifeLeft)) {
                thrustCurrentLeft = 0f;
            }

            // Strife Right
            if (Input.GetKeyDown (kcStrifeRight)) {
                thrustCurrentRight = thrustManeuveringJet * engineCountManeuveringSide;
            }
            if (Input.GetKeyUp (kcStrifeRight)) {
                thrustCurrentRight = 0f;
            }

            // Strife Up
            if (Input.GetKeyDown (kcStrifeUp)) {
                thrustCurrentUp = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
            }
            if (Input.GetKeyUp (kcStrifeUp)) {
                thrustCurrentUp = 0f;
            }

            // Strife  Down
            if (Input.GetKeyDown (kcStrifeDown)) {
                thrustCurrentDown = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
            }
            if (Input.GetKeyUp (kcStrifeDown)) {
                thrustCurrentDown = 0f;
            }
            /* ------------------- TORQUE CONTROL---------------------- */
            // Yaw Clock
            if (Input.GetKeyDown (kcYawClock)) {
                StartCoroutine (StartYawClock ());
            }
            if (Input.GetKeyUp (kcYawClock)) {
                StopCoroutine (StartYawClock ());
                torqueCurrentYawClock = 0f;
            }

            // Yaw Anti Clock
            if (Input.GetKeyDown (kcYawAntiClock)) {
                StartCoroutine (StartYawAntiClock ());
            }
            if (Input.GetKeyUp (kcYawAntiClock)) {
                StopCoroutine (StartYawAntiClock ());
                torqueCurrentYawAntiClock = 0f;
            }

            // Roll Clock
            if (Input.GetKeyDown (kcRollClock)) {
                StartCoroutine (StartRollClock ());
            }
            if (Input.GetKeyUp (kcRollClock)) {
                StopCoroutine (StartRollClock ());
                torqueCurrentRollClock = 0f;
            }

            // Roll Anti Clock
            if (Input.GetKeyDown (kcRollAntiClock)) {
                StartCoroutine (StartRollAntiClock ());
            }
            if (Input.GetKeyUp (kcRollAntiClock)) {
                StopCoroutine (StartRollAntiClock ());
                torqueCurrentRollAntiClock = 0f;
            }

            // Pitch Up
            if (Input.GetKeyDown (kcPitchUp)) {
                StartCoroutine (StartPitchUp ());
            }
            if (Input.GetKeyUp (kcPitchUp)) {
                StopCoroutine (StartPitchUp ());
                torqueCurrentPitchUp = 0f;
            }

            // Pitch Down
            if (Input.GetKeyDown (kcPitchDown)) {
                StartCoroutine (StartPitchDown ());
            }
            if (Input.GetKeyUp (kcPitchDown)) {
                StopCoroutine (StartPitchDown ());
                torqueCurrentPitchDown = 0f;
            }

        }
    }

    // Update is called once per frame
    void FixedUpdate () {
        if (controlsEnabled) {
            /* ------------------- THRUST CONTROL ---------------------- */
            // Forward
            if (Input.GetKey (kcForward)) {
                rb.AddRelativeForce (Vector3.forward * thrustCurrentForward);
                // Debug.Log ("Forward");
            }

            // Backward
            if (Input.GetKey (kcBackward)) {
                rb.AddRelativeForce (Vector3.back * thrustCurrentBack);
                // Debug.Log ("Backward");
            }

            // Strife Left
            if (Input.GetKey (kcStrifeLeft)) {
                rb.AddRelativeForce (Vector3.left * thrustCurrentLeft);
                // Debug.Log ("StrafeLeft");
            }

            // Strife Right
            if (Input.GetKey (kcStrifeRight)) {
                rb.AddRelativeForce (Vector3.right * thrustCurrentRight);
                // Debug.Log ("StrafeRight");
            }

            // Strife Up
            if (Input.GetKey (kcStrifeUp)) {
                rb.AddRelativeForce (Vector3.up * thrustCurrentUp);
                // Debug.Log ("StrifeUp");

            }

            // Strife Down
            if (Input.GetKey (kcStrifeDown)) {
                rb.AddRelativeForce (Vector3.down * thrustCurrentDown);
                // Debug.Log ("StrafeDown");
            }

            /* ------------------- TORQUE CONTROL---------------------- */
            // Yaw Clock
            if (Input.GetKey (kcYawClock)) {
                rb.AddRelativeTorque (Vector3.up * torqueCurrentYawClock);
                // Debug.Log ("YawClock!");

            }

            // Yaw Anti Clock
            if (Input.GetKey (kcYawAntiClock)) {
                rb.AddRelativeTorque (Vector3.up * torqueCurrentYawAntiClock);
                // Debug.Log ("YawAntiClock!");
            }

            // Roll Clock
            if (Input.GetKey (kcRollClock)) {
                rb.AddRelativeTorque (Vector3.forward * torqueCurrentRollClock);
                // Debug.Log ("RollClock!");
            }

            // Roll Anti Clock
            if (Input.GetKey (kcRollAntiClock)) {
                rb.AddRelativeTorque (Vector3.forward * torqueCurrentRollAntiClock);
                // Debug.Log ("RollAntiClock!");
            }

            // Pitch Up
            if (Input.GetKey (kcPitchUp)) {
                rb.AddRelativeTorque (Vector3.left * torqueCurrentPitchUp);
                // Debug.Log ("PitchUP!");
            }

            // Pitch Down
            if (Input.GetKey (kcPitchDown)) {
                rb.AddRelativeTorque (Vector3.left * torqueCurrentPitchDown);
                // Debug.Log ("PitchDown!");
            }

        }
    }
    /* ------------------- TORQUE CONTROL---------------------- */

    private IEnumerator StartYawClock () {
        float torqueCurrentYawClock = thrustManeuveringJet * engineCountManeuveringSide;
        if (Input.GetKey (kcStrifeLeft) && Input.GetKey (kcStrifeRight)) {
                torqueCurrentYawClock = 0f;
        } else if (Input.GetKey (kcStrifeLeft) || Input.GetKey (kcStrifeRight)) {
                torqueCurrentYawClock = torqueCurrentYawClock / 2;
        }
        yield return null;
    }

    private IEnumerator StartYawAntiClock () {
        float torqueCurrentYawAntiClock = thrustManeuveringJet * engineCountManeuveringSide;
        if (Input.GetKey (kcStrifeLeft) && Input.GetKey (kcStrifeRight)) {
            torqueCurrentYawAntiClock = 0f;
        } else if (Input.GetKey (kcStrifeLeft) || Input.GetKey (kcStrifeRight)) {
            torqueCurrentYawAntiClock = torqueCurrentYawAntiClock / 2;
        }
        yield return null;
    }

    private IEnumerator StartRollClock () {
        float torqueCurrentRollClock = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
        if (Input.GetKey (kcStrifeUp) && Input.GetKey (kcStrifeDown)) {
            torqueCurrentRollClock = 0f;
        } else if (Input.GetKey (kcStrifeUp) || Input.GetKey (kcStrifeDown)) {
            torqueCurrentRollClock = torqueCurrentRollClock / 2;
        }
        yield return null;
    }

    private IEnumerator StartRollAntiClock () {
        float torqueCurrentRollAntiClock = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
        if (Input.GetKey (kcStrifeUp) && Input.GetKey (kcStrifeDown)) {
            torqueCurrentRollAntiClock = 0f;
        } else if (Input.GetKey (kcStrifeUp) || Input.GetKey (kcStrifeDown)) {
            torqueCurrentRollAntiClock = torqueCurrentRollAntiClock / 2;
        }
        yield return null;
    }

    private IEnumerator StartPitchUp () {
        float torqueCurrentPitchUp = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
        if (Input.GetKey (kcStrifeUp) && Input.GetKey (kcStrifeDown)) {
            torqueCurrentPitchUp = 0f;
        } else if (Input.GetKey (kcStrifeUp) || Input.GetKey (kcStrifeDown)) {
            torqueCurrentPitchUp = torqueCurrentPitchUp / 2;
        }
        yield return null;
    }

    private IEnumerator StartPitchDown () {
        float torqueCurrentPitchDown = thrustManeuveringJet * engineCountManeuveringTopAndBottom;
        if (Input.GetKey (kcStrifeUp) && Input.GetKey (kcStrifeDown)) {
            torqueCurrentPitchDown = 0f;
        } else if (Input.GetKey (kcStrifeUp) || Input.GetKey (kcStrifeDown)) {
            torqueCurrentPitchDown = torqueCurrentPitchDown / 2;
        }
        yield return null;
    }
}

I also attach the screenshot.