This commit is contained in:
2025-09-17 18:56:28 +08:00
commit 54c72710a5
5244 changed files with 5717609 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
using System;
using UnityEngine;
namespace DestroyIt
{
public static class Check
{
public static bool IsDefaultParticleAssigned()
{
if (DestructionManager.Instance == null) return false;
if (DestructionManager.Instance.defaultParticle == null)
{
Debug.LogError("DestructionManager: Default Particle is not assigned. You should assign a default particle effect for simple destructible objects.");
return false;
}
return true;
}
public static bool LayerExists(string layerName, bool logMessage)
{
if (DestructionManager.Instance == null) return false;
int layer = LayerMask.NameToLayer(layerName);
if (layer == -1)
{
if (logMessage)
Debug.LogWarning(String.Format("[DestroyIt Core] Layer \"{0}\" does not exist. Please add a layer named \"{0}\" to your project.", layerName));
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 02b0ef77a73e92145b8cb5fdfd1888cb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,121 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
public static class DestructibleHelper
{
/// <summary>When a Destructible Object is DESTROYED, this script will attempt to find and transfer the appropriate damaged materials over to the new prefab.</summary>
public static void TransferMaterials(Destructible oldObj, GameObject newObj)
{
if (oldObj == null) return;
Renderer[] oldMeshes = oldObj.GetComponentsInChildren<Renderer>();
Renderer[] newMeshes = newObj.GetComponentsInChildren<Renderer>();
// If either object has no meshes, then there's nothing to transfer, so exit.
if (oldMeshes.Length == 0 || newMeshes.Length == 0) return;
//TODO: Should this be removed? It has been commented out for a while.
// If there are no specified materials to replace, then exit, because we will just use the materials already assigned on the destroyed prefab.
//if (oldObj.replaceMaterials == null || oldObj.replaceMaterials.Count == 0) return;
// Get new materials for each destroyed mesh
for (int i = 0; i < newMeshes.Length; i++)
{
if (newMeshes[i] is MeshRenderer || newMeshes[i] is SkinnedMeshRenderer)
newMeshes[i].materials = GetNewMaterialsForDestroyedMesh(newMeshes[i], oldObj);
}
}
/// <summary>
/// For SpeedTree trees, locks the Hue Variation by setting the override property _HueVariationPos.
/// This way, destroyed trees won't change color as they fall and roll around.
/// Note that _HueVariationPos is a custom property added by the DestroyItSpeedTree custom shader.
/// </summary>
public static void LockHueVariation(this GameObject go)
{
if (go == null) return;
Renderer[] meshes = go.GetComponentsInChildren<Renderer>();
if (meshes.Length == 0) return;
for (int i = 0; i < meshes.Length; i++)
{
for (int j = 0; j < meshes[i].materials.Length; j++)
{
Material mat = meshes[i].materials[j];
if (mat.HasProperty("_HueVariationPos"))
mat.SetVector("_HueVariationPos", go.transform.position);
}
}
}
private static Material[] GetNewMaterialsForDestroyedMesh(Renderer destMesh, Destructible destructibleObj)
{
if (destructibleObj == null) return null;
Material[] curMats = destMesh.sharedMaterials;
Material[] newMats = new Material[curMats.Length];
// For each of the old materials, try to get the destroyed version.
for (int i = 0; i < curMats.Length; i++)
{
Material currentMat = curMats[i];
if (currentMat == null) continue;
// First, see if we need to replace the material with one defined on the Destructible script.
MaterialMapping matMap = destructibleObj.replaceMaterials.Find(x => x.SourceMaterial == currentMat);
newMats[i] = matMap == null ? currentMat : matMap.ReplacementMaterial;
// If we are using Progressive Damage, try to get a destroyed version of the material.
if (!destructibleObj.UseProgressiveDamage) continue;
if (destructibleObj.damageLevels == null || destructibleObj.damageLevels.Count == 0)
destructibleObj.damageLevels = DefaultDamageLevels();
DestructionManager.Instance.SetProgressiveDamageTexture(destMesh, newMats[i], destructibleObj.damageLevels[destructibleObj.damageLevels.Count - 1]);
}
return newMats;
}
/// <summary>Reapply force to the impact object (if any) so it punches through the destroyed object.</summary>
public static void ReapplyImpactForce(ImpactDamage info, float velocityReduction)
{
if (info.ImpactObject == null || info.ImpactObject.isKinematic) return;
info.ImpactObject.velocity = Vector3.zero; //zero out the velocity
info.ImpactObject.AddForce(info.ImpactObjectVelocityTo * velocityReduction, ForceMode.Impulse);
}
public static List<DamageLevel> DefaultDamageLevels()
{
// Initialize with default damage levels if null.
return new List<DamageLevel>
{
new DamageLevel{healthPercent = 100, visibleDamageLevel = 0},
new DamageLevel{healthPercent = 80, visibleDamageLevel = 2},
new DamageLevel{healthPercent = 60, visibleDamageLevel = 4},
new DamageLevel{healthPercent = 40, visibleDamageLevel = 6},
new DamageLevel{healthPercent = 20, visibleDamageLevel = 8}
};
}
/// <summary>Removes colliders from the object and lets it fall through the terrain.</summary>
public static void SinkAndDestroy(Destructible destObj)
{
// First, turn Kinematic off for all rigidbodies under this object.
Rigidbody[] rbodies = destObj.GetComponentsInChildren<Rigidbody>();
foreach (Rigidbody rbody in rbodies)
{
rbody.isKinematic = false;
rbody.WakeUp();
}
// Next, strip off all colliders so it falls through the terrain.
Collider[] colliders = destObj.GetComponentsInChildren<Collider>();
foreach (Collider coll in colliders)
coll.enabled = false;
// Attach the DestroyAfter script to the object so it will get removed from the game.
DestroyAfter destAfter = destObj.gameObject.AddComponent<DestroyAfter>();
destAfter.seconds = 5f;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a31acc56e013afd44b356df989ac3843
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,60 @@
using UnityEngine;
namespace DestroyIt
{
public static class ExplosionHelper
{
//TODO: IsExposedToBlast method is not used right now. Need to determine if it's worth fixing, and if so, how to fix it.
//TODO: It was not reporting objects being exposed to blasts when at steep angles to, or in contact with, the object.
/// <summary>Determines whether a collider object was exposed to a blast, by raycasting.</summary>
/// <param name="gameObj">The game object that may be exposed to the blast.</param>
/// <param name="explosion">The details about the blast.</param>
public static bool IsExposedToBlast(this GameObject gameObj, ExplosiveDamage explosion)
{
RaycastHit hit;
if (Physics.Raycast(explosion.Position, (gameObj.transform.position - explosion.Position), out hit, explosion.Radius))
{
Collider[] colliders = gameObj.GetComponentsInChildren<Collider>();
foreach (Collider coll in colliders)
{
if (hit.collider == coll)
{
//Debug.DrawRay(explosion.Position, gameObj.transform.position - explosion.Position, Color.red, 5f);
return true;
}
}
//Debug.DrawRay(explosion.Position, gameObj.transform.position - explosion.Position, Color.gray, 5f);
}
return false;
}
/// <summary>Applies impact/explosive force to debris and collider for a realistic effect.</summary>
/// <remarks>Force/Impact is reduced by the destroyed object's VelocityReduction amount (from XML config file).</remarks>
public static void ApplyForcesToDebris<T>(GameObject destroyedObj, float velocityReduction, T damageInfo)
{
if (destroyedObj == null) { return; }
Rigidbody[] debrisRigidbodies = destroyedObj.GetComponentsInChildren<Rigidbody>();
// For Explosive Damage: Apply force to exposed debris from direction explosion originated, modified by proximity to the blast.
if (damageInfo.GetType() == typeof(ExplosiveDamage))
{
ExplosiveDamage explosion = damageInfo as ExplosiveDamage;
// Apply explosive force to each debris piece. (NOTE: decided not to check if each piece of debris was exposed to the blast, because that effect was inaccurate when raycasting from steep angles.)
foreach (Rigidbody debrisRigidbody in debrisRigidbodies)
debrisRigidbody.AddExplosionForce(explosion.BlastForce, explosion.Position, explosion.Radius, explosion.UpwardModifier);
}
if (damageInfo.GetType() == typeof(ImpactDamage))
{
ImpactDamage impact = damageInfo as ImpactDamage;
if (impact != null && impact.AdditionalForce > 0f)
{
foreach (Rigidbody debrisRigidbody in debrisRigidbodies)
debrisRigidbody.AddExplosionForce(impact.AdditionalForce, impact.AdditionalForcePosition, impact.AdditionalForceRadius, 0f);
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 191756bea7ece5942aae5305428a89c9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,35 @@
using UnityEngine;
namespace DestroyIt
{
public static class ParticleHelper
{
private static Material[] GetNewMaterialsForDestroyedParticle(Renderer destMesh, Destructible destructibleObj)
{
if (destructibleObj == null) return null;
Material[] curMats = destMesh.sharedMaterials;
Material[] newMats = new Material[curMats.Length];
// For each of the old materials, try to get the destroyed version.
for (int i = 0; i < curMats.Length; i++)
{
Material currentMat = curMats[i];
if (currentMat == null) continue;
// First, see if we need to replace the material with one defined on the Destructible script.
MaterialMapping matMap = destructibleObj.replaceParticleMats.Find(x => x.SourceMaterial == currentMat);
newMats[i] = matMap == null ? currentMat : matMap.ReplacementMaterial;
// If we are using Progressive Damage, try to get a destroyed version of the material.
if (!destructibleObj.UseProgressiveDamage) continue;
if (destructibleObj.damageLevels == null || destructibleObj.damageLevels.Count == 0)
destructibleObj.damageLevels = DestructibleHelper.DefaultDamageLevels();
//DestructionManager.Instance.SetProgressiveDamageTexture(destMesh, newMats[i], destructibleObj.damageLevels[destructibleObj.damageLevels.Count - 1]);
}
return newMats;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a01c89b575673294ba6b39161f1bb2de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: