178 lines
5.3 KiB
C#
178 lines
5.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class Explosion3DTestController : MonoBehaviour
|
|
{
|
|
[Header("Trigger")]
|
|
[SerializeField] private bool enableDebugKey = true;
|
|
[SerializeField] private KeyCode triggerKey = KeyCode.Alpha0;
|
|
|
|
[Header("Target")]
|
|
[SerializeField] private GameObject intactObject;
|
|
[SerializeField] private GameObject fracturedPrefab;
|
|
[SerializeField] private Transform spawnRoot;
|
|
[SerializeField] private bool disableIntactObjectOnExplode = true;
|
|
[SerializeField] private bool destroyPreviousFractureInstance = true;
|
|
|
|
[Header("Explosion Force")]
|
|
[SerializeField] private float explosionForce = 2.5f;
|
|
[SerializeField] private float explosionRadius = 1.25f;
|
|
[SerializeField] private float upwardModifier = 0.15f;
|
|
[SerializeField] private float randomForceMultiplier = 0.2f;
|
|
[SerializeField] private float randomTorque = 8f;
|
|
|
|
[Header("Containment")]
|
|
[SerializeField] private bool keepFragmentsClose = true;
|
|
[SerializeField] private float maxFragmentSpeed = 1.2f;
|
|
[SerializeField] private float fragmentDrag = 4f;
|
|
[SerializeField] private float fragmentAngularDrag = 6f;
|
|
[SerializeField] private bool disableFragmentGravity = false;
|
|
|
|
[Header("Lifecycle")]
|
|
[SerializeField] private bool autoCleanupFragments = false;
|
|
[SerializeField] private float cleanupDelay = 5f;
|
|
|
|
private GameObject spawnedFractureRoot;
|
|
private bool exploded;
|
|
|
|
private void Update()
|
|
{
|
|
if (!enableDebugKey)
|
|
return;
|
|
|
|
if (Input.GetKeyDown(triggerKey))
|
|
{
|
|
TriggerExplosion();
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Trigger Explosion")]
|
|
public void TriggerExplosion()
|
|
{
|
|
if (exploded)
|
|
return;
|
|
|
|
if (fracturedPrefab == null)
|
|
{
|
|
Debug.LogWarning("[Explosion3DTest] Missing fracturedPrefab.");
|
|
return;
|
|
}
|
|
|
|
Transform sourceTransform = intactObject != null ? intactObject.transform : transform;
|
|
Transform parent = spawnRoot != null ? spawnRoot : sourceTransform.parent;
|
|
|
|
if (destroyPreviousFractureInstance && spawnedFractureRoot != null)
|
|
{
|
|
Destroy(spawnedFractureRoot);
|
|
spawnedFractureRoot = null;
|
|
}
|
|
|
|
spawnedFractureRoot = Instantiate(
|
|
fracturedPrefab,
|
|
sourceTransform.position,
|
|
sourceTransform.rotation,
|
|
parent);
|
|
spawnedFractureRoot.name = fracturedPrefab.name + "_Exploded";
|
|
|
|
if (disableIntactObjectOnExplode && intactObject != null)
|
|
{
|
|
intactObject.SetActive(false);
|
|
}
|
|
|
|
ApplyExplosionToFragments(spawnedFractureRoot, sourceTransform.position);
|
|
|
|
exploded = true;
|
|
|
|
if (autoCleanupFragments && cleanupDelay > 0f)
|
|
{
|
|
StartCoroutine(CleanupAfterDelay(cleanupDelay));
|
|
}
|
|
}
|
|
|
|
[ContextMenu("Reset Explosion")]
|
|
public void ResetExplosion()
|
|
{
|
|
exploded = false;
|
|
|
|
if (spawnedFractureRoot != null)
|
|
{
|
|
Destroy(spawnedFractureRoot);
|
|
spawnedFractureRoot = null;
|
|
}
|
|
|
|
if (intactObject != null)
|
|
{
|
|
intactObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
private void ApplyExplosionToFragments(GameObject fractureRoot, Vector3 explosionCenter)
|
|
{
|
|
if (fractureRoot == null)
|
|
return;
|
|
|
|
Rigidbody[] rigidbodies = fractureRoot.GetComponentsInChildren<Rigidbody>(true);
|
|
for (int i = 0; i < rigidbodies.Length; i++)
|
|
{
|
|
Rigidbody rb = rigidbodies[i];
|
|
if (rb == null)
|
|
continue;
|
|
|
|
rb.isKinematic = false;
|
|
rb.useGravity = !disableFragmentGravity;
|
|
rb.linearDamping = fragmentDrag;
|
|
rb.angularDamping = fragmentAngularDrag;
|
|
|
|
Vector3 fragmentCenter = rb.worldCenterOfMass;
|
|
Vector3 direction = fragmentCenter - explosionCenter;
|
|
if (direction.sqrMagnitude < 0.0001f)
|
|
{
|
|
direction = Random.onUnitSphere;
|
|
}
|
|
|
|
float randomScale = 1f + Random.Range(-randomForceMultiplier, randomForceMultiplier);
|
|
Vector3 force = direction.normalized * Mathf.Max(0f, explosionForce * randomScale);
|
|
force += Vector3.up * upwardModifier;
|
|
|
|
rb.linearVelocity = Vector3.zero;
|
|
rb.angularVelocity = Vector3.zero;
|
|
rb.AddForce(force, ForceMode.Impulse);
|
|
|
|
if (randomTorque > 0f)
|
|
{
|
|
Vector3 torqueAxis = Random.onUnitSphere * randomTorque;
|
|
rb.AddTorque(torqueAxis, ForceMode.Impulse);
|
|
}
|
|
|
|
if (keepFragmentsClose)
|
|
{
|
|
LimitFragmentVelocity(rb);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LimitFragmentVelocity(Rigidbody rb)
|
|
{
|
|
if (rb == null)
|
|
return;
|
|
|
|
float maxSpeed = Mathf.Max(0.01f, maxFragmentSpeed);
|
|
if (rb.linearVelocity.sqrMagnitude > maxSpeed * maxSpeed)
|
|
{
|
|
rb.linearVelocity = rb.linearVelocity.normalized * maxSpeed;
|
|
}
|
|
}
|
|
|
|
private IEnumerator CleanupAfterDelay(float delay)
|
|
{
|
|
yield return new WaitForSeconds(delay);
|
|
|
|
if (spawnedFractureRoot != null)
|
|
{
|
|
Destroy(spawnedFractureRoot);
|
|
spawnedFractureRoot = null;
|
|
}
|
|
}
|
|
}
|