0
\$\begingroup\$

I have been able to simulate a floating boat very simply by attaching a script called Boat.cs to a ship model with a Rigidbody; the Drag and Angular Drag are set to 2, and the mass to 15, and the Rigidbody uses gravity.

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

  [RequireComponent(typeof(Rigidbody))]
  public class Boat : MonoBehaviour {
     public static float waterLevel = 16.6f;
     public float floatThreshhold = 2.0f;
     public float waterDensity = 0.125f;
     public float downForce = 0.5f;

     float forceFactor;
     Vector3 floatForce;
     public Transform pointOfBuyancy;

      void FixedUpdate () {

        forceFactor = 1.0f - ((transform.position.y - waterLevel) / floatThreshhold);
        if(forceFactor > 0.0f)
        {
           floatForce = -Physics.gravity * GetComponent<Rigidbody>().mass * (forceFactor - GetComponent<Rigidbody>().velocity.y * waterDensity);
           floatForce += new Vector3(0.0f, -downForce * GetComponent<Rigidbody>().mass, 0.0f);
           GetComponent<Rigidbody>().AddForceAtPosition(floatForce, pointOfBuyancy.position);
        }
     }
  }

the Transform named pointOfBuyancy is an empty placed above the ship model. This is where the floating force is applied, acting as a pendulum to stabilize the ship. This script works very well, and doesn't require changes.

The control script is called SimpleBoatController.cs, and is as follows:

  // Denis Labrecque, copy of #02 Boat Movement - How to make a Boat Controller - Unity 3D on YouTube

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

  [RequireComponent(typeof(Rigidbody))]
  [RequireComponent(typeof(Boat))]
  public class SimpleBoatController : MonoBehaviour {

     public float movementThreshold = 0.2f;
     public float turnThreshold = 0.2f;
     public float maxSpeed = 30.0f;

     public Transform pointOfEngine;

     Rigidbody rigidbody;
     Transform centerOfMassTransform;
     float waterDynamicFactor;
     float verticalInput;
     float movementFactor;
     float horizontalInput;
     float steerFactor;

     public float CurrentSpeed { get; private set; }

      // Use this for initialization
      void Start () {
        rigidbody = GetComponent<Rigidbody>();
      }

      // Update is called once per frame
      void Update () {
        // Assign properties
        CurrentSpeed = rigidbody.velocity.x;

        Move();
      }

     void Move()
     {
        // Receive player input
        verticalInput = Input.GetAxis("Vertical");
        horizontalInput = Input.GetAxis("Horizontal");

        // Calculate factors
        movementFactor = Mathf.Lerp(movementFactor, verticalInput, Time.deltaTime * movementThreshold);
        steerFactor = Mathf.Lerp(steerFactor, horizontalInput, Time.deltaTime * turnThreshold);

        // Move forwards
        rigidbody.AddForceAtPosition(new Vector3(movementFactor * rigidbody.mass * maxSpeed, 0, 0), pointOfEngine.position);

        // Turn
        // https://forum.unity.com/threads/rigidbody-lookat-torque.146625/
        // rigidbody.AddTorque(Vector3.Cross(transform.forward, rigidbody.velocity), ForceMode.FORCE);
        rigidbody.AddTorque(0, transform.position.y * CurrentSpeed * 25f * horizontalInput, 0); // Rotate
        rigidbody.AddTorque(Vector3.Cross(rigidbody.velocity, transform.forward), ForceMode.Force); // Align relative to direction
        Debug.Log("Turning of " + horizontalInput);
     }
  }

This script requires an additional empty at the location of the center of mass of the ship, called pointOfEngine in the code, where the ship is pushed forwards. This works very well.

My difficulty is in the move method, when it comes to applying rotation.

Because the flotation script does not apply any angular drag, the boat rotates without turning in the direction of rotation. It makes a flat spin and wobbles like over jellow -- which looks good, but just doesn't allow controlling the boat.

How can I make the boat travel in an arc, and not just back and forth while making a flat spin?

I have searched various physics answers about rotation and wind resistance, but these don't apply to my problem.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

I use the following for the boat control:

public Vector3 COM;
[Space (15)]
public float speed = 1.0f;
public float steerSpeed = 1.0f;
public float movementThresold = 10.0f;

Transform m_COM;
float verticalInput;
float movementFactor;
float horizontalInput;
float steerFactor;

public GameObject Rudder;

// Update is called once per frame
void Update () {
    Balance ();
    Movement ();
    Steer ();
}

void Balance () {
    if (!m_COM) {
        m_COM = new GameObject ("COM").transform;
        m_COM.SetParent (transform);
    }

    m_COM.position = COM;
    GetComponent<Rigidbody> ().centerOfMass = m_COM.position;
}

void Movement () {
    verticalInput = Input.GetAxis ("Vertical");
    movementFactor = Mathf.Lerp (movementFactor, verticalInput, Time.deltaTime / movementThresold);
    transform.Translate (0.0f, 0.0f, movementFactor * speed);
}

void Steer () {
    horizontalInput = Input.GetAxis ("Horizontal");
    steerFactor = Mathf.Lerp (steerFactor, horizontalInput * verticalInput, Time.deltaTime / movementThresold);
    transform.Rotate (0.0f, steerFactor * steerSpeed, 0.0f);

    // To move the physical rudder wheel on the deck
    Rudder.transform.Rotate(Vector3.down, steerFactor * steerSpeed * 5f);
}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ This answer would be even better if it included a description of why this solves OP's problem, to help a reader develop an intuition about the strategy you're using rather than just copying your code. \$\endgroup\$
    – DMGregory
    Nov 28, 2018 at 18:10
  • \$\begingroup\$ I'm using physics, so I'll have to check whether transform.Rotate and transform.Translate are really the way to go. Thank you for your feedback; I'll look into it once I have time. \$\endgroup\$ Nov 29, 2018 at 0:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .