Which of these methods is the best for moving a spaceplane?

Hi!

So lately I’ve been making a script that controls a space plane. It is for mobile, so it doesn’t have to be 100% realistic. I have a joystick that determines direction and a slider that determines speed.

First, I went with something like Rigidbody.AddForce(transform.forward * Time.deltaTime*speed). This worked, but made for very slow gameplay because most of the time when playing I’d have to try to counter old forces. While probably the most realistic for a space plane, it makes for some horrible gameplay.

Second, I went to Transform.Translate(transform.forward * Time.deltaTime*speed). This worked pretty well, while pretty unrealistic it was much better than my older method. However if I crash into objects at high speed, the plane will go right thru them. While in-game I’d probably destroy the plane, this could lead to some considerable bugs. After considerable tweaking I could probably get it to work.

So today I wanted to make the plane flip and accidentally ran into Rigidbody.AddForce(speed, 0, 0, ForceMode.Impulse). This looked pretty interesting. After more testing, I noticed that Rigidbody.AddForce also works better with collisions. So now I’m interested in re-writing my script to use the 3rd method.

Before I invest a lot of time into that, what is your opinion? If you were in my spot, would you use the 3rd method, or would you try something else?

Thank you for any suggestions!

rigidbody.moveposition

its like translate, but for physics.

make sure you use it fixedupdate

This is way of using AddForce is incorrect. You shouldn’t use deltaTime here. Also, speed is incorrect because you’re aplying a force (N, newtons), not a speed (m/s, meters per second).

I’m not sure on what are you trying to do exactly, but this would be more correct when used within FixedUpdate:

Rigidbody.AddForce (transform.forward * forceAmount);

This applies a force of “forceAmount” newtons in the forward direction of your object.

Yeah sorry for the confusion, I shouldn’t have called it speed because it is adding force. That’s why I got a B in physics class :frowning:

I’ll start modifying my script to use AddForce

Currently this is the state of my script. Feeling proud but something tells me I’m doing this badly lol

Feel free to take a look if interested. Perhaps it might be useful for your projects

using UnityEngine;
using System.Collections;

public class TransformController : MonoBehaviour {

    //using default joystick
    public UnityStandardAssets.CrossPlatformInput.Joystick joystick;
    //joystick positions
    public float Joyx = 0, Joyy = 0;
    //original position of joystick
    public Vector3 OrigPos;
    //current position of joystick
    public Vector3 CurrPos;
    //difference--how much the joystick has moved compared to original position
    public float DiffX;
    public float DiffY;
    //ratio of current difference and max possible difference
    //used to calculate how fast to move the plane based on how much the joystick is moved
    public float DiffXRatio;
    public float DiffYRatio;
    //how much the joystick moves from the center
    public float MovementRange;
    //max speed the plane moves forward
    public float MaxForwardSpeed;
    //max speed the plane moves sideways
    public float MaxHorizontalSpeed;
    //slider that decides forward speed
    public SpeedSlider SpeedSlider;
    //will decide how to control plane once on land LATER
    public bool LandingStatus;
    private Rigidbody Rigid;

    // Use this for initialization
    void Start ()
    {
        //set original joystick position
        OrigPos = joystick.transform.position;
        Rigid = this.gameObject.GetComponent<Rigidbody>();
    }
   
    // Update is called once per frame
    void FixedUpdate ()
    {
        Joyx = joystick.transform.position.x;
        Joyy = joystick.transform.position.y;
        //find the diffirence of joystick position
        DiffX = Joyx - OrigPos.x;
        DiffY = Joyy - OrigPos.y;
        //now find the ratio
        DiffXRatio = DiffX / joystick.MovementRange;
        DiffYRatio = DiffY / joystick.MovementRange;
        CurrPos = joystick.transform.position;
        //now that we have calculated the joystick's positions, let's move the plane
        //first, we need to make sure we're not landing!
        if (LandingStatus == false)
        {
            //BETA CODE---- Don't waste time on this atm
            //want to put in flips
            //for now just X
            //if (DiffXRatio >= 0.7)
            //{
            //    //flip plane
            //    FlipPlaneXPlus();
            //}

            //if (DiffXRatio <= -0.7)
            //{
            //    //flip plane
            //    FlipPlaneXMinus();
            //}
            //apply controls
            ControlPlane2();
            //move plane forward
            Rigid.MovePosition(transform.position + transform.forward * Time.deltaTime * SpeedSlider.SpeedSliderValue * MaxForwardSpeed);
        }
    }

    //why is this all commented? This is old code that shouldn't be used
    //this uses Transform.Translate. Migrating to AddForce
    //http://forum.unity3d.com/threads/which-of-these-methods-is-the-best-for-moving-a-spaceplane.425901/#post-2752770
    //void ControlPlane()
    //{
    //    Rigid.velocity = Vector3.zero;
    //    Rigid.angularVelocity = Vector3.zero;
    //    //how much to move the plane
    //    float XMovement = DiffXRatio * MovementRange;
    //    float YMovement = DiffYRatio * MovementRange;
    //    //I do NOT know why this is inversed... but so be it!
    //    //rotate up-down
    //    transform.Rotate(Vector3.right * Time.deltaTime * YMovement);
    //    //rotate right-left
    //    transform.Rotate(Vector3.up * Time.deltaTime * XMovement);
    //    //tilt as rotating
    //    transform.Rotate(Vector3.back * Time.deltaTime * XMovement * TiltFactor);
    //    //now that all the rotating is done, we need to move the plane
    //    //TESTING Space.World... never used this
    //    transform.Translate(Vector3.right * Time.deltaTime * XMovement * MaxHorizontalSpeed, Space.World);
    //}

        //currently using this to control plane
    void ControlPlane2()
    {
        //how much to move the plane
        float XMovement = DiffXRatio * MovementRange;
        float YMovement = DiffYRatio * MovementRange;
        //I do NOT know why this is inversed... but so be it!
        //rotate up-down
        transform.Rotate(Vector3.right * Time.deltaTime * YMovement);
        //rotate right-left
        transform.Rotate(Vector3.up * Time.deltaTime * XMovement);
        //tilt as rotating
        transform.Rotate(Vector3.back * Time.deltaTime * XMovement);
        //now that all the rotating is done, we need to move the plane
        Rigid.MovePosition(transform.position + transform.right * XMovement * MaxHorizontalSpeed * Time.deltaTime);
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "StopPosition")
        {
            //Cool tip!
            //For some reason, I need to "penetrate" (no, not in THAT way ;) the collider before stopping the player
            //so I'll wait a bit before stopping the player
            StartCoroutine(Penetrate());
            Debug.Log("Player Stopped");
        }
    }

    IEnumerator Penetrate()
    {
        yield return new WaitForSeconds(0.6f);
        LandingStatus = true;
    }

    //CURRENTLY don't need this
    //void FlipPlaneXPlus()
    //{
    //    transform.Rotate(Vector3.back * Time.deltaTime * 300);
    //    Rigid.AddForce(1000, 0, 0, ForceMode.Impulse);
    //}

    void FlipPlaneXMinus()
    {

    }
}

Thanks for the help, happy coding! :slight_smile:

Only thing I would change is use RigidBody.MoveRotation rather than transform.Rotate

Thanks. Not sure what I gained by using Rigidbody.MovePosition and Rigidbody.MoveRotation instead of transform.translate and transform.rotate, but at least I’m doing things properly for once :slight_smile:

Here’s the updated void ControlPlane2:

void ControlPlane2()
    {
        //how much to move the plane
        float XMovement = DiffXRatio * MovementRange;
        float YMovement = DiffYRatio * MovementRange;
        //I do NOT know why this is inversed... but so be it!
        //rotate up-down
        Rigid.MoveRotation(Rigid.rotation * Quaternion.Euler(Vector3.right * Time.deltaTime * YMovement));
        //rotate right-left
        Rigid.MoveRotation(Rigid.rotation * Quaternion.Euler(Vector3.up * Time.deltaTime * XMovement));
        //tilt as rotating
        Rigid.MoveRotation(Rigid.rotation * Quaternion.Euler(Vector3.back * Time.deltaTime * XMovement));
        //now that all the rotating is done, we need to move the plane
        Rigid.MovePosition(transform.position + transform.right * XMovement * MaxHorizontalSpeed * Time.deltaTime);
    }

You gained the ability to write correct physics code that wont (shouldnt) miss collisions. Super high velocity aside of course.

When ppl complain that there car/character/spaceship pushes through a wall, its because they used Translate/Rotate rather than MovePos/MoveRot

1 Like

AM I missing something here or shouldn’t you be using fixedDeltaTime instead of fixedTime?

do you mean instead of deltaTime?

You might be right.

You mean “instead of deltaTime”, right?

You may use deltaTime anywhere. deltaTime always contains the proper value based on the method it’s being used from. When used from FixedUpdate, deltaTime = fixedDeltaTime. When used from Update, deltaTime = last visual frame’s time.

Great, now you guys confused me even more. Edy, what you’re saying is that since my code is in FixedUpdate, it is the same as fixedDeltaTime?

Dont worry droid, edy was just confirming your code is all good.

Edy made a point I forgot, that fixedDeltaTime is the same as deltaTime in FixedUpdate, which makes sense.

1 Like