Первый коммит
This commit is contained in:
805
Assets/RealisticCarControllerV3/Scripts/RCC_Damage.cs
Normal file
805
Assets/RealisticCarControllerV3/Scripts/RCC_Damage.cs
Normal file
@ -0,0 +1,805 @@
|
||||
//----------------------------------------------
|
||||
// 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;
|
||||
|
||||
/// <summary>
|
||||
/// Damage class.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class RCC_Damage {
|
||||
|
||||
internal RCC_CarControllerV3 carController; // Car controller.
|
||||
public bool automaticInstallation = true; // If set to enabled, all parts of the vehicle will be processed. If disabled, each part can be selected individually.
|
||||
|
||||
// Mesh deformation
|
||||
[Space()]
|
||||
[Header("Mesh Deformation")]
|
||||
public bool meshDeformation = true;
|
||||
public DeformationMode deformationMode = DeformationMode.Fast;
|
||||
|
||||
public enum DeformationMode { Accurate, Fast }
|
||||
[Range(1, 100)] public int damageResolution = 100; // Resolution of the deformation.
|
||||
public LayerMask damageFilter = -1; // LayerMask filter. Damage will be taken from the objects with these layers.
|
||||
public float damageRadius = .5f; // Verticies in this radius will be effected on collisions.
|
||||
public float damageMultiplier = 1f; // Damage multiplier.
|
||||
public float maximumDamage = .5f; // Maximum Vert Distance For Limiting Damage. 0 Value Will Disable The Limit.
|
||||
private readonly float minimumCollisionImpulse = .5f; // Minimum collision force.
|
||||
private readonly float minimumVertDistanceForDamagedMesh = .002f; // Comparing Original Vertex Positions Between Last Vertex Positions To Decide Mesh Is Repaired Or Not.
|
||||
|
||||
public struct OriginalMeshVerts { public Vector3[] meshVerts; } // Struct for Original Mesh Verticies positions.
|
||||
public struct OriginalWheelPos { public Vector3 wheelPosition; public Quaternion wheelRotation; }
|
||||
public struct MeshCol { public Collider col; public bool created; }
|
||||
|
||||
public OriginalMeshVerts[] originalMeshData; // Array for struct above.
|
||||
public OriginalMeshVerts[] damagedMeshData; // Array for struct above.
|
||||
public OriginalWheelPos[] originalWheelData; // Array for struct above.
|
||||
public OriginalWheelPos[] damagedWheelData; // Array for struct above.
|
||||
|
||||
[Space()]
|
||||
[HideInInspector] public bool repairNow = false; // Repairing now.
|
||||
[HideInInspector] public bool repaired = true; // Returns true if vehicle is completely repaired.
|
||||
private bool deformingNow = false; // Deforming the mesh now.
|
||||
private bool deformed = true; // Returns true if vehicle is completely deformed.
|
||||
private float deformationTime = 0f; // Timer for deforming the vehicle.
|
||||
|
||||
[Space()]
|
||||
public bool recalculateNormals = true; // Recalculate normals while deforming / restoring the mesh.
|
||||
public bool recalculateBounds = true; // Recalculate bounds while deforming / restoring the mesh.
|
||||
|
||||
// Wheel deformation
|
||||
[Space()]
|
||||
[Header("Wheel Deformation")]
|
||||
public bool wheelDamage = true; // Use wheel damage.
|
||||
public float wheelDamageRadius = .5f; // Wheel damage radius.
|
||||
public float wheelDamageMultiplier = 1f; // Wheel damage multiplier.
|
||||
public bool wheelDetachment = true; // Use wheel detachment.
|
||||
|
||||
// Light deformation
|
||||
[Space()]
|
||||
[Header("Light Deformation")]
|
||||
public bool lightDamage = true; // Use light damage.
|
||||
public float lightDamageRadius = .5f; //Light damage radius.
|
||||
public float lightDamageMultiplier = 1f; //Light damage multiplier.
|
||||
|
||||
// Part deformation
|
||||
[Space()]
|
||||
[Header("Part Deformation")]
|
||||
public bool partDamage = true; // Use part damage.
|
||||
public float partDamageRadius = .5f; //Light damage radius.
|
||||
public float partDamageMultiplier = 1f; //Light damage multiplier.
|
||||
|
||||
[Space()]
|
||||
public MeshFilter[] meshFilters; // Collected mesh filters.
|
||||
public RCC_DetachablePart[] detachableParts; // Collected detachable parts.
|
||||
public RCC_Light[] lights; // Collected lights.
|
||||
public RCC_WheelCollider[] wheels; // Collected wheels.
|
||||
|
||||
private Vector3 contactPoint = Vector3.zero;
|
||||
private Vector3[] contactPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Collecting all meshes and detachable parts of the vehicle.
|
||||
/// </summary>
|
||||
public void Initialize(RCC_CarControllerV3 _carController) {
|
||||
|
||||
// Getting the main car controller.
|
||||
carController = _carController;
|
||||
|
||||
if (automaticInstallation) {
|
||||
|
||||
if (meshDeformation) {
|
||||
|
||||
MeshFilter[] allMeshFilters = carController.gameObject.GetComponentsInChildren<MeshFilter>(true);
|
||||
List<MeshFilter> properMeshFilters = new List<MeshFilter>();
|
||||
|
||||
// Model import must be readable. If it's not readable, inform the developer. We don't wanna deform wheel meshes. Exclude any meshes belongs to the wheels.
|
||||
foreach (MeshFilter mf in allMeshFilters) {
|
||||
|
||||
if (mf.mesh != null) {
|
||||
|
||||
if (!mf.mesh.isReadable)
|
||||
Debug.LogError("Not deformable mesh detected. Mesh of the " + mf.transform.name + " isReadable is false; Read/Write must be enabled in import settings for this model!");
|
||||
else if (!mf.transform.IsChildOf(carController.FrontLeftWheelTransform) && !mf.transform.IsChildOf(carController.FrontRightWheelTransform) && !mf.transform.IsChildOf(carController.RearLeftWheelTransform) && !mf.transform.IsChildOf(carController.RearRightWheelTransform))
|
||||
properMeshFilters.Add(mf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GetMeshes(properMeshFilters.ToArray());
|
||||
|
||||
}
|
||||
|
||||
if (lightDamage)
|
||||
GetLights(carController.GetComponentsInChildren<RCC_Light>());
|
||||
|
||||
if (partDamage)
|
||||
GetParts(carController.GetComponentsInChildren<RCC_DetachablePart>());
|
||||
|
||||
if (wheelDamage)
|
||||
GetWheels(carController.GetComponentsInChildren<RCC_WheelCollider>());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all meshes.
|
||||
/// </summary>
|
||||
/// <param name="allMeshFilters"></param>
|
||||
public void GetMeshes(MeshFilter[] allMeshFilters) {
|
||||
|
||||
meshFilters = allMeshFilters;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all lights.
|
||||
/// </summary>
|
||||
/// <param name="allLights"></param>
|
||||
public void GetLights(RCC_Light[] allLights) {
|
||||
|
||||
lights = allLights;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all detachable parts.
|
||||
/// </summary>
|
||||
/// <param name="allParts"></param>
|
||||
public void GetParts(RCC_DetachablePart[] allParts) {
|
||||
|
||||
detachableParts = allParts;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all wheels
|
||||
/// </summary>
|
||||
/// <param name="allWheels"></param>
|
||||
public void GetWheels(RCC_WheelCollider[] allWheels) {
|
||||
|
||||
wheels = allWheels;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We will be using two structs for deformed sections. Original part struction, and deformed part struction.
|
||||
/// All damaged meshes and wheel transforms will be using these structs. At this section, we're creating them with original struction.
|
||||
/// </summary>
|
||||
//private void CheckMeshData() {
|
||||
|
||||
// originalMeshData = new OriginalMeshVerts[meshFilters.Length];
|
||||
|
||||
// for (int i = 0; i < meshFilters.Length; i++)
|
||||
// originalMeshData[i].meshVerts = meshFilters[i].mesh.vertices;
|
||||
|
||||
// damagedMeshData = new OriginalMeshVerts[meshFilters.Length];
|
||||
|
||||
// for (int i = 0; i < meshFilters.Length; i++)
|
||||
// damagedMeshData[i].meshVerts = meshFilters[i].mesh.vertices;
|
||||
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// We will be using two structs for deformed sections. Original part struction, and deformed part struction.
|
||||
/// All damaged meshes and wheel transforms will be using these structs. At this section, we're creating them with original struction.
|
||||
/// </summary>
|
||||
private void CheckWheelData() {
|
||||
|
||||
originalWheelData = new OriginalWheelPos[wheels.Length];
|
||||
|
||||
for (int i = 0; i < wheels.Length; i++) {
|
||||
|
||||
originalWheelData[i].wheelPosition = wheels[i].transform.localPosition;
|
||||
originalWheelData[i].wheelRotation = wheels[i].transform.localRotation;
|
||||
|
||||
}
|
||||
|
||||
damagedWheelData = new OriginalWheelPos[wheels.Length];
|
||||
|
||||
for (int i = 0; i < wheels.Length; i++) {
|
||||
|
||||
damagedWheelData[i].wheelPosition = wheels[i].transform.localPosition;
|
||||
damagedWheelData[i].wheelRotation = wheels[i].transform.localRotation;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moving deformed vertices to their original positions while repairing.
|
||||
/// </summary>
|
||||
public void UpdateRepair() {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
// If vehicle is not repaired completely, and repairNow is enabled, restore all deformed meshes to their original structions.
|
||||
if (!repaired && repairNow) {
|
||||
|
||||
//if (originalMeshData == null || originalMeshData.Length < 1)
|
||||
// CheckMeshData();
|
||||
|
||||
int k;
|
||||
repaired = true;
|
||||
|
||||
// If deformable mesh is still exists, get all verticies of the mesh first. And then move all single verticies to the original positions. If verticies are close enough to the original
|
||||
// position, repaired = true;
|
||||
for (k = 0; k < meshFilters.Length; k++) {
|
||||
|
||||
if (meshFilters[k] != null && meshFilters[k].mesh != null) {
|
||||
|
||||
// Get all verticies of the mesh first.
|
||||
Vector3[] vertices = meshFilters[k].mesh.vertices;
|
||||
|
||||
for (int i = 0; i < vertices.Length; i++) {
|
||||
|
||||
// And then move all single verticies to the original positions
|
||||
if (deformationMode == DeformationMode.Accurate)
|
||||
vertices[i] += (originalMeshData[k].meshVerts[i] - vertices[i]) * (Time.deltaTime * 5f);
|
||||
else
|
||||
vertices[i] += (originalMeshData[k].meshVerts[i] - vertices[i]);
|
||||
|
||||
// If verticies are close enough to their original positions, repaired = true;
|
||||
if ((originalMeshData[k].meshVerts[i] - vertices[i]).magnitude >= minimumVertDistanceForDamagedMesh)
|
||||
repaired = false;
|
||||
|
||||
}
|
||||
|
||||
// We were using the variable named "vertices" above, therefore we need to set the new verticies to the damaged mesh data.
|
||||
// Damaged mesh data also restored while repairing with this proccess.
|
||||
damagedMeshData[k].meshVerts = vertices;
|
||||
|
||||
// Setting new verticies to the all meshes. Recalculating normals and bounds, and then optimizing. This proccess can be heavy for high poly meshes.
|
||||
// You may want to disable last three lines.
|
||||
meshFilters[k].mesh.SetVertices(vertices);
|
||||
|
||||
if (recalculateNormals)
|
||||
meshFilters[k].mesh.RecalculateNormals();
|
||||
|
||||
if (recalculateBounds)
|
||||
meshFilters[k].mesh.RecalculateBounds();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (k = 0; k < wheels.Length; k++) {
|
||||
|
||||
if (wheels[k] != null) {
|
||||
|
||||
// Get all verticies of the mesh first.
|
||||
Vector3 wheelPos = wheels[k].transform.localPosition;
|
||||
|
||||
// And then move all single verticies to the original positions
|
||||
if (deformationMode == DeformationMode.Accurate)
|
||||
wheelPos += (originalWheelData[k].wheelPosition - wheelPos) * (Time.deltaTime * 5f);
|
||||
else
|
||||
wheelPos += (originalWheelData[k].wheelPosition - wheelPos);
|
||||
|
||||
// If verticies are close enough to their original positions, repaired = true;
|
||||
if ((originalWheelData[k].wheelPosition - wheelPos).magnitude >= minimumVertDistanceForDamagedMesh)
|
||||
repaired = false;
|
||||
|
||||
// We were using the variable named "vertices" above, therefore we need to set the new verticies to the damaged mesh data.
|
||||
// Damaged mesh data also restored while repairing with this proccess.
|
||||
damagedWheelData[k].wheelPosition = wheelPos;
|
||||
|
||||
wheels[k].transform.localPosition = wheelPos;
|
||||
wheels[k].transform.localRotation = Quaternion.identity;
|
||||
|
||||
if (!wheels[k].gameObject.activeSelf)
|
||||
wheels[k].gameObject.SetActive(true);
|
||||
|
||||
carController.ESPBroken = false;
|
||||
|
||||
wheels[k].Inflate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Repairing and restoring all detachable parts of the vehicle.
|
||||
for (int i = 0; i < detachableParts.Length; i++) {
|
||||
|
||||
if (detachableParts[i] != null)
|
||||
detachableParts[i].OnRepair();
|
||||
|
||||
}
|
||||
|
||||
// Repairing and restoring all lights of the vehicle.
|
||||
for (int i = 0; i < lights.Length; i++) {
|
||||
|
||||
if (lights[i] != null)
|
||||
lights[i].OnRepair();
|
||||
|
||||
}
|
||||
|
||||
// If all meshes are completely restored, make sure repairing now is false.
|
||||
if (repaired)
|
||||
repairNow = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moving vertices of the collided meshes to the damaged positions while deforming.
|
||||
/// </summary>
|
||||
public void UpdateDamage() {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
//if (originalMeshData == null || originalMeshData.Length < 1)
|
||||
// CheckMeshData();
|
||||
|
||||
// If vehicle is not deformed completely, and deforming is enabled, deform all meshes to their damaged structions.
|
||||
if (!deformed && deformingNow) {
|
||||
|
||||
int k;
|
||||
deformed = true;
|
||||
deformationTime += Time.deltaTime;
|
||||
|
||||
// If deformable mesh is still exists, get all verticies of the mesh first. And then move all single verticies to the damaged positions. If verticies are close enough to the original
|
||||
// position, deformed = true;
|
||||
for (k = 0; k < meshFilters.Length; k++) {
|
||||
|
||||
if (meshFilters[k] != null && meshFilters[k].mesh != null) {
|
||||
|
||||
// Get all verticies of the mesh first.
|
||||
Vector3[] vertices = meshFilters[k].mesh.vertices;
|
||||
|
||||
// And then move all single verticies to the damaged positions.
|
||||
for (int i = 0; i < vertices.Length; i++) {
|
||||
|
||||
if (deformationMode == DeformationMode.Accurate)
|
||||
vertices[i] += (damagedMeshData[k].meshVerts[i] - vertices[i]) * (Time.deltaTime * 5f);
|
||||
else
|
||||
vertices[i] += (damagedMeshData[k].meshVerts[i] - vertices[i]);
|
||||
|
||||
}
|
||||
|
||||
// Setting new verticies to the all meshes. Recalculating normals and bounds, and then optimizing. This proccess can be heavy for high poly meshes.
|
||||
meshFilters[k].mesh.SetVertices(vertices);
|
||||
|
||||
if (recalculateNormals)
|
||||
meshFilters[k].mesh.RecalculateNormals();
|
||||
|
||||
if (recalculateBounds)
|
||||
meshFilters[k].mesh.RecalculateBounds();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (k = 0; k < wheels.Length; k++) {
|
||||
|
||||
if (wheels[k] != null) {
|
||||
|
||||
Vector3 vertices = wheels[k].transform.localPosition;
|
||||
|
||||
if (deformationMode == DeformationMode.Accurate)
|
||||
vertices += (damagedWheelData[k].wheelPosition - vertices) * (Time.deltaTime * 5f);
|
||||
else
|
||||
vertices += (damagedWheelData[k].wheelPosition - vertices);
|
||||
|
||||
wheels[k].transform.localPosition = vertices;
|
||||
//wheels[k].transform.localRotation = Quaternion.Euler(vertices);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure deforming proccess takes only 1 second.
|
||||
if (deformationMode == DeformationMode.Accurate && deformationTime <= 1f)
|
||||
deformed = false;
|
||||
|
||||
// If all meshes are completely deformed, make sure deforming is false and timer is set to 0.
|
||||
if (deformed) {
|
||||
|
||||
deformingNow = false;
|
||||
deformationTime = 0f;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deforming meshes.
|
||||
/// </summary>
|
||||
/// <param name="collision"></param>
|
||||
/// <param name="impulse"></param>
|
||||
private void DamageMesh(float impulse) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
//if (originalMeshData == null || originalMeshData.Length < 1)
|
||||
// CheckMeshData();
|
||||
|
||||
// We will be checking all mesh filters with these contact points. If contact point is close enough to the mesh, deformation will be applied.
|
||||
for (int i = 0; i < meshFilters.Length; i++) {
|
||||
|
||||
// If mesh filter is not null, enabled, and has a valid mesh data...
|
||||
if (meshFilters[i] != null && meshFilters[i].mesh != null && meshFilters[i].gameObject.activeSelf) {
|
||||
|
||||
// Getting closest point to the mesh. Distance value will be set to closest point of the mesh - contact point.
|
||||
float distance = Vector3.Distance(NearestVertex(meshFilters[i].transform, meshFilters[i], contactPoint), contactPoint);
|
||||
|
||||
// If distance between contact point and closest point of the mesh is in range...
|
||||
if (distance <= damageRadius) {
|
||||
|
||||
// Collision direction.
|
||||
Vector3 collisionDirection = contactPoint - carController.transform.position;
|
||||
collisionDirection = -collisionDirection.normalized;
|
||||
|
||||
// All vertices of the mesh.
|
||||
Vector3[] vertices = damagedMeshData[i].meshVerts;
|
||||
|
||||
for (int k = 0; k < vertices.Length; k++) {
|
||||
|
||||
// Contact point is a world space unit. We need to transform to the local space unit with mesh origin. Verticies are local space units.
|
||||
Vector3 point = meshFilters[i].transform.InverseTransformPoint(contactPoint);
|
||||
// Distance between vertex and contact point.
|
||||
float distanceToVert = (point - vertices[k]).magnitude;
|
||||
|
||||
// If distance between vertex and contact point is in range...
|
||||
if (distanceToVert <= damageRadius) {
|
||||
|
||||
// Default impulse of the collision.
|
||||
float damage = impulse;
|
||||
|
||||
// The damage should decrease with distance from the contact point.
|
||||
damage -= damage * Mathf.Clamp01(distanceToVert / damageRadius);
|
||||
|
||||
Quaternion rot = Quaternion.identity;
|
||||
|
||||
Vector3 vW = carController.transform.TransformPoint(vertices[k]);
|
||||
|
||||
vW += rot * (collisionDirection * damage * (damageMultiplier / 10f));
|
||||
|
||||
vertices[k] = carController.transform.InverseTransformPoint(vW);
|
||||
|
||||
// If distance between original vertex position and deformed vertex position exceeds limits, make sure they are in the limits.
|
||||
if (maximumDamage > 0 && ((vertices[k] - originalMeshData[i].meshVerts[k]).magnitude) > maximumDamage)
|
||||
vertices[k] = originalMeshData[i].meshVerts[k] + (vertices[k] - originalMeshData[i].meshVerts[k]).normalized * (maximumDamage);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deforming wheels. Actually changing their local positions and rotations based on the impact.
|
||||
/// </summary>
|
||||
/// <param name="collision"></param>
|
||||
/// <param name="impulse"></param>
|
||||
private void DamageWheel(float impulse) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (originalWheelData == null || originalWheelData.Length < 1)
|
||||
CheckWheelData();
|
||||
|
||||
for (int i = 0; i < wheels.Length; i++) {
|
||||
|
||||
if (wheels[i] != null && wheels[i].gameObject.activeSelf) {
|
||||
|
||||
Vector3 wheelPos = damagedWheelData[i].wheelPosition;
|
||||
|
||||
Vector3 collisionDirection = contactPoint - carController.transform.position;
|
||||
collisionDirection = -collisionDirection.normalized;
|
||||
|
||||
Vector3 closestPoint = wheels[i].WheelCollider.ClosestPointOnBounds(contactPoint);
|
||||
float distance = Vector3.Distance(closestPoint, contactPoint);
|
||||
|
||||
if (distance < wheelDamageRadius) {
|
||||
|
||||
float damage = (impulse * wheelDamageMultiplier) / 30f;
|
||||
|
||||
// The damage should decrease with distance from the contact point.
|
||||
damage -= damage * Mathf.Clamp01(distance / wheelDamageRadius);
|
||||
|
||||
Vector3 vW = carController.transform.TransformPoint(wheelPos);
|
||||
|
||||
vW += (collisionDirection * damage);
|
||||
|
||||
wheelPos = carController.transform.InverseTransformPoint(vW);
|
||||
|
||||
if (maximumDamage > 0 && ((wheelPos - originalWheelData[i].wheelPosition).magnitude) > maximumDamage) {
|
||||
|
||||
//wheelPos = originalWheelData[i].wheelPosition + (wheelPos - originalWheelData[i].wheelPosition).normalized * (maximumDamage);
|
||||
|
||||
if (wheelDetachment && wheels[i].gameObject.activeSelf)
|
||||
DetachWheel(wheels[i]);
|
||||
|
||||
}
|
||||
|
||||
damagedWheelData[i].wheelPosition = wheelPos;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Deforming the detachable parts.
|
||||
/// </summary>
|
||||
/// <param name="collision"></param>
|
||||
/// <param name="impulse"></param>
|
||||
private void DamagePart(float impulse) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (detachableParts != null && detachableParts.Length >= 1) {
|
||||
|
||||
for (int i = 0; i < detachableParts.Length; i++) {
|
||||
|
||||
if (detachableParts[i] != null && detachableParts[i].gameObject.activeSelf) {
|
||||
|
||||
if (detachableParts[i].partCollider != null) {
|
||||
|
||||
Vector3 closestPoint = detachableParts[i].partCollider.ClosestPointOnBounds(contactPoint);
|
||||
float distance = Vector3.Distance(closestPoint, contactPoint);
|
||||
float damage = impulse * partDamageMultiplier;
|
||||
|
||||
// The damage should decrease with distance from the contact point.
|
||||
damage -= damage * Mathf.Clamp01(distance / damageRadius);
|
||||
|
||||
if (distance <= damageRadius)
|
||||
detachableParts[i].OnCollision(damage);
|
||||
|
||||
} else {
|
||||
|
||||
if ((contactPoint - detachableParts[i].transform.position).magnitude < 1f)
|
||||
detachableParts[i].OnCollision(impulse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deforming the lights.
|
||||
/// </summary>
|
||||
/// <param name="collision"></param>
|
||||
/// <param name="impulse"></param>
|
||||
private void DamageLight(float impulse) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (lights != null && lights.Length >= 1) {
|
||||
|
||||
for (int i = 0; i < lights.Length; i++) {
|
||||
|
||||
if (lights[i] != null && lights[i].gameObject.activeSelf) {
|
||||
|
||||
if ((contactPoint - lights[i].transform.position).magnitude < lightDamageRadius)
|
||||
lights[i].OnCollision(impulse * lightDamageMultiplier);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detaches the target wheel.
|
||||
/// </summary>
|
||||
/// <param name="wheelCollider"></param>
|
||||
public void DetachWheel(RCC_WheelCollider wheelCollider) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (!wheelCollider)
|
||||
return;
|
||||
|
||||
if (!wheelCollider.gameObject.activeSelf)
|
||||
return;
|
||||
|
||||
wheelCollider.gameObject.SetActive(false);
|
||||
Transform wheelModel = wheelCollider.wheelModel;
|
||||
|
||||
GameObject clonedWheel = GameObject.Instantiate(wheelModel.gameObject, wheelModel.transform.position, wheelModel.transform.rotation, null);
|
||||
clonedWheel.SetActive(true);
|
||||
clonedWheel.AddComponent<Rigidbody>();
|
||||
|
||||
GameObject clonedMeshCollider = new GameObject("Mesh Collider");
|
||||
clonedMeshCollider.transform.SetParent(clonedWheel.transform, false);
|
||||
clonedMeshCollider.transform.position = RCC_GetBounds.GetBoundsCenter(clonedWheel.transform);
|
||||
MeshCollider mc = clonedMeshCollider.AddComponent<MeshCollider>();
|
||||
MeshFilter biggestMesh = RCC_GetBounds.GetBiggestMesh(clonedWheel.transform);
|
||||
mc.sharedMesh = biggestMesh.mesh;
|
||||
mc.convex = true;
|
||||
|
||||
carController.ESPBroken = true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the collision enter event.
|
||||
/// </summary>
|
||||
/// <param name="collision">Collision.</param>
|
||||
public void OnCollision(Collision collision) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (!carController.useDamage)
|
||||
return;
|
||||
|
||||
if (((1 << collision.gameObject.layer) & damageFilter) != 0) {
|
||||
|
||||
float impulse = collision.impulse.magnitude / 10000f;
|
||||
|
||||
if (collision.rigidbody)
|
||||
impulse *= collision.rigidbody.mass / 1000f;
|
||||
|
||||
if (impulse < minimumCollisionImpulse)
|
||||
impulse = 0f;
|
||||
|
||||
if (impulse > 10f)
|
||||
impulse = 10f;
|
||||
|
||||
if (impulse > 0f) {
|
||||
|
||||
deformingNow = true;
|
||||
deformed = false;
|
||||
|
||||
repairNow = false;
|
||||
repaired = false;
|
||||
|
||||
// First, we are getting all contact points.
|
||||
ContactPoint[] contacts = collision.contacts;
|
||||
contactPoints = new Vector3[contacts.Length];
|
||||
|
||||
for (int i = 0; i < contactPoints.Length; i++)
|
||||
contactPoints[i] = contacts[i].point;
|
||||
|
||||
contactPoint = ContactPointsMagnitude();
|
||||
|
||||
if (meshFilters != null && meshFilters.Length >= 1 && meshDeformation)
|
||||
DamageMesh(impulse);
|
||||
|
||||
if (wheels != null && wheels.Length >= 1 && wheelDamage)
|
||||
DamageWheel(impulse);
|
||||
|
||||
if (detachableParts != null && detachableParts.Length >= 1 && partDamage)
|
||||
DamagePart(impulse);
|
||||
|
||||
if (lights != null && lights.Length >= 1 && lightDamage)
|
||||
DamageLight(impulse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the collision enter event.
|
||||
/// </summary>
|
||||
/// <param name="collision">Collision.</param>
|
||||
public void OnCollisionWithRay(RaycastHit hit, float impulse) {
|
||||
|
||||
if (!carController)
|
||||
return;
|
||||
|
||||
if (!carController.useDamage)
|
||||
return;
|
||||
|
||||
if (impulse < minimumCollisionImpulse)
|
||||
impulse = 0f;
|
||||
|
||||
if (impulse > 10f)
|
||||
impulse = 10f;
|
||||
|
||||
if (impulse > 0f) {
|
||||
|
||||
deformingNow = true;
|
||||
deformed = false;
|
||||
|
||||
repairNow = false;
|
||||
repaired = false;
|
||||
|
||||
// First, we are getting all contact points.
|
||||
contactPoint = hit.point;
|
||||
|
||||
if (meshFilters != null && meshFilters.Length >= 1 && meshDeformation)
|
||||
DamageMesh(impulse);
|
||||
|
||||
if (wheels != null && wheels.Length >= 1 && wheelDamage)
|
||||
DamageWheel(impulse);
|
||||
|
||||
if (detachableParts != null && detachableParts.Length >= 1 && partDamage)
|
||||
DamagePart(impulse);
|
||||
|
||||
if (lights != null && lights.Length >= 1 && lightDamage)
|
||||
DamageLight(impulse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Vector3 ContactPointsMagnitude() {
|
||||
|
||||
Vector3 magnitude = Vector3.zero;
|
||||
|
||||
for (int i = 0; i < contactPoints.Length; i++)
|
||||
magnitude += contactPoints[i];
|
||||
|
||||
magnitude /= contactPoints.Length;
|
||||
|
||||
return magnitude;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds closest vertex to the target point.
|
||||
/// </summary>
|
||||
/// <param name="trans"></param>
|
||||
/// <param name="mf"></param>
|
||||
/// <param name="point"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 NearestVertex(Transform trans, MeshFilter mf, Vector3 point) {
|
||||
|
||||
// Convert point to local space.
|
||||
point = trans.InverseTransformPoint(point);
|
||||
|
||||
float minDistanceSqr = Mathf.Infinity;
|
||||
Vector3 nearestVertex = Vector3.zero;
|
||||
|
||||
// Check all vertices to find nearest.
|
||||
foreach (Vector3 vertex in mf.mesh.vertices) {
|
||||
|
||||
Vector3 diff = point - vertex;
|
||||
float distSqr = diff.sqrMagnitude;
|
||||
|
||||
if (distSqr < minDistanceSqr) {
|
||||
|
||||
minDistanceSqr = distSqr;
|
||||
nearestVertex = vertex;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Convert nearest vertex back to the world space.
|
||||
return trans.TransformPoint(nearestVertex);
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user