using UnityEngine; using UnityEngine.Serialization; namespace Unity.Cinemachine { #if !(CINEMACHINE_PHYSICS || CINEMACHINE_PHYSICS_2D) /// If Physics or Physics 2D is part of the project, this would generate inpulse events. [AddComponentMenu("")] // Hide in menu public class CinemachineCollisionImpulseSource : CinemachineImpulseSource {} #else /// /// Generate an Impulse Event this object's Collider collides with something /// or its trigger zone is entered. /// /// This component should be attached to a GameObject with a Collider or a Collider2D. /// Objects colliding with this (or entering its trigger zone if it's a trigger) will be /// filtered according to the layer and tag settings defined here, and if they /// pass the filter, they will cause an impulse event to be generated. /// [SaveDuringPlay] [AddComponentMenu("Cinemachine/Helpers/Cinemachine Collision Impulse Source")] [HelpURL(Documentation.BaseURL + "manual/CinemachineCollisionImpulseSource.html")] public class CinemachineCollisionImpulseSource : CinemachineImpulseSource { /// Only collisions with objects on these layers will generate Impulse events. [Header("Trigger Object Filter")] [Tooltip("Only collisions with objects on these layers will generate Impulse events")] [FormerlySerializedAs("m_LayerMask")] public LayerMask LayerMask = 1; /// No Impulse events will be generated for collisions with objects having these tags [TagField] [Tooltip("No Impulse events will be generated for collisions with objects having these tags")] [FormerlySerializedAs("m_IgnoreTag")] public string IgnoreTag = string.Empty; /// If checked, signal direction will be affected by the direction of impact [Header("How To Generate The Impulse")] [Tooltip("If checked, signal direction will be affected by the direction of impact")] [FormerlySerializedAs("m_UseImpactDirection")] public bool UseImpactDirection = false; /// If checked, signal amplitude will be multiplied by the mass of the impacting object [Tooltip("If checked, signal amplitude will be multiplied by the mass of the impacting object")] [FormerlySerializedAs("m_ScaleImpactWithMass")] public bool ScaleImpactWithMass = false; /// If checked, signal amplitude will be multiplied by the speed of the impacting object [Tooltip("If checked, signal amplitude will be multiplied by the speed of the impacting object")] [FormerlySerializedAs("m_ScaleImpactWithSpeed")] public bool ScaleImpactWithSpeed = false; #if CINEMACHINE_PHYSICS Rigidbody m_RigidBody; #endif #if CINEMACHINE_PHYSICS_2D Rigidbody2D m_RigidBody2D; #endif void Reset() { LayerMask = 1; IgnoreTag = string.Empty; UseImpactDirection = false; ScaleImpactWithMass = false; ScaleImpactWithSpeed = false; } void Start() { #if CINEMACHINE_PHYSICS TryGetComponent(out m_RigidBody); #endif #if CINEMACHINE_PHYSICS_2D TryGetComponent(out m_RigidBody2D); #endif } void OnEnable() {} // For the Enabled checkbox #if CINEMACHINE_PHYSICS void OnCollisionEnter(Collision c) { GenerateImpactEvent(c.collider, c.relativeVelocity); } void OnTriggerEnter(Collider c) { GenerateImpactEvent(c, Vector3.zero); } float GetMassAndVelocity(Collider other, ref Vector3 vel) { bool getVelocity = vel == Vector3.zero; float mass = 1; if (ScaleImpactWithMass || ScaleImpactWithSpeed || UseImpactDirection) { if (m_RigidBody != null) { if (ScaleImpactWithMass) mass *= m_RigidBody.mass; if (getVelocity) #if UNITY_2023_3_OR_NEWER vel = -m_RigidBody.linearVelocity; #else vel = -m_RigidBody.velocity; #endif } var rb = other != null ? other.attachedRigidbody : null; if (rb != null) { if (ScaleImpactWithMass) mass *= rb.mass; if (getVelocity) #if UNITY_2023_3_OR_NEWER vel += rb.linearVelocity; #else vel += rb.velocity; #endif } } return mass; } void GenerateImpactEvent(Collider other, Vector3 vel) { // Check the filters if (!enabled) return; if (other != null) { int layer = other.gameObject.layer; if (((1 << layer) & LayerMask) == 0) return; if (IgnoreTag.Length != 0 && other.CompareTag(IgnoreTag)) return; } // Calculate the signal direction and magnitude float mass = GetMassAndVelocity(other, ref vel); if (ScaleImpactWithSpeed) mass *= Mathf.Sqrt(vel.magnitude); Vector3 dir = DefaultVelocity; if (UseImpactDirection && !vel.AlmostZero()) dir = -vel.normalized * dir.magnitude; // Fire it off! GenerateImpulseWithVelocity(dir * mass); } #endif #if CINEMACHINE_PHYSICS_2D void OnCollisionEnter2D(Collision2D c) { GenerateImpactEvent2D(c.collider, c.relativeVelocity); } void OnTriggerEnter2D(Collider2D c) { GenerateImpactEvent2D(c, Vector3.zero); } float GetMassAndVelocity2D(Collider2D other2d, ref Vector3 vel) { bool getVelocity = vel == Vector3.zero; float mass = 1; if (ScaleImpactWithMass || ScaleImpactWithSpeed || UseImpactDirection) { if (m_RigidBody2D != null) { if (ScaleImpactWithMass) mass *= m_RigidBody2D.mass; if (getVelocity) vel = -m_RigidBody2D.velocity; } var rb2d = other2d != null ? other2d.attachedRigidbody : null; if (rb2d != null) { if (ScaleImpactWithMass) mass *= rb2d.mass; if (getVelocity) { Vector3 v = rb2d.velocity; vel += v; } } } return mass; } void GenerateImpactEvent2D(Collider2D other2d, Vector3 vel) { // Check the filters if (!enabled) return; if (other2d != null) { int layer = other2d.gameObject.layer; if (((1 << layer) & LayerMask) == 0) return; if (IgnoreTag.Length != 0 && other2d.CompareTag(IgnoreTag)) return; } // Calculate the signal direction and magnitude float mass = GetMassAndVelocity2D(other2d, ref vel); if (ScaleImpactWithSpeed) mass *= Mathf.Sqrt(vel.magnitude); Vector3 dir = DefaultVelocity; if (UseImpactDirection && !vel.AlmostZero()) dir = -vel.normalized * dir.magnitude; // Fire it off! GenerateImpulseWithVelocity(dir * mass); } #endif } #endif }