FEvent.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. using UnityEngine;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Security;
  5. namespace Flux
  6. {
  7. [Serializable]
  8. /**
  9. * @brief Range of frames.
  10. * @note Start is _not_ guaranteed to be smaller or equal to End, it is up to the user to make sure.
  11. */
  12. public struct FrameRange
  13. {
  14. // start frame
  15. [SerializeField]
  16. private int _start;
  17. // end frame
  18. [SerializeField]
  19. private int _end;
  20. /// @brief Returns the start frame.
  21. public int Start
  22. {
  23. get { return _start; }
  24. set
  25. {
  26. _start = value;
  27. }
  28. }
  29. /// @brief Returns the end frame.
  30. public int End
  31. {
  32. get { return _end; }
  33. set
  34. {
  35. _end = value;
  36. }
  37. }
  38. /// @brief Sets / Gets the length.
  39. /// @note It doesn't cache the value.
  40. public int Length { set{ End = _start + value; } get{ return _end - _start; } }
  41. /**
  42. * @brief Create a frame range
  43. * @param start Start frame
  44. * @param end End frame
  45. * @note It is up to you to make sure start is smaller than end.
  46. */
  47. public FrameRange( int start, int end )
  48. {
  49. this._start = start;
  50. this._end = end;
  51. }
  52. /// @brief Returns \e i clamped to the range.
  53. public int Cull( int i )
  54. {
  55. return Mathf.Clamp( i, _start, _end );
  56. }
  57. /// @brief Returns if \e i is inside [start, end], i.e. including borders
  58. public bool Contains( int i )
  59. {
  60. return i >= _start && i <= _end;
  61. }
  62. /// @brief Returns if \e i is inside ]start, end[, i.e. excluding borders
  63. public bool ContainsExclusive( int i )
  64. {
  65. return i > _start && i < _end;
  66. }
  67. /// @brief Returns if the ranges intersect, i.e. touching returns false
  68. /// @note Assumes They are both valid
  69. public bool Collides( FrameRange range )
  70. {
  71. return _start < range._end && _end > range._start;
  72. // return (range.start > start && range.start < end) || (range.end > start && range.end < end );
  73. }
  74. /// @brief Returns if the ranges overlap, i.e. touching return true
  75. /// @note Assumes They are both valid
  76. public bool Overlaps( FrameRange range )
  77. {
  78. return range.End >= _start && range.Start <= _end;
  79. }
  80. /// @brief Returns what kind of overlap it has with \e range.
  81. /// @note Assumes They are both valid
  82. public FrameRangeOverlap GetOverlap( FrameRange range )
  83. {
  84. if( range._start >= _start )
  85. {
  86. // contains, left or none
  87. if( range._end <= _end )
  88. {
  89. return FrameRangeOverlap.ContainsFull;
  90. }
  91. else
  92. {
  93. if( range._start > _end )
  94. {
  95. return FrameRangeOverlap.MissOnRight;
  96. }
  97. return FrameRangeOverlap.ContainsStart;
  98. }
  99. }
  100. else
  101. {
  102. // contained, right or none
  103. if( range._end < _start )
  104. {
  105. return FrameRangeOverlap.MissOnLeft;
  106. }
  107. else
  108. {
  109. if( range._end > _end )
  110. {
  111. return FrameRangeOverlap.IsContained;
  112. }
  113. return FrameRangeOverlap.ContainsEnd;
  114. }
  115. }
  116. }
  117. public static bool operator ==( FrameRange a, FrameRange b )
  118. {
  119. return a._start == b._start && a._end == b._end;
  120. }
  121. public static bool operator !=( FrameRange a, FrameRange b )
  122. {
  123. return !(a == b);
  124. }
  125. public override bool Equals( object obj )
  126. {
  127. if( obj.GetType() != GetType() )
  128. return false;
  129. return (FrameRange)obj == this;
  130. }
  131. public override int GetHashCode()
  132. {
  133. return _start + _end;
  134. }
  135. public override string ToString()
  136. {
  137. return string.Format("[{0}; {1}]", _start, _end);
  138. }
  139. }
  140. /// @brief Types of range overlap
  141. public enum FrameRangeOverlap
  142. {
  143. MissOnLeft = -2, /// @brief missed and is to the left of the range passed
  144. MissOnRight, /// @brief missed and is to the right of the range passed
  145. IsContained, /// @brief overlaps and is contained by the range passed
  146. ContainsFull, /// @brief overlaps and contains the range passed
  147. ContainsStart, /// @brief overlaps and contains the start of the range passed
  148. ContainsEnd /// @brief overlaps and contains the end of the range passed
  149. }
  150. public class FEventParam
  151. {
  152. public string name;
  153. public string val;
  154. public string valType;
  155. }
  156. /**
  157. * @brief Base class for Events
  158. * @sa FSequence, FTimeline, FTrack.
  159. */
  160. public class FEvent : FObject
  161. {
  162. public override Transform Owner { get { return _track.Owner; } }
  163. public override FSequence Sequence { get { return _track.Sequence; } }
  164. // track that owns this event
  165. [SerializeField]
  166. [HideInInspector]
  167. protected FTrack _track = null;
  168. /// @brief Returns the track it belongs to
  169. public FTrack Track { get { return _track; } }
  170. [SerializeField]
  171. [HideInInspector]
  172. private bool _triggerOnSkip = true;
  173. /// @brief Should this event trigger if you skip it?
  174. public bool TriggerOnSkip { get { return _triggerOnSkip; } set { _triggerOnSkip = value; } }
  175. [SerializeField]
  176. [HideInInspector]
  177. private FrameRange _frameRange;
  178. /// @brief Range of the event.
  179. public FrameRange FrameRange { get { return _frameRange; }
  180. set {
  181. FrameRange oldFrameRange = _frameRange;
  182. _frameRange = value; OnFrameRangeChanged( oldFrameRange );
  183. }
  184. }
  185. // has this event called Trigger already?
  186. private bool _hasTriggered = false;
  187. /// @brief Has Trigger been called already?
  188. public bool HasTriggered { get { return _hasTriggered; } }
  189. // has this event called Finish already?
  190. private bool _hasFinished = false;
  191. /// @brief Has Finish been called already?
  192. public bool HasFinished { get { return _hasFinished; } }
  193. public virtual string Text { get { return null; } set { } }
  194. protected Transform _casterTrans;
  195. protected Transform _targetTrans;
  196. protected Transform _cameraTrans;
  197. protected SkillActionFrameEventType _eventType = SkillActionFrameEventType.FE_NONE;
  198. public SkillActionFrameEventType EventType
  199. {
  200. get { return _eventType; }
  201. }
  202. protected List<FEventParam> _eventParams;
  203. /**
  204. * @brief Create an event. Should be used to create events since it also
  205. * calls SetDefaultValues.
  206. * @param range Range of the event.
  207. */
  208. public static T Create<T>( FrameRange range ) where T : FEvent
  209. {
  210. GameObject go = new GameObject( typeof(T).ToString() );
  211. T evt = go.AddComponent<T>();
  212. evt._frameRange = new FrameRange( range.Start, range.End );
  213. return evt;
  214. }
  215. /// @overload
  216. public static FEvent Create( Type evtType, FrameRange range )
  217. {
  218. GameObject go = new GameObject( evtType.ToString() );
  219. FEvent evt = (FEvent)go.AddComponent(evtType);
  220. evt._frameRange = new FrameRange( range.Start, range.End );
  221. return evt;
  222. }
  223. // sets the track this event belongs to, to be called only by FTrack
  224. internal void SetTrack( FTrack track )
  225. {
  226. _track = track;
  227. if( _track )
  228. {
  229. transform.parent = _track.transform;
  230. }
  231. else
  232. {
  233. transform.parent = null;
  234. }
  235. }
  236. /// @brief Use this function to setup default values for when events get created
  237. public void SetDefaultValues()
  238. {
  239. OnSetDefaultValues();
  240. }
  241. /// @brief Use this function if you want to do something to the event when the frame range
  242. /// changed, e.g. adjust some variables to the new event size.
  243. /// @param oldFrameRange Previous FrameRange, the current one is set on the event.
  244. protected virtual void OnFrameRangeChanged( FrameRange oldFrameRange )
  245. {
  246. }
  247. /**
  248. * @brief Called when the event gets reached.
  249. * The reason we pass the time is because they may have been frames skipped
  250. * or simply we may have jumped into the middle of an event, and that allows you
  251. * to skip to the right point. E.g. useful when you want to play an animation,
  252. * if you jumped to the middle of it you want to tell mecanim to start in the middle,
  253. * not at the start.
  254. * @param frameSinceTrigger Frames that passed since the actual TriggerFrame
  255. * @param timeSinceTrigger Time passed since the actual TriggerFrame
  256. * @sa TriggerFrame, TriggerTime, Finish
  257. */
  258. public void Trigger( float timeSinceTrigger )
  259. {
  260. _hasTriggered = true;
  261. OnTrigger( timeSinceTrigger );
  262. }
  263. /// @brief At which frame will the event trigger, basically the start of it's range.
  264. public int TriggerFrame { get { return _frameRange.Start; } }
  265. /// @brief At which time the event triggers.
  266. /// @note Value isn't cached.
  267. public float TriggerTime { get { return _frameRange.Start * Sequence.InverseFrameRate; } }
  268. /**
  269. * @brief Used to setup your own code when Trigger is called.
  270. * @param framesSinceTrigger Frames passed since TriggerFrame
  271. * @param timeSinceTrigger Time passed since timeSinceTrigger
  272. */
  273. protected virtual void OnTrigger( float timeSinceTrigger ){ }
  274. /**
  275. * @brief Called when the event ends, i.e. we pass the end of it's range.
  276. * @sa Trigger
  277. */
  278. public void Finish()
  279. {
  280. _hasFinished = true;
  281. #if UNITY_EDITOR
  282. PreEvent();
  283. #endif
  284. if( Sequence.IsPlayingForward )
  285. OnFinish(); // only do this code if we're moving forward, otherwise it doesn't really matter
  286. #if UNITY_EDITOR
  287. PostEvent();
  288. #endif
  289. }
  290. /// @brief Used to setup your own code when Finish is called.
  291. protected virtual void OnFinish(){ }
  292. public sealed override void Init()
  293. {
  294. _hasTriggered = false;
  295. _hasFinished = false;
  296. // init doesn't get wrapped between Pre/PostEvent because
  297. // it is here that vars will be initialized
  298. OnInit();
  299. }
  300. protected virtual void OnSetDefaultValues()
  301. {
  302. if (Sequence.CasterActor != null)
  303. {
  304. _casterTrans = Sequence.CasterActor.transform;
  305. }
  306. if (Sequence.TargetActor != null)
  307. {
  308. _targetTrans = Sequence.TargetActor.transform;
  309. }
  310. if (Sequence.CameraGo != null)
  311. {
  312. _cameraTrans = Sequence.CameraGo.transform;
  313. }
  314. }
  315. /// @brief Used to setup your own code for when the sequence is initialized
  316. protected virtual void OnInit()
  317. {
  318. }
  319. public void Pause()
  320. {
  321. #if UNITY_EDITOR
  322. PreEvent();
  323. #endif
  324. OnPause();
  325. #if UNITY_EDITOR
  326. PostEvent();
  327. #endif
  328. }
  329. /// @brief Used to setup your own code for when the sequence is paused
  330. protected virtual void OnPause() { }
  331. public void Resume()
  332. {
  333. #if UNITY_EDITOR
  334. PreEvent();
  335. #endif
  336. OnResume();
  337. #if UNITY_EDITOR
  338. PostEvent();
  339. #endif
  340. }
  341. /// @brief Used to setup your own code for when the sequence is resumed
  342. protected virtual void OnResume() { }
  343. public sealed override void Stop()
  344. {
  345. _hasTriggered = false;
  346. _hasFinished = false;
  347. #if UNITY_EDITOR
  348. PreEvent();
  349. #endif
  350. OnStop();
  351. #if UNITY_EDITOR
  352. PostEvent();
  353. #endif
  354. }
  355. /// @brief Used to setup your own code for when the sequence is stopped
  356. protected virtual void OnStop(){}
  357. /**
  358. * @brief Called each time the sequence gets updated, if the current frame is in this event's range.
  359. * @param framesSinceTrigger How many frames have passed since TriggerFrame
  360. * @param timeSinceTrigger How much time passed since TriggerFrame
  361. */
  362. public void UpdateEvent( int framesSinceTrigger, float timeSinceTrigger )
  363. {
  364. #if UNITY_EDITOR
  365. PreEvent();
  366. #endif
  367. if( !_hasTriggered )
  368. {
  369. Trigger( timeSinceTrigger );
  370. }
  371. OnUpdateEvent( timeSinceTrigger );
  372. if( framesSinceTrigger == Length )
  373. {
  374. Finish();
  375. }
  376. #if UNITY_EDITOR
  377. PostEvent();
  378. #endif
  379. }
  380. /**
  381. * @brief Used to setup your code that gets called when the event updates.
  382. * @param framesSinceTrigger How many frames passed since TriggerFrame
  383. * @param timeSinceTrigger How much time passed since TriggerFrame
  384. */
  385. protected virtual void OnUpdateEvent( float timeSinceTrigger )
  386. {
  387. }
  388. /**
  389. * @brief Used to mark objects used as not to be saved, in order to not make the scene dirty when
  390. * scrubbing the editor.
  391. * @note This is called before every call to FEvent, i.e. Trigger, UpdateEvent, Stop, etc.
  392. */
  393. protected virtual void PreEvent()
  394. {
  395. #if UNITY_EDITOR
  396. if( !Application.isPlaying )
  397. Owner.gameObject.hideFlags = HideFlags.DontSave;
  398. #endif
  399. }
  400. /**
  401. * @brief Used to mark objects used as to be saved again.
  402. * @note This is called after every call to FEvent, i.e. Trigger, UpdateEvent, Stop, etc.
  403. */
  404. protected virtual void PostEvent()
  405. {
  406. #if UNITY_EDITOR
  407. if( !Application.isPlaying )
  408. Owner.gameObject.hideFlags = HideFlags.None;
  409. #endif
  410. }
  411. /// @brief Returns \e true if it is the first event of the track it belongs to.
  412. public bool IsFirstEvent { get { return GetId() == 0; } }
  413. /// @brief Returns \e true if it is the last event of the track it belongs to.
  414. public bool IsLastEvent { get { return GetId() == _track.Events.Count-1; } }
  415. /// @brief Shortcut to FrameRange.Start
  416. public int Start
  417. {
  418. get{ return _frameRange.Start; }
  419. set{ _frameRange.Start = value; }
  420. }
  421. /// @brief Shortcut to FrameRange.End
  422. public int End
  423. {
  424. get { return _frameRange.End; }
  425. set{ _frameRange.End = value; }
  426. }
  427. /// @brief Shortcut to FrameRange.Length
  428. public int Length
  429. {
  430. get{ return _frameRange.Length; }
  431. set{ _frameRange.Length = value; }
  432. }
  433. /// @brief What this the event starts.
  434. /// @note This value isn't cached.
  435. public float StartTime
  436. {
  437. get { return _frameRange.Start * Sequence.InverseFrameRate; }
  438. }
  439. /// @brief What this the event ends.
  440. /// @note This value isn't cached.
  441. public float EndTime
  442. {
  443. get { return _frameRange.End * Sequence.InverseFrameRate; }
  444. }
  445. /// @brief Length of the event in seconds.
  446. /// @note This value isn't cached.
  447. public float LengthTime
  448. {
  449. get { return _frameRange.Length * Sequence.InverseFrameRate; }
  450. }
  451. /// @brief What's the minimum length this event can have?
  452. /// @warning Events cannot be smaller than 1 frame.
  453. public virtual int GetMinLength()
  454. {
  455. return 1;
  456. }
  457. /// @brief What's the maximum length this event can have?
  458. public virtual int GetMaxLength()
  459. {
  460. return int.MaxValue;
  461. }
  462. public virtual SecurityElement SaveToXml()
  463. {
  464. int eventType = (int)EventType;
  465. SecurityElement node = new SecurityElement("event");
  466. node.AddAttribute("startFrame", this.FrameRange.Start.ToString());
  467. node.AddAttribute("endFrame", this.FrameRange.End.ToString());
  468. node.AddAttribute("type", eventType.ToString());
  469. return node;
  470. }
  471. public SecurityElement WriteParamNode(string paramName, string paramVal, string paramValueType)
  472. {
  473. if (string.IsNullOrEmpty(paramName) || string.IsNullOrEmpty(paramVal) || string.IsNullOrEmpty(paramValueType)) return null;
  474. SecurityElement paramNode = new SecurityElement("param");
  475. paramNode.AddAttribute("name", paramName);
  476. paramNode.AddAttribute("value", paramVal);
  477. paramNode.AddAttribute("valueType", paramValueType);
  478. return paramNode;
  479. }
  480. public virtual void LoadFromXml(SecurityElement eventNode)
  481. {
  482. if (eventNode == null || eventNode.Children == null) return;
  483. _eventParams = new List<FEventParam>();
  484. for (int idx = 0; idx < eventNode.Children.Count; idx++)
  485. {
  486. var paramNode = eventNode.Children[idx] as SecurityElement;
  487. FEventParam param = new FEventParam();
  488. param.name = paramNode.Attribute("name");
  489. param.val = paramNode.Attribute("value");
  490. param.valType = paramNode.Attribute("valueType");
  491. if (string.IsNullOrEmpty(param.valType))
  492. param.valType = paramNode.Attribute("valType");
  493. _eventParams.Add(param);
  494. }
  495. }
  496. protected string GetSParam(string paramName)
  497. {
  498. if (_eventParams == null) return null;
  499. for(int idx =0; idx < _eventParams.Count;idx++)
  500. {
  501. if (_eventParams[idx].name == paramName) return _eventParams[idx].val;
  502. }
  503. return null;
  504. }
  505. protected int GetNParam(string paramName)
  506. {
  507. string strVal = GetSParam(paramName);
  508. if (string.IsNullOrEmpty(strVal)) return 0;
  509. int iVal = 0;
  510. int.TryParse(strVal, out iVal);
  511. return iVal;
  512. }
  513. protected float GetFParam(string paramName)
  514. {
  515. string strVal = GetSParam(paramName);
  516. if (string.IsNullOrEmpty(strVal)) return 0;
  517. float fVal = 0;
  518. float.TryParse(strVal, out fVal);
  519. return fVal;
  520. }
  521. protected Vector3 GetVParam(string paramName)
  522. {
  523. string strVal = GetSParam(paramName);
  524. if (string.IsNullOrEmpty(strVal)) return Vector3.zero;
  525. Vector3 vec = StringUtil.convertVector3(strVal);
  526. return vec;
  527. }
  528. /// @brief Does the Event collides the \e e?
  529. public bool Collides( FEvent e )
  530. {
  531. return _frameRange.Collides( e.FrameRange );
  532. }
  533. /// @brief Returns the biggest frame range this event can have
  534. public FrameRange GetMaxFrameRange()
  535. {
  536. FrameRange range = new FrameRange(0, 0);
  537. int id = GetId();
  538. if( id == 0 )
  539. {
  540. range.Start = 0;
  541. }
  542. else
  543. {
  544. range.Start = _track.Events[id-1].End;
  545. }
  546. if( id == _track.Events.Count-1 ) // last one?
  547. {
  548. range.End = _track.Timeline.Sequence.Length;
  549. }
  550. else
  551. {
  552. range.End = _track.Events[id+1].Start;
  553. }
  554. return range;
  555. }
  556. /// @brief Compares events based on their start frame, basically used to order them.
  557. /// @param e1 Event
  558. /// @param e2 Event
  559. public static int Compare( FEvent e1, FEvent e2 )
  560. {
  561. return e1.Start.CompareTo( e2.Start );
  562. }
  563. }
  564. /**
  565. * @brief Attribute that adds an Event to the add event menu.
  566. */
  567. public class FEventAttribute : System.Attribute
  568. {
  569. // menu path
  570. public string menu;
  571. // type of track to be used
  572. public Type trackType;
  573. // public object _color = null;
  574. public FEventAttribute( string menu )
  575. :this( menu, typeof(FTrack) )
  576. {
  577. }
  578. public FEventAttribute( string menu, Type trackType )
  579. {
  580. this.menu = menu;
  581. this.trackType = trackType;
  582. }
  583. // public FEventAttribute( string menu, Color color )
  584. // :this( menu )
  585. // {
  586. // _color = color;
  587. // }
  588. }
  589. }