Alright we are inching our way towards a boat. The boat can currently float, but it also has to move, so we need to add an engine and a propeller.
Adding a propeller is just a matter of adding a force where the propeller is, which will make the boat move forward. But it also has to turn. But I'm lucky because I'm modelling a boat that's propelled forward not with a propeller but with a water jet. This water jet will also steer the boat by turning the nozzle in another direction. If you have a rudder you have to find another solution!
This is how my BoatEngine script looks like (just add it to the boat you have):
using UnityEngine;
using System.Collections;
public class BoatEngine : MonoBehaviour
{
//Drags
public Transform waterJetTransform;
//How fast should the engine accelerate?
public float powerFactor;
//What's the boat's maximum engine power?
public float maxPower;
//The boat's current engine power is public for debugging
public float currentJetPower;
private float thrustFromWaterJet = 0f;
private Rigidbody boatRB;
private float WaterJetRotation_Y = 0f;
BoatController boatController;
void Start()
{
boatRB = GetComponent<Rigidbody>();
boatController = GetComponent<BoatController>();
}
void Update()
{
UserInput();
}
void FixedUpdate()
{
UpdateWaterJet();
}
void UserInput()
{
//Forward / reverse
if (Input.GetKey(KeyCode.W))
{
if (boatController.CurrentSpeed < 50f && currentJetPower < maxPower)
{
currentJetPower += 1f * powerFactor;
}
}
else
{
currentJetPower = 0f;
}
//Steer left
if (Input.GetKey(KeyCode.A))
{
WaterJetRotation_Y = waterJetTransform.localEulerAngles.y + 2f;
if (WaterJetRotation_Y > 30f && WaterJetRotation_Y < 270f)
{
WaterJetRotation_Y = 30f;
}
Vector3 newRotation = new Vector3(0f, WaterJetRotation_Y, 0f);
waterJetTransform.localEulerAngles = newRotation;
}
//Steer right
else if (Input.GetKey(KeyCode.D))
{
WaterJetRotation_Y = waterJetTransform.localEulerAngles.y - 2f;
if (WaterJetRotation_Y < 330f && WaterJetRotation_Y > 90f)
{
WaterJetRotation_Y = 330f;
}
Vector3 newRotation = new Vector3(0f, WaterJetRotation_Y, 0f);
waterJetTransform.localEulerAngles = newRotation;
}
}
void UpdateWaterJet()
{
//Debug.Log(boatController.CurrentSpeed);
Vector3 forceToAdd = -waterJetTransform.forward * currentJetPower;
//Only add the force if the engine is below sea level
float waveYPos = WaterController.current.GetWaveYPos(waterJetTransform.position, Time.time);
if (waterJetTransform.position.y < waveYPos)
{
boatRB.AddForceAtPosition(forceToAdd, waterJetTransform.position);
}
else
{
boatRB.AddForceAtPosition(Vector3.zero, waterJetTransform.position);
}
}
}
To make the script work you have to tell it where the water jet is by giving it a gameobject. This gameobject is just an empty gameobject which is a child to the boat and its position is where the waterjet is. You can also add a box so you can see in which way the water jet is pointing.
You also need a way to calculate the speed. And I've added the speed calculations to another script called BoatController.
using UnityEngine;
using System.Collections;
public class BoatController : MonoBehaviour
{
//Speed calculations
private float currentSpeed;
private Vector3 lastPosition;
void FixedUpdate()
{
CalculateSpeed();
//Debug.Log(currentSpeed);
}
//Calculate the current speed in m/s
private void CalculateSpeed()
{
//Calculate the distance of the Transform Object between the fixedupdate calls with
//'(transform.position - lastPosition).magnitude' Now you know the 'meter per fixedupdate'
//Divide this value by Time.deltaTime to get meter per second
currentSpeed = (transform.position - lastPosition).magnitude / Time.deltaTime;
//Save the position for the next update
lastPosition = transform.position;
}
public float CurrentSpeed
{
get
{
return this.currentSpeed;
}
}
}
And now you have your very own boat!