CinemachineTriggerAction.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #if !UNITY_2019_3_OR_NEWER
  2. #define CINEMACHINE_PHYSICS
  3. #define CINEMACHINE_PHYSICS_2D
  4. #endif
  5. using System;
  6. using System.Collections.Generic;
  7. using UnityEngine;
  8. using UnityEngine.Events;
  9. using UnityEngine.Playables;
  10. namespace Cinemachine
  11. {
  12. #if !(CINEMACHINE_PHYSICS || CINEMACHINE_PHYSICS_2D)
  13. // Workaround for Unity scripting bug
  14. /// <summary>
  15. /// A multi-purpose script which causes an action to occur when
  16. /// a trigger collider is entered and exited.
  17. /// </summary>
  18. [AddComponentMenu("")] // Hide in menu
  19. public class CinemachineTriggerAction : MonoBehaviour {}
  20. #else
  21. /// <summary>
  22. /// A multi-purpose script which causes an action to occur when
  23. /// a trigger collider is entered and exited.
  24. /// </summary>
  25. [DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
  26. [SaveDuringPlay]
  27. [HelpURL(Documentation.BaseURL + "api/Cinemachine.CinemachineTriggerAction.html")]
  28. public class CinemachineTriggerAction : MonoBehaviour
  29. {
  30. /// <summary>Only triggers generated by objects on these layers will be considered.</summary>
  31. [Header("Trigger Object Filter")]
  32. [Tooltip("Only triggers generated by objects on these layers will be considered")]
  33. public LayerMask m_LayerMask = 1;
  34. /// <summary>If set, only triggers generated by objects with this tag will be considered</summary>
  35. [TagField]
  36. [Tooltip("If set, only triggers generated by objects with this tag will be considered")]
  37. public string m_WithTag = string.Empty;
  38. /// <summary>Triggers generated by objects with this tag will be ignored</summary>
  39. [TagField]
  40. [Tooltip("Triggers generated by objects with this tag will be ignored")]
  41. public string m_WithoutTag = string.Empty;
  42. /// <summary>Skip this many trigger entries before taking action</summary>
  43. [NoSaveDuringPlay]
  44. [Tooltip("Skip this many trigger entries before taking action")]
  45. public int m_SkipFirst = 0;
  46. /// <summary>Repeat the action for all subsequent trigger entries</summary>
  47. [Tooltip("Repeat the action for all subsequent trigger entries")]
  48. public bool m_Repeating = true;
  49. /// <summary>Defines what action to take on trigger enter/exit</summary>
  50. [Serializable]
  51. public struct ActionSettings
  52. {
  53. /// <summary>What action to take</summary>
  54. public enum Mode
  55. {
  56. /// <summary>Use the event only</summary>
  57. Custom,
  58. /// <summary>Boost priority of virtual camera target</summary>
  59. PriorityBoost,
  60. /// <summary>Activate the target GameObject</summary>
  61. Activate,
  62. /// <summary>Decativate target GameObject</summary>
  63. Deactivate,
  64. /// <summary>Enable a component</summary>
  65. Enable,
  66. /// <summary>Disable a component</summary>
  67. Disable,
  68. #if CINEMACHINE_TIMELINE
  69. /// <summary>Start animation on target</summary>
  70. Play,
  71. /// <summary>Stop animation on target</summary>
  72. Stop
  73. #endif
  74. }
  75. /// <summary>Serializable parameterless game event</summary>
  76. [Serializable] public class TriggerEvent : UnityEvent {}
  77. /// <summary>What action to take</summary>
  78. [Tooltip("What action to take")]
  79. public Mode m_Action;
  80. /// <summary>The target object on which to operate. If null, then the current behaviour/GameObject will be used</summary>
  81. [Tooltip("The target object on which to operate. If null, then the current behaviour/GameObject will be used")]
  82. public UnityEngine.Object m_Target;
  83. /// <summary>If PriorityBoost, this amount will be added to the virtual camera's priority</summary>
  84. [Tooltip("If PriorityBoost, this amount will be added to the virtual camera's priority")]
  85. public int m_BoostAmount;
  86. /// <summary>If playing a timeline, start at this time</summary>
  87. [Tooltip("If playing a timeline, start at this time")]
  88. public float m_StartTime;
  89. /// <summary>How to interpret the start time</summary>
  90. public enum TimeMode
  91. {
  92. /// <summary>Offset after the start of the timeline</summary>
  93. FromStart,
  94. /// <summary>Offset before the end of the timeline</summary>
  95. FromEnd,
  96. /// <summary>Offset before the current timeline time</summary>
  97. BeforeNow,
  98. /// <summary>Offset after the current timeline time</summary>
  99. AfterNow
  100. };
  101. /// <summary>How to interpret the start time</summary>
  102. [Tooltip("How to interpret the start time")]
  103. public TimeMode m_Mode;
  104. /// <summary>This event will be invoked</summary>
  105. [Tooltip("This event will be invoked")]
  106. public TriggerEvent m_Event;
  107. /// <summary>Standard Constructor</summary>
  108. /// <param name="action">Action to set</param>
  109. public ActionSettings(Mode action)
  110. {
  111. m_Action = action;
  112. m_Target = null;
  113. m_BoostAmount = 0;
  114. m_StartTime = 0;
  115. m_Mode = TimeMode.FromStart;
  116. m_Event = new TriggerEvent();
  117. }
  118. /// <summary>Invoke the action. Depending on the mode, different action will
  119. /// be performed. The embedded event will always be invoked, in addition to the
  120. /// action specified by the Mode.</summary>
  121. public void Invoke()
  122. {
  123. UnityEngine.Object currentTarget = m_Target;
  124. if (currentTarget != null)
  125. {
  126. GameObject targetGameObject = currentTarget as GameObject;
  127. Behaviour targetBehaviour = currentTarget as Behaviour;
  128. if (targetBehaviour != null)
  129. targetGameObject = targetBehaviour.gameObject;
  130. switch (m_Action)
  131. {
  132. case Mode.Custom:
  133. break;
  134. case Mode.PriorityBoost:
  135. {
  136. CinemachineVirtualCameraBase vcam
  137. = targetGameObject.GetComponent<CinemachineVirtualCameraBase>();
  138. if (vcam != null)
  139. {
  140. vcam.Priority += m_BoostAmount;
  141. vcam.MoveToTopOfPrioritySubqueue();
  142. }
  143. break;
  144. }
  145. case Mode.Activate:
  146. if (targetGameObject != null)
  147. {
  148. targetGameObject.SetActive(true);
  149. CinemachineVirtualCameraBase vcam
  150. = targetGameObject.GetComponent<CinemachineVirtualCameraBase>();
  151. if (vcam != null)
  152. vcam.MoveToTopOfPrioritySubqueue();
  153. }
  154. break;
  155. case Mode.Deactivate:
  156. if (targetGameObject != null)
  157. targetGameObject.SetActive(false);
  158. break;
  159. case Mode.Enable:
  160. {
  161. if (targetBehaviour != null)
  162. targetBehaviour.enabled = true;
  163. break;
  164. }
  165. case Mode.Disable:
  166. {
  167. if (targetBehaviour != null)
  168. targetBehaviour.enabled = false;
  169. break;
  170. }
  171. #if CINEMACHINE_TIMELINE
  172. case Mode.Play:
  173. {
  174. PlayableDirector playable
  175. = targetGameObject.GetComponent<PlayableDirector>();
  176. if (playable != null)
  177. {
  178. double startTime = 0;
  179. double duration = playable.duration;
  180. double current = playable.time;
  181. switch (m_Mode)
  182. {
  183. default:
  184. case TimeMode.FromStart:
  185. startTime += m_StartTime;
  186. break;
  187. case TimeMode.FromEnd:
  188. startTime = duration - m_StartTime;
  189. break;
  190. case TimeMode.BeforeNow:
  191. startTime = current - m_StartTime;
  192. break;
  193. case TimeMode.AfterNow:
  194. startTime = current + m_StartTime;
  195. break;
  196. }
  197. playable.time = startTime;
  198. playable.Play();
  199. }
  200. else
  201. {
  202. Animation ani = targetGameObject.GetComponent<Animation>();
  203. if (ani != null)
  204. ani.Play();
  205. }
  206. break;
  207. }
  208. case Mode.Stop:
  209. {
  210. PlayableDirector playable
  211. = targetGameObject.GetComponent<PlayableDirector>();
  212. if (playable != null)
  213. playable.Stop();
  214. else
  215. {
  216. Animation ani = targetGameObject.GetComponent<Animation>();
  217. if (ani != null)
  218. ani.Stop();
  219. }
  220. break;
  221. }
  222. #endif
  223. }
  224. }
  225. m_Event.Invoke();
  226. }
  227. }
  228. /// <summary>What action to take when an eligible object enters the collider or trigger zone</summary>
  229. public ActionSettings m_OnObjectEnter = new ActionSettings(ActionSettings.Mode.Custom);
  230. /// <summary>What action to take when an eligible object exits the collider or trigger zone</summary>
  231. public ActionSettings m_OnObjectExit = new ActionSettings(ActionSettings.Mode.Custom);
  232. HashSet<GameObject> m_ActiveTriggerObjects = new HashSet<GameObject>();
  233. private bool Filter(GameObject other)
  234. {
  235. if (!enabled)
  236. return false;
  237. if (((1 << other.layer) & m_LayerMask) == 0)
  238. return false;
  239. if (m_WithTag.Length != 0 && !other.CompareTag(m_WithTag))
  240. return false;
  241. if (m_WithoutTag.Length != 0 && other.CompareTag(m_WithoutTag))
  242. return false;
  243. return true;
  244. }
  245. void InternalDoTriggerEnter(GameObject other)
  246. {
  247. if (!Filter(other))
  248. return;
  249. --m_SkipFirst;
  250. if (m_SkipFirst > -1)
  251. return;
  252. if (!m_Repeating && m_SkipFirst != -1)
  253. return;
  254. m_ActiveTriggerObjects.Add(other);
  255. m_OnObjectEnter.Invoke();
  256. }
  257. void InternalDoTriggerExit(GameObject other)
  258. {
  259. if (!m_ActiveTriggerObjects.Contains(other))
  260. return;
  261. m_ActiveTriggerObjects.Remove(other);
  262. if (enabled)
  263. m_OnObjectExit.Invoke();
  264. }
  265. #if CINEMACHINE_PHYSICS
  266. void OnTriggerEnter(Collider other) { InternalDoTriggerEnter(other.gameObject); }
  267. void OnTriggerExit(Collider other) { InternalDoTriggerExit(other.gameObject); }
  268. void OnCollisionEnter(Collision other) { InternalDoTriggerEnter(other.gameObject); }
  269. void OnCollisionExit(Collision other) { InternalDoTriggerExit(other.gameObject); }
  270. #endif
  271. #if CINEMACHINE_PHYSICS_2D
  272. void OnTriggerEnter2D(Collider2D other) { InternalDoTriggerEnter(other.gameObject); }
  273. void OnTriggerExit2D(Collider2D other) { InternalDoTriggerExit(other.gameObject); }
  274. void OnCollisionEnter2D(Collision2D other) { InternalDoTriggerEnter(other.gameObject); }
  275. void OnCollisionExit2D(Collision2D other) { InternalDoTriggerExit(other.gameObject); }
  276. #endif
  277. void OnEnable() {} // For the Enabled checkbox
  278. }
  279. #endif
  280. }