Files
bansonic_beta_main/Assets/scripts/Utilities/Explosion3DTestController.cs
T

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;
}
}
}