#if !UNITY_2019_3_OR_NEWER #define CINEMACHINE_PHYSICS #define CINEMACHINE_PHYSICS_2D #endif using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.Playables; namespace Cinemachine { #if !(CINEMACHINE_PHYSICS || CINEMACHINE_PHYSICS_2D) // Workaround for Unity scripting bug /// /// A multi-purpose script which causes an action to occur when /// a trigger collider is entered and exited. /// [AddComponentMenu("")] // Hide in menu public class CinemachineTriggerAction : MonoBehaviour {} #else /// /// A multi-purpose script which causes an action to occur when /// a trigger collider is entered and exited. /// [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)] [SaveDuringPlay] [HelpURL(Documentation.BaseURL + "api/Cinemachine.CinemachineTriggerAction.html")] public class CinemachineTriggerAction : MonoBehaviour { /// Only triggers generated by objects on these layers will be considered. [Header("Trigger Object Filter")] [Tooltip("Only triggers generated by objects on these layers will be considered")] public LayerMask m_LayerMask = 1; /// If set, only triggers generated by objects with this tag will be considered [TagField] [Tooltip("If set, only triggers generated by objects with this tag will be considered")] public string m_WithTag = string.Empty; /// Triggers generated by objects with this tag will be ignored [TagField] [Tooltip("Triggers generated by objects with this tag will be ignored")] public string m_WithoutTag = string.Empty; /// Skip this many trigger entries before taking action [NoSaveDuringPlay] [Tooltip("Skip this many trigger entries before taking action")] public int m_SkipFirst = 0; /// Repeat the action for all subsequent trigger entries [Tooltip("Repeat the action for all subsequent trigger entries")] public bool m_Repeating = true; /// Defines what action to take on trigger enter/exit [Serializable] public struct ActionSettings { /// What action to take public enum Mode { /// Use the event only Custom, /// Boost priority of virtual camera target PriorityBoost, /// Activate the target GameObject Activate, /// Decativate target GameObject Deactivate, /// Enable a component Enable, /// Disable a component Disable, #if CINEMACHINE_TIMELINE /// Start animation on target Play, /// Stop animation on target Stop #endif } /// Serializable parameterless game event [Serializable] public class TriggerEvent : UnityEvent {} /// What action to take [Tooltip("What action to take")] public Mode m_Action; /// The target object on which to operate. If null, then the current behaviour/GameObject will be used [Tooltip("The target object on which to operate. If null, then the current behaviour/GameObject will be used")] public UnityEngine.Object m_Target; /// If PriorityBoost, this amount will be added to the virtual camera's priority [Tooltip("If PriorityBoost, this amount will be added to the virtual camera's priority")] public int m_BoostAmount; /// If playing a timeline, start at this time [Tooltip("If playing a timeline, start at this time")] public float m_StartTime; /// How to interpret the start time public enum TimeMode { /// Offset after the start of the timeline FromStart, /// Offset before the end of the timeline FromEnd, /// Offset before the current timeline time BeforeNow, /// Offset after the current timeline time AfterNow }; /// How to interpret the start time [Tooltip("How to interpret the start time")] public TimeMode m_Mode; /// This event will be invoked [Tooltip("This event will be invoked")] public TriggerEvent m_Event; /// Standard Constructor /// Action to set public ActionSettings(Mode action) { m_Action = action; m_Target = null; m_BoostAmount = 0; m_StartTime = 0; m_Mode = TimeMode.FromStart; m_Event = new TriggerEvent(); } /// Invoke the action. Depending on the mode, different action will /// be performed. The embedded event will always be invoked, in addition to the /// action specified by the Mode. public void Invoke() { UnityEngine.Object currentTarget = m_Target; if (currentTarget != null) { GameObject targetGameObject = currentTarget as GameObject; Behaviour targetBehaviour = currentTarget as Behaviour; if (targetBehaviour != null) targetGameObject = targetBehaviour.gameObject; switch (m_Action) { case Mode.Custom: break; case Mode.PriorityBoost: { CinemachineVirtualCameraBase vcam = targetGameObject.GetComponent(); if (vcam != null) { vcam.Priority += m_BoostAmount; vcam.MoveToTopOfPrioritySubqueue(); } break; } case Mode.Activate: if (targetGameObject != null) { targetGameObject.SetActive(true); CinemachineVirtualCameraBase vcam = targetGameObject.GetComponent(); if (vcam != null) vcam.MoveToTopOfPrioritySubqueue(); } break; case Mode.Deactivate: if (targetGameObject != null) targetGameObject.SetActive(false); break; case Mode.Enable: { if (targetBehaviour != null) targetBehaviour.enabled = true; break; } case Mode.Disable: { if (targetBehaviour != null) targetBehaviour.enabled = false; break; } #if CINEMACHINE_TIMELINE case Mode.Play: { PlayableDirector playable = targetGameObject.GetComponent(); if (playable != null) { double startTime = 0; double duration = playable.duration; double current = playable.time; switch (m_Mode) { default: case TimeMode.FromStart: startTime += m_StartTime; break; case TimeMode.FromEnd: startTime = duration - m_StartTime; break; case TimeMode.BeforeNow: startTime = current - m_StartTime; break; case TimeMode.AfterNow: startTime = current + m_StartTime; break; } playable.time = startTime; playable.Play(); } else { Animation ani = targetGameObject.GetComponent(); if (ani != null) ani.Play(); } break; } case Mode.Stop: { PlayableDirector playable = targetGameObject.GetComponent(); if (playable != null) playable.Stop(); else { Animation ani = targetGameObject.GetComponent(); if (ani != null) ani.Stop(); } break; } #endif } } m_Event.Invoke(); } } /// What action to take when an eligible object enters the collider or trigger zone public ActionSettings m_OnObjectEnter = new ActionSettings(ActionSettings.Mode.Custom); /// What action to take when an eligible object exits the collider or trigger zone public ActionSettings m_OnObjectExit = new ActionSettings(ActionSettings.Mode.Custom); HashSet m_ActiveTriggerObjects = new HashSet(); private bool Filter(GameObject other) { if (!enabled) return false; if (((1 << other.layer) & m_LayerMask) == 0) return false; if (m_WithTag.Length != 0 && !other.CompareTag(m_WithTag)) return false; if (m_WithoutTag.Length != 0 && other.CompareTag(m_WithoutTag)) return false; return true; } void InternalDoTriggerEnter(GameObject other) { if (!Filter(other)) return; --m_SkipFirst; if (m_SkipFirst > -1) return; if (!m_Repeating && m_SkipFirst != -1) return; m_ActiveTriggerObjects.Add(other); m_OnObjectEnter.Invoke(); } void InternalDoTriggerExit(GameObject other) { if (!m_ActiveTriggerObjects.Contains(other)) return; m_ActiveTriggerObjects.Remove(other); if (enabled) m_OnObjectExit.Invoke(); } #if CINEMACHINE_PHYSICS void OnTriggerEnter(Collider other) { InternalDoTriggerEnter(other.gameObject); } void OnTriggerExit(Collider other) { InternalDoTriggerExit(other.gameObject); } void OnCollisionEnter(Collision other) { InternalDoTriggerEnter(other.gameObject); } void OnCollisionExit(Collision other) { InternalDoTriggerExit(other.gameObject); } #endif #if CINEMACHINE_PHYSICS_2D void OnTriggerEnter2D(Collider2D other) { InternalDoTriggerEnter(other.gameObject); } void OnTriggerExit2D(Collider2D other) { InternalDoTriggerExit(other.gameObject); } void OnCollisionEnter2D(Collision2D other) { InternalDoTriggerEnter(other.gameObject); } void OnCollisionExit2D(Collision2D other) { InternalDoTriggerExit(other.gameObject); } #endif void OnEnable() {} // For the Enabled checkbox } #endif }