[Problem] Boat / Ship movement

Hi!
I want to make a simple movement for a boat on sea or spaceship in space.
“w” and “s” keys to move foreward or break and “a” and “d” key for turning.
values are set as following:
2591468--181290--upload_2016-4-11_16-38-24.png
For testing, i have a simple cube with rigidbody set and script as following:

using UnityEngine;
using System.Collections;

public class CubeController : MonoBehaviour {

    public float speed;
    public float turnSpeed;

    private Rigidbody rb;

    // Use this for initialization
    void Start () {
        rb = GetComponent<Rigidbody>();
    }
   
    // Update is called once per frame
    void FixedUpdate () {

        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        rb.AddTorque(0f,h * turnSpeed, 0f);
        rb.AddForce(transform.forward * v * speed);
   
    }
}

my problem - look at my painting
2591468--181291--upload_2016-4-11_16-39-11.png
when i press “w” the cube is speeding up, i release the “w” key and press the “d” key for turning, the cube turns, but keep up to move in the original direction it had before. (you will call this maybe as drift)
but i dont want a drift :slight_smile: The cube should start to move into new direction without pressing “w” for new acceleration. The cube should take new direction with the remaining speed (without given new speed).
I hope you understand my problem and thx for help ! :slight_smile:
(i am no nativ english speaker :wink:

torque is only a rotational force, if you want the object to start moving sideways you need to provide a lateral (aka sideways) force.

You might get movement more like what you are after by manipulating the rigidbody’s velocity vector rather than applying forces to it.

sidenote: handling input in the fixedupdate may cause input to be “missed” since fixedupdate isn’t called every frame which can make things feel unresponsive. You probably want to get the input in update.

this tutorial might be of interest on how to separate out the two

The movement you ended up with is more or less realistic given that the supposed fluid causes no drag. You will need to thrust in the direction the craft is facing in order to make it go that way.

If you want to manipulate Rigidbody.velocity directly (which results in less realistic physics), you check each frame for the current velocity magnitude, then set velocity to the normalized rotation direction vector multiplied by the magnitude.

If you want to use forces to change the direction of motion when it is different from the direction of rotation, then add a force to the body that increases in magnitude as the difference in angles increases and direct the force normal to the craft’s direction of rotation. The force should be 0 when the difference is 0, and some large value when the difference is 90, so it should be a sine formula, which is convenient because for values greater than 90 the force should start to decrease again. The force should never be negative, though, so I’d recommend using the absolute value.

Note that you can get the direction of motion using Rigidbody.velocity and there is a bunch of vector math operations available for Vector2’s and Vector3’s. I’m not sure how much of this you know already, so let us know if you have more specific questions.

Hi there! Thank you for your answers!
I don’t know if i got you right @Hyblademin :slight_smile: The problem is my understanding in english and in math :wink:
But i ended up like this:

using UnityEngine;
using System.Collections;

public class CubeController : MonoBehaviour {

    public float speed;
    public float turnSpeed;

    private Rigidbody rb;
  [COLOR=#ff0000] [B] private float velocityMagnitude;[/B][/COLOR]


    // Use this for initialization
    void Start () {
        rb = GetComponent<Rigidbody>();
    }
 
    // Update is called once per frame
    void FixedUpdate () {

        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        rb.AddTorque(0f,h * turnSpeed, 0f);
        rb.AddForce(transform.forward * v * speed);

       [COLOR=#ff0000] [B]//TESTING
        velocityMagnitude = rb.velocity.magnitude;
        rb.velocity = transform.forward * velocityMagnitude;[/B][/COLOR]
    }
}

The red lines are new code. The behavior seems like what i wanted to do. But i still have some questions!
In the documentation about Rigidbody.velocity you can read:

But when you look in the example, they also did it in the FixedUpdate. Why?
@LeftyRighty : why don’t use the input.getaxis in the FixedUpdate? In the 2D UFO Tutorial here on this page, they also did the inputs in the FixedUpdate.

So what is wrong, what is right? :slight_smile: I am confused

When I mentioned that directly setting the velocity will result in less realistic physics, I was actually referring to this same quote from the API. They’re just saying, of course, that the physics engine’s ultimate purpose on an object level is to output the velocity and angular velocity for each Rigidbody. Setting it yourself is essentially patially overriding this, so unless your physics system is at least as good, the quality of the simulation goes down. This may actually be preferred in some cases; player control is often more important than realism!

They set velocity in FixedUpdate() because that’s when the physics engine does it; if you set it in Update() instead, then you will in theory have your script and the physics engine going back and forth between what values they each think the velocity should be, result in potentially erratic behavior. I’ve noticed that it doesn’t often make a huge difference, but it’s recommended to update velocity in FixedUpdate(). Generally speaking, anything that changes a Rigidbody’s physical state should be updated in FixedUpdate() rather than in Update(); this includes forces.

1 Like

ok, this is somewhat simplified but lets say Update is being called 100 times a second (this is entirely variable based on what hardware it is being run on and what your app is doing, what other apps are doing, os resource sharing etc.etc.). FixedUpdate is being called at the default 50 times a second.

If you tap a key and it happens in one of the frames where FixedUpdate isn’t being checked and you’re checking the Input in FixedUpdate it won’t be detected.

A lot of tutorials are aimed at teaching newbies “something”, not “everything”, mostly so newbies aren’t totally overwhelmed with minutiae.

as to what is “right”, depending on what you are doing it might have no negative impact in which case it’s “right”, if you find that it is feeling unresponsive then it’s “wrong”… there isn’t really a “right way” in coding/development, just the way that works :slight_smile:

1 Like

If you mix adding force with setting velocity directly, your velocity will be changed by the force you added. This is bad.

If you set velocity directly and do not use forces, then you pretty much are calculating the forces yourself. Done wrong (or correctly on purpose) this results in less realistic physics. Sometimes that is what we want.

If you use forces, Unity will calculate velocity so you shouldn’t set it directly. (One time velocity changes, eg a jump, is still okay.)

tl;dr Use forces or set velocity yourself. Probably not both.

I agree you shouldn’t check Input in FixedUpdate. Because Inputs are set at the beginning of Update(), two things might happen.

  • You can miss inputs if Update runs twice before FixedUpdate runs.
  • You can process a single input multiple times if FixedUpdate runs multiple times betore Update runs.

NOTE: In my experience, Unity can handle one-time force/velocity changes in Update (it’ll get processed in the next FixedUpdate cycle), but if you’re applying force or changing velocity over several frames, then you should definitely use FixedUpdate. I would still recommend against using Update however because then you’re affecting the rigidbody from multiple functions that get called at different times and it can quickly be confusing to bug fix.

First of all, thank you for your helps!

But now i am totaly confused :slight_smile: I think, i understand the part, that inputs should be in Update() rather than FixedUpdate().

I still struggle with the physics :frowning: So my approach is not good, because i use addforce and influence on velocity? But what than is the solution for my problem?