321 lines
10 KiB
C#

//----------------------------------------------
// Realistic Car Controller
//
// Copyright © 2014 - 2023 BoneCracker Games
// https://www.bonecrackergames.com
// Buğra Özdoğanlar
//
//----------------------------------------------
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// Truck trailer has additional wheelcolliders. This script handles center of mass of the trailer, wheelcolliders, ligths, etc...
/// </summary>
[AddComponentMenu("BoneCracker Games/Realistic Car Controller/Misc/RCC Truck Trailer")]
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(ConfigurableJoint))]
public class RCC_TruckTrailer : MonoBehaviour {
private RCC_CarControllerV3 carController; // Car controller of this trailer.
private Rigidbody rigid; // Rigidbody.
private ConfigurableJoint joint; // Configurable joint of this trailer.
/// <summary>
/// Wheel colliders and models.
/// </summary>
[System.Serializable]
public class TrailerWheel {
public WheelCollider wheelCollider;
public Transform wheelModel;
public void Torque(float torque) {
wheelCollider.motorTorque = torque;
}
public void Brake(float torque) {
wheelCollider.brakeTorque = torque;
}
}
public TrailerWheel[] trailerWheels; // All trailer wheels.
public Transform COM; // Center of mass.
public GameObject legs; // Legs will be enabled when trailer is detached.
private bool isSleeping = false; // Is rigidbody of the trailer is sleeping?
private float timer = 0f; // Timer for attach / detach process.
public bool attached = false; // Is this trailer attached now?
public bool brakeWhenDetached = false;
public float brakeForce = 5000f;
/// <summary>
/// Joint restrictions of the trailer.
/// </summary>
private class JointRestrictions {
public ConfigurableJointMotion motionX;
public ConfigurableJointMotion motionY;
public ConfigurableJointMotion motionZ;
public ConfigurableJointMotion angularMotionX;
public ConfigurableJointMotion angularMotionY;
public ConfigurableJointMotion angularMotionZ;
public void Get(ConfigurableJoint configurableJoint) {
motionX = configurableJoint.xMotion;
motionY = configurableJoint.yMotion;
motionZ = configurableJoint.zMotion;
angularMotionX = configurableJoint.angularXMotion;
angularMotionY = configurableJoint.angularYMotion;
angularMotionZ = configurableJoint.angularZMotion;
}
public void Set(ConfigurableJoint configurableJoint) {
configurableJoint.xMotion = motionX;
configurableJoint.yMotion = motionY;
configurableJoint.zMotion = motionZ;
configurableJoint.angularXMotion = angularMotionX;
configurableJoint.angularYMotion = angularMotionY;
configurableJoint.angularZMotion = angularMotionZ;
}
public void Reset(ConfigurableJoint configurableJoint) {
configurableJoint.xMotion = ConfigurableJointMotion.Free;
configurableJoint.yMotion = ConfigurableJointMotion.Free;
configurableJoint.zMotion = ConfigurableJointMotion.Free;
configurableJoint.angularXMotion = ConfigurableJointMotion.Free;
configurableJoint.angularYMotion = ConfigurableJointMotion.Free;
configurableJoint.angularZMotion = ConfigurableJointMotion.Free;
}
}
private JointRestrictions jointRestrictions = new JointRestrictions();
private RCC_Light[] lights;
private void Start() {
rigid = GetComponent<Rigidbody>(); // Getting rigidbody.
joint = GetComponentInParent<ConfigurableJoint>(); // Getting configurable joint.
jointRestrictions.Get(joint); // Getting current limitations of the joint.
// Fixing stutering bug of the rigid.
rigid.interpolation = RigidbodyInterpolation.None;
rigid.interpolation = RigidbodyInterpolation.Interpolate;
joint.configuredInWorldSpace = true;
// If joint is connected as default, attach the trailer. Otherwise detach.
if (joint.connectedBody) {
AttachTrailer(joint.connectedBody.gameObject.GetComponent<RCC_CarControllerV3>());
} else {
carController = null;
joint.connectedBody = null;
jointRestrictions.Reset(joint);
}
}
private void FixedUpdate() {
attached = joint.connectedBody; // Is trailer attached now?
rigid.centerOfMass = transform.InverseTransformPoint(COM.transform.position); // Setting center of mass.
// Applying torque to the wheels.
for (int i = 0; i < trailerWheels.Length; i++) {
if (carController) {
trailerWheels[i].Torque(carController.throttleInput * (attached ? 1f : 0f));
trailerWheels[i].Brake((attached ? 0f : 5000f));
} else {
trailerWheels[i].Torque(0f);
trailerWheels[i].Brake((brakeWhenDetached ? brakeForce : 0f));
}
}
}
private void Update() {
// If trailer is not moving, enable sleeping mode.
if (rigid.velocity.magnitude < .01f && Mathf.Abs(rigid.angularVelocity.magnitude) < .01f)
isSleeping = true;
else
isSleeping = false;
// Timer was used for attach/detach delay.
if (timer > 0f)
timer -= Time.deltaTime;
timer = Mathf.Clamp01(timer); // Clamping timer between 0f - 1f.
WheelAlign(); // Aligning wheel model position and rotation.
}
/// <summary>
/// Aligning wheel model position and rotation.
/// </summary>
private void WheelAlign() {
// If trailer is sleeping, return.
if (isSleeping)
return;
for (int i = 0; i < trailerWheels.Length; i++) {
// Return if no wheel model selected.
if (!trailerWheels[i].wheelModel) {
Debug.LogError(transform.name + " wheel of the " + transform.name + " is missing wheel model. This wheel is disabled");
enabled = false;
return;
}
// Locating correct position and rotation for the wheel.
Vector3 wheelPosition;
Quaternion wheelRotation;
trailerWheels[i].wheelCollider.GetWorldPose(out wheelPosition, out wheelRotation);
// Assigning position and rotation to the wheel model.
trailerWheels[i].wheelModel.transform.SetPositionAndRotation(wheelPosition, wheelRotation);
}
}
/// <summary>
/// Detach the trailer.
/// </summary>
public void DetachTrailer() {
foreach (RCC_Light item in lights) {
item.CarController = null;
}
// Resetting attachedTrailer of car controller.
carController.attachedTrailer = null;
carController = null;
lights = null;
timer = 1f;
joint.connectedBody = null;
jointRestrictions.Reset(joint);
if (legs)
legs.SetActive(true);
if (RCC_SceneManager.Instance.activePlayerCamera && RCC_SceneManager.Instance.activePlayerCamera.TPSAutoFocus)
StartCoroutine(RCC_SceneManager.Instance.activePlayerCamera.AutoFocus());
}
/// <summary>
/// Attach the trailer.
/// </summary>
/// <param name="vehicle"></param>
public void AttachTrailer(RCC_CarControllerV3 vehicle) {
// If delay is short, return.
if (timer > 0)
return;
carController = vehicle; // Assigning car controller.
lights = GetComponentsInChildren<RCC_Light>(); // Getting car controller lights.
timer = 1f; // Setting timer.
joint.connectedBody = vehicle.Rigid; // Connecting joint.
//joint.autoConfigureConnectedAnchor = false; // Setting auto configuration off of the joint.
//Vector3 jointVector = joint.connectedAnchor; // Resetting X axis of the connected anchor on attachment.
//jointVector.x = 0f;
//joint.connectedAnchor = jointVector;
jointRestrictions.Set(joint); // Enabling limitations of the joint.
// If trailer has legs, disable on attach.
if (legs)
legs.SetActive(false);
// Initializing lights of the trailer. Parent car controller will take control of them.
foreach (RCC_Light item in lights) {
item.CarController = carController;
}
// Assigning attachedTrailer of car controller.
vehicle.attachedTrailer = this;
rigid.isKinematic = false;
// If autofocus is enabled on RCC Camera, run it.
if (RCC_SceneManager.Instance.activePlayerCamera && RCC_SceneManager.Instance.activePlayerCamera.TPSAutoFocus)
StartCoroutine(RCC_SceneManager.Instance.activePlayerCamera.AutoFocus(transform, carController.transform));
}
private void Reset() {
if (COM == null) {
GameObject com = new GameObject("COM");
com.transform.SetParent(transform, false);
com.transform.localPosition = Vector3.zero;
com.transform.localRotation = Quaternion.identity;
com.transform.localScale = Vector3.one;
COM = com.transform;
}
if (transform.Find("Wheel Models") == null) {
GameObject com = new GameObject("Wheel Models");
com.transform.SetParent(transform, false);
com.transform.localPosition = Vector3.zero;
com.transform.localRotation = Quaternion.identity;
com.transform.localScale = Vector3.one;
}
if (transform.Find("Wheel Colliders") == null) {
GameObject com = new GameObject("Wheel Colliders");
com.transform.SetParent(transform, false);
com.transform.localPosition = Vector3.zero;
com.transform.localRotation = Quaternion.identity;
com.transform.localScale = Vector3.one;
}
GetComponent<Rigidbody>().mass = 5000;
}
}