Unity3D prevent object moving along particular axis

Viewed 47

I'm working on a sailing simulation in Unity3D. I have basic downwind sail physics implemented with sail angle and rudder control, but now I want to prevent "leeway", i.e. a ship's lateral movement. In a real ship, the daggerboard or keel provides a lot of resistance to sideways motion, which leads to the ship traveling more forward than sideways even with a wind from the side.

I currently have a GameManager object that calls a method on the ship to apply the wind physics in every FixedUpdate. There isn't an easy way to sum all the forces on the ship in a given frame, because each sail's force is applied with some offset according to where the sail is on the ship. So what I'm attempting to do is store the previous velocity of the ship, and in every FixedUpdate calculate how much the velocity has changed from the previous frame, and then apply an opposite acceleration to prevent leeway. Something like this:

Rigidbody rigidBody = this.ship.GetComponent<Rigidbody>();
// Get velocity in local coordinate frame
Vector3 localVelocity = rigidBody.transform.InverseTransformDirection(rigidBody.velocity);
float leewayDV = (localVelocity - this.previousVelocity).x;
this.previousVelocity = localVelocity;

Vector3 leewayCorrection = -1.0f * leewayDV * rigidBody.transform.right;
leewayCorrection = rigidBody.transform.TransformDirection(leewayCorrection);
rigidBody.AddForce(leewayCorrection, ForceMode.Acceleration);

(Ultimately, the leeway correction won't be 100%, but I'm using 100% while debugging).

Debugging code is showing that I'm applying an acceleration to try to prevent this motion, but it's not working as intended. I don't know if there's something fundamentally wrong with this approach, or a bug in my implementation, or if there's just an entirely different way that I could accomplish this.

1 Answers

Alright, so I don't have an answer to the question as posted (restricting motion on one axis), but I do have an answer that solves the "leeway" problem. I realized I was overcomplicating this, and I just needed to plug in the Drag Equation. I added it to LateUpdate, and it seems to do what I want: by tweaking different parameters, I can essentially limit the amount of leeway of the ship for a given wind speed. This seems like the most realistic approach, so I'm happy with this as a solution.

void LateUpdate() {
        Rigidbody rigidBody = this.ship.GetComponent<Rigidbody>();
        // Get velocity in ship's coordinate frame
        Vector3 localVelocity = rigidBody.transform.InverseTransformDirection(rigidBody.velocity);
        float dragForce = calculateSidewaysDrag(localVelocity.x);
        // Only worried about "x" drag here, e.g. leeway, because the engine handles regular drag just fine.
        Vector3 dragVector = new Vector3(-dragForce, 0, 0);
        // Transform the drag vector back to global coordinate frame
        dragVector = rigidBody.transform.TransformDirection(dragVector);
        rigidBody.AddForce(dragVector);
}
Related