Files
2026-04-07 03:14:32 +03:00

160 lines
5.1 KiB
C#

using UnityEngine;
using UnityEngine.Events;
namespace YueDestructibles
{
[RequireComponent(typeof(Rigidbody))]
public class YueDestructible : MonoBehaviour
{
[Header("Destruction Properties")]
public float shatterBounceMultiplier = 3f;
public float maximumImpulse = 1.5f;
public float impulseDamageMultiplier = 30f;
public bool accumulateDamage = false;
[Header("Health [%]")]
[SerializeField]
[Range(0f, 100f)]
private float health = 100f;
[Header("Debris Disappearance")]
public bool isDisappearing = true;
public float disappearingTime = 5f;
[Header("Sound Effects")]
public AudioClip[] destructionClips;
public float impulseVolumeFactor = 0.5f;
public YueDestructableAudioSourceTemplate audioSourceTemplate;
[Header("Dependencies")]
public GameObject debrisRoot;
[Header("Events")]
public UnityEvent onObjectDestruct;
// variables
#region
private Renderer mainObjectRenderer;
private Rigidbody[] debris;
private Rigidbody rigid;
private bool isDestructed = false;
private bool isSetup = false;
#endregion
private void Start()
{
// disable deris meshes
debrisRoot.SetActive(false);
// get list of debris rigidbodies
debris = debrisRoot.GetComponentsInChildren<Rigidbody>();
// get renderer to determine object size
mainObjectRenderer = GetComponent<Renderer>();
// get main rigidbody
rigid = GetComponent<Rigidbody>();
// check UnityEvent
if (onObjectDestruct == null)
onObjectDestruct = new UnityEvent();
isSetup = true;
}
private void OnCollisionEnter(Collision collision)
{
if (!isSetup)
return;
if (collision.impulse.magnitude > maximumImpulse)
{
DestructWithImpulse(collision.impulse, collision.GetContact(0).point);
}
if (!accumulateDamage)
return;
health -= collision.impulse.magnitude * impulseDamageMultiplier;
if (health < 0f)
DestructWithImpulse(collision.impulse, collision.GetContact(0).point);
}
public void DestructWithImpulse(Vector3 impulse, Vector3 point)
{
if (isDestructed)
return;
if (debris.Length <= 0)
return;
// active and unparent root
debrisRoot.SetActive(true);
debrisRoot.transform.parent = null;
// inherit main rigid velocity
foreach (Rigidbody rb in debris)
{
if (!rb)
break;
// set active
rb.gameObject.SetActive(true);
// apply propertie
rb.mass = rigid.mass / debris.Length;
rb.drag = rigid.drag;
rb.angularDrag = rigid.angularDrag;
// add velocity
rb.velocity = rigid.velocity;
rb.angularVelocity = rigid.angularVelocity;
// add impulse
rb.AddExplosionForce(impulse.magnitude * shatterBounceMultiplier, point, mainObjectRenderer.bounds.max.magnitude);
}
// create sound effect
CreateAudioEffect(impulse, point);
// set flag
isDestructed = true;
// setup root, if disappearing
if (isDisappearing)
{
debrisRoot.AddComponent<YueDestructiblesRoot>();
debrisRoot.GetComponent<YueDestructiblesRoot>().SetDebris(debris);
debrisRoot.GetComponent<YueDestructiblesRoot>().SetDisappearingTime(disappearingTime);
}
// invoke event
onObjectDestruct.Invoke();
// destroy intact object
Destroy(this.gameObject);
}
public void DestructSimple()
{
DestructWithImpulse(Vector3.zero, transform.position);
}
public void AddDamage(float damageInPercent)
{
health -= damageInPercent;
}
private void CreateAudioEffect(Vector3 impulse, Vector3 point)
{
if (destructionClips.Length <= 0)
return;
// instatiate sound effect
GameObject effect = Instantiate<GameObject>(audioSourceTemplate.gameObject, point, Quaternion.identity);
// init debris
YueDestructableAudioSourceTemplate templateClone = effect.GetComponent<YueDestructableAudioSourceTemplate>();
templateClone.debris = debrisRoot.GetComponentsInChildren<Transform>();
templateClone.audioSource.volume = impulseVolumeFactor * impulse.magnitude;
// play random sound
templateClone.audioSource.PlayOneShot(destructionClips[Random.Range(0, destructionClips.Length)]);
Destroy(effect, 5f);
}
}
}