//----------------------------------------------
// Realistic Car Controller
//
// Copyright © 2014 - 2023 BoneCracker Games
// https://www.bonecrackergames.com
// Buğra Özdoğanlar
//
//----------------------------------------------
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// Detachable part of the vehicle.
///
[AddComponentMenu("BoneCracker Games/Realistic Car Controller/Misc/RCC Detachable Part")]
public class RCC_DetachablePart : MonoBehaviour {
public ConfigurableJoint Joint {
get {
if (_joint == null)
_joint = GetComponentInParent();
return _joint;
}
set {
_joint = value;
}
}
private ConfigurableJoint _joint;
public Rigidbody Rigid {
get {
if (_rigid == null)
_rigid = GetComponentInParent();
return _rigid;
}
set {
_rigid = value;
}
}
private Rigidbody _rigid;
private RCC_Joint jointProperties; // Joint properties class.
public Transform COM; // Center of mass.
public Collider partCollider; // Collider.
public enum DetachablePartType { Hood, Trunk, Door, Bumper_F, Bumper_R }
public DetachablePartType partType = DetachablePartType.Hood;
public bool lockAtStart = true; // Lock all motions of Configurable Joint at start.
public float strength = 100f; // Strength of the part.
internal float orgStrength = 100f; // Original strength of the part. We will be using this original value while restoring the part.
public bool isBreakable = true; // Can it break at certain damage?
public bool broken = false; // Is this part broken currently?
public int loosePoint = 35; // Part will be broken at this point.
public int detachPoint = 0; // Part will be detached at this point.
public float deactiveAfterSeconds = 5f; // Part will be deactivated after the detachment.
public Vector3 addTorqueAfterLoose = Vector3.zero; // Adds angular velocity related to speed after the brake point reached.
private void Start() {
orgStrength = strength; // Getting original strength of the part. We will be using this original value while restoring the part.
// Getting collider.
if (!partCollider)
partCollider = GetComponentInChildren();
if (partCollider)
partCollider.enabled = false;
// Setting center of mass if selected.
if (COM)
Rigid.centerOfMass = transform.InverseTransformPoint(COM.transform.position);
// Disable the script if configurable joint not found.
if (!Joint) {
Debug.LogWarning("Configurable Joint not found for " + gameObject.name + "!");
enabled = false;
return;
}
// Getting original properties of the joint. We will be using the original data for restoring the part while repairing.
GetJointProperties();
// Locks all motions of Configurable Joint at start.
if (lockAtStart)
StartCoroutine(LockJoint());
}
///
/// Getting original properties of the joint. We will be using the original data for restoring the part while repairing.
///
private void GetJointProperties() {
jointProperties = new RCC_Joint();
jointProperties.GetProperties(Joint);
}
///
/// Locks the parts.
///
private IEnumerator LockJoint() {
yield return new WaitForFixedUpdate();
RCC_Joint.LockPart(Joint);
}
private void Update() {
// If part is broken, return.
if (broken)
return;
// If part is weak and loosen, apply angular velocity related to vehicle speed.
if (addTorqueAfterLoose != Vector3.zero && strength <= loosePoint) {
float speed = transform.InverseTransformDirection(Rigid.velocity).z; // Local speed.
Rigid.AddRelativeTorque(new Vector3(addTorqueAfterLoose.x * speed, addTorqueAfterLoose.y * speed, addTorqueAfterLoose.z * speed)); // Applying local torque.
}
}
///
/// On collision with impulse.
///
///
public void OnCollision(float impulse) {
// If part is broken, return.
if (broken)
return;
// Decreasing strength of the part related to collision impulse.
strength -= impulse * 5f;
strength = Mathf.Clamp(strength, 0f, Mathf.Infinity);
// Check joint of the part based on strength.
CheckJoint();
}
///
/// Checks joint of the part based on strength.
///
private void CheckJoint() {
// If part is broken, return.
if (broken)
return;
// If strength is 0, unlock the parts and set their joint limits to none. Detach them from the vehicle. If strength is below detach point, only set joint limits to none.
if (isBreakable && strength <= detachPoint) {
if (Joint) {
if (partCollider)
partCollider.enabled = true;
broken = true;
Destroy(Joint);
transform.SetParent(null);
StartCoroutine(DisablePart(deactiveAfterSeconds));
}
} else if (strength <= loosePoint) {
if (partCollider)
partCollider.enabled = false;
if (Joint) {
Joint.angularXMotion = jointProperties.jointMotionAngularX;
Joint.angularYMotion = jointProperties.jointMotionAngularY;
Joint.angularZMotion = jointProperties.jointMotionAngularZ;
Joint.xMotion = jointProperties.jointMotionX;
Joint.yMotion = jointProperties.jointMotionY;
Joint.zMotion = jointProperties.jointMotionZ;
}
}
}
///
/// Repairs, and restores the part.
///
public void OnRepair() {
// Enabling gameobject first if it's disabled.
if (!gameObject.activeSelf)
gameObject.SetActive(true);
if (partCollider)
partCollider.enabled = false;
// If joint is removed and part is detached, adding new configurable joint component. Configurable Joints cannot be toggled on or off. Therefore, we need to destroy and create configurable joints.
if (Joint == null) {
// Setting properties of the configurable joint to original properties.
Joint = gameObject.AddComponent();
jointProperties.SetProperties(Joint);
} else {
// Setting strength to original strength value. And make sure part is not broken anymore.
strength = orgStrength;
broken = false;
// Locking the part.
Joint.angularXMotion = ConfigurableJointMotion.Locked;
Joint.angularYMotion = ConfigurableJointMotion.Locked;
Joint.angularZMotion = ConfigurableJointMotion.Locked;
Joint.xMotion = ConfigurableJointMotion.Locked;
Joint.yMotion = ConfigurableJointMotion.Locked;
Joint.zMotion = ConfigurableJointMotion.Locked;
}
}
///
/// Disables the part with delay.
///
///
///
private IEnumerator DisablePart(float delay) {
yield return new WaitForSeconds(delay);
gameObject.SetActive(false);
}
private void Reset() {
if(!string.IsNullOrEmpty(RCC_Settings.Instance.DetachablePartLayer))
gameObject.layer = LayerMask.NameToLayer(RCC_Settings.Instance.DetachablePartLayer);
if (!COM) {
COM = new GameObject("COM").transform;
COM.SetParent(transform);
COM.localPosition = Vector3.zero;
COM.localRotation = Quaternion.identity;
}
if (!Joint)
Joint = gameObject.AddComponent();
Joint.connectedBody = GetComponentInParent().gameObject.GetComponent();
if (!Rigid)
Rigid = gameObject.AddComponent();
Rigid.mass = 35f;
Rigid.interpolation = RigidbodyInterpolation.Interpolate;
Rigid.collisionDetectionMode = CollisionDetectionMode.Continuous;
if (!partCollider)
partCollider = GetComponentInChildren();
}
}