| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- using UnityEngine;
- using System;
- using System.Collections.Generic;
- using System.Security;
- namespace Flux
- {
- [Serializable]
- /**
- * @brief Range of frames.
- * @note Start is _not_ guaranteed to be smaller or equal to End, it is up to the user to make sure.
- */
- public struct FrameRange
- {
- // start frame
- [SerializeField]
- private int _start;
- // end frame
- [SerializeField]
- private int _end;
- /// @brief Returns the start frame.
- public int Start
- {
- get { return _start; }
- set
- {
- _start = value;
- }
- }
- /// @brief Returns the end frame.
- public int End
- {
- get { return _end; }
- set
- {
- _end = value;
- }
- }
- /// @brief Sets / Gets the length.
- /// @note It doesn't cache the value.
- public int Length { set{ End = _start + value; } get{ return _end - _start; } }
- /**
- * @brief Create a frame range
- * @param start Start frame
- * @param end End frame
- * @note It is up to you to make sure start is smaller than end.
- */
- public FrameRange( int start, int end )
- {
- this._start = start;
- this._end = end;
- }
- /// @brief Returns \e i clamped to the range.
- public int Cull( int i )
- {
- return Mathf.Clamp( i, _start, _end );
- }
- /// @brief Returns if \e i is inside [start, end], i.e. including borders
- public bool Contains( int i )
- {
- return i >= _start && i <= _end;
- }
- /// @brief Returns if \e i is inside ]start, end[, i.e. excluding borders
- public bool ContainsExclusive( int i )
- {
- return i > _start && i < _end;
- }
- /// @brief Returns if the ranges intersect, i.e. touching returns false
- /// @note Assumes They are both valid
- public bool Collides( FrameRange range )
- {
- return _start < range._end && _end > range._start;
- // return (range.start > start && range.start < end) || (range.end > start && range.end < end );
- }
- /// @brief Returns if the ranges overlap, i.e. touching return true
- /// @note Assumes They are both valid
- public bool Overlaps( FrameRange range )
- {
- return range.End >= _start && range.Start <= _end;
- }
- /// @brief Returns what kind of overlap it has with \e range.
- /// @note Assumes They are both valid
- public FrameRangeOverlap GetOverlap( FrameRange range )
- {
- if( range._start >= _start )
- {
- // contains, left or none
- if( range._end <= _end )
- {
- return FrameRangeOverlap.ContainsFull;
- }
- else
- {
- if( range._start > _end )
- {
- return FrameRangeOverlap.MissOnRight;
- }
- return FrameRangeOverlap.ContainsStart;
- }
- }
- else
- {
- // contained, right or none
- if( range._end < _start )
- {
- return FrameRangeOverlap.MissOnLeft;
- }
- else
- {
- if( range._end > _end )
- {
- return FrameRangeOverlap.IsContained;
- }
- return FrameRangeOverlap.ContainsEnd;
- }
- }
- }
- public static bool operator ==( FrameRange a, FrameRange b )
- {
- return a._start == b._start && a._end == b._end;
- }
- public static bool operator !=( FrameRange a, FrameRange b )
- {
- return !(a == b);
- }
- public override bool Equals( object obj )
- {
- if( obj.GetType() != GetType() )
- return false;
- return (FrameRange)obj == this;
- }
- public override int GetHashCode()
- {
- return _start + _end;
- }
- public override string ToString()
- {
- return string.Format("[{0}; {1}]", _start, _end);
- }
- }
- /// @brief Types of range overlap
- public enum FrameRangeOverlap
- {
- MissOnLeft = -2, /// @brief missed and is to the left of the range passed
- MissOnRight, /// @brief missed and is to the right of the range passed
- IsContained, /// @brief overlaps and is contained by the range passed
- ContainsFull, /// @brief overlaps and contains the range passed
- ContainsStart, /// @brief overlaps and contains the start of the range passed
- ContainsEnd /// @brief overlaps and contains the end of the range passed
- }
- public class FEventParam
- {
- public string name;
- public string val;
- public string valType;
- }
- /**
- * @brief Base class for Events
- * @sa FSequence, FTimeline, FTrack.
- */
- public class FEvent : FObject
- {
- public override Transform Owner { get { return _track.Owner; } }
- public override FSequence Sequence { get { return _track.Sequence; } }
- // track that owns this event
- [SerializeField]
- [HideInInspector]
- protected FTrack _track = null;
- /// @brief Returns the track it belongs to
- public FTrack Track { get { return _track; } }
- [SerializeField]
- [HideInInspector]
- private bool _triggerOnSkip = true;
- /// @brief Should this event trigger if you skip it?
- public bool TriggerOnSkip { get { return _triggerOnSkip; } set { _triggerOnSkip = value; } }
- [SerializeField]
- [HideInInspector]
- private FrameRange _frameRange;
- /// @brief Range of the event.
- public FrameRange FrameRange { get { return _frameRange; }
- set {
- FrameRange oldFrameRange = _frameRange;
- _frameRange = value; OnFrameRangeChanged( oldFrameRange );
- }
- }
- // has this event called Trigger already?
- private bool _hasTriggered = false;
- /// @brief Has Trigger been called already?
- public bool HasTriggered { get { return _hasTriggered; } }
- // has this event called Finish already?
- private bool _hasFinished = false;
- /// @brief Has Finish been called already?
- public bool HasFinished { get { return _hasFinished; } }
- public virtual string Text { get { return null; } set { } }
- protected Transform _casterTrans;
- protected Transform _targetTrans;
- protected Transform _cameraTrans;
- protected SkillActionFrameEventType _eventType = SkillActionFrameEventType.FE_NONE;
- public SkillActionFrameEventType EventType
- {
- get { return _eventType; }
- }
- protected List<FEventParam> _eventParams;
- /**
- * @brief Create an event. Should be used to create events since it also
- * calls SetDefaultValues.
- * @param range Range of the event.
- */
- public static T Create<T>( FrameRange range ) where T : FEvent
- {
- GameObject go = new GameObject( typeof(T).ToString() );
- T evt = go.AddComponent<T>();
- evt._frameRange = new FrameRange( range.Start, range.End );
- return evt;
- }
- /// @overload
- public static FEvent Create( Type evtType, FrameRange range )
- {
- GameObject go = new GameObject( evtType.ToString() );
-
- FEvent evt = (FEvent)go.AddComponent(evtType);
-
- evt._frameRange = new FrameRange( range.Start, range.End );
-
- return evt;
- }
- // sets the track this event belongs to, to be called only by FTrack
- internal void SetTrack( FTrack track )
- {
- _track = track;
- if( _track )
- {
- transform.parent = _track.transform;
- }
- else
- {
- transform.parent = null;
- }
- }
- /// @brief Use this function to setup default values for when events get created
- public void SetDefaultValues()
- {
- OnSetDefaultValues();
- }
- /// @brief Use this function if you want to do something to the event when the frame range
- /// changed, e.g. adjust some variables to the new event size.
- /// @param oldFrameRange Previous FrameRange, the current one is set on the event.
- protected virtual void OnFrameRangeChanged( FrameRange oldFrameRange )
- {
- }
- /**
- * @brief Called when the event gets reached.
- * The reason we pass the time is because they may have been frames skipped
- * or simply we may have jumped into the middle of an event, and that allows you
- * to skip to the right point. E.g. useful when you want to play an animation,
- * if you jumped to the middle of it you want to tell mecanim to start in the middle,
- * not at the start.
- * @param frameSinceTrigger Frames that passed since the actual TriggerFrame
- * @param timeSinceTrigger Time passed since the actual TriggerFrame
- * @sa TriggerFrame, TriggerTime, Finish
- */
- public void Trigger( float timeSinceTrigger )
- {
- _hasTriggered = true;
- OnTrigger( timeSinceTrigger );
- }
- /// @brief At which frame will the event trigger, basically the start of it's range.
- public int TriggerFrame { get { return _frameRange.Start; } }
- /// @brief At which time the event triggers.
- /// @note Value isn't cached.
- public float TriggerTime { get { return _frameRange.Start * Sequence.InverseFrameRate; } }
- /**
- * @brief Used to setup your own code when Trigger is called.
- * @param framesSinceTrigger Frames passed since TriggerFrame
- * @param timeSinceTrigger Time passed since timeSinceTrigger
- */
- protected virtual void OnTrigger( float timeSinceTrigger ){ }
- /**
- * @brief Called when the event ends, i.e. we pass the end of it's range.
- * @sa Trigger
- */
- public void Finish()
- {
- _hasFinished = true;
- #if UNITY_EDITOR
- PreEvent();
- #endif
- if( Sequence.IsPlayingForward )
- OnFinish(); // only do this code if we're moving forward, otherwise it doesn't really matter
- #if UNITY_EDITOR
- PostEvent();
- #endif
- }
- /// @brief Used to setup your own code when Finish is called.
- protected virtual void OnFinish(){ }
- public sealed override void Init()
- {
- _hasTriggered = false;
- _hasFinished = false;
- // init doesn't get wrapped between Pre/PostEvent because
- // it is here that vars will be initialized
- OnInit();
- }
- protected virtual void OnSetDefaultValues()
- {
- if (Sequence.CasterActor != null)
- {
- _casterTrans = Sequence.CasterActor.transform;
- }
- if (Sequence.TargetActor != null)
- {
- _targetTrans = Sequence.TargetActor.transform;
- }
- if (Sequence.CameraGo != null)
- {
- _cameraTrans = Sequence.CameraGo.transform;
- }
- }
- /// @brief Used to setup your own code for when the sequence is initialized
- protected virtual void OnInit()
- {
-
- }
- public void Pause()
- {
- #if UNITY_EDITOR
- PreEvent();
- #endif
- OnPause();
- #if UNITY_EDITOR
- PostEvent();
- #endif
- }
- /// @brief Used to setup your own code for when the sequence is paused
- protected virtual void OnPause() { }
- public void Resume()
- {
- #if UNITY_EDITOR
- PreEvent();
- #endif
-
- OnResume();
- #if UNITY_EDITOR
- PostEvent();
- #endif
- }
- /// @brief Used to setup your own code for when the sequence is resumed
- protected virtual void OnResume() { }
- public sealed override void Stop()
- {
- _hasTriggered = false;
- _hasFinished = false;
- #if UNITY_EDITOR
- PreEvent();
- #endif
- OnStop();
- #if UNITY_EDITOR
- PostEvent();
- #endif
- }
- /// @brief Used to setup your own code for when the sequence is stopped
- protected virtual void OnStop(){}
-
- /**
- * @brief Called each time the sequence gets updated, if the current frame is in this event's range.
- * @param framesSinceTrigger How many frames have passed since TriggerFrame
- * @param timeSinceTrigger How much time passed since TriggerFrame
- */
- public void UpdateEvent( int framesSinceTrigger, float timeSinceTrigger )
- {
- #if UNITY_EDITOR
- PreEvent();
- #endif
- if( !_hasTriggered )
- {
- Trigger( timeSinceTrigger );
- }
- OnUpdateEvent( timeSinceTrigger );
- if( framesSinceTrigger == Length )
- {
- Finish();
- }
- #if UNITY_EDITOR
- PostEvent();
- #endif
- }
- /**
- * @brief Used to setup your code that gets called when the event updates.
- * @param framesSinceTrigger How many frames passed since TriggerFrame
- * @param timeSinceTrigger How much time passed since TriggerFrame
- */
- protected virtual void OnUpdateEvent( float timeSinceTrigger )
- {
- }
-
- /**
- * @brief Used to mark objects used as not to be saved, in order to not make the scene dirty when
- * scrubbing the editor.
- * @note This is called before every call to FEvent, i.e. Trigger, UpdateEvent, Stop, etc.
- */
- protected virtual void PreEvent()
- {
- #if UNITY_EDITOR
- if( !Application.isPlaying )
- Owner.gameObject.hideFlags = HideFlags.DontSave;
- #endif
- }
- /**
- * @brief Used to mark objects used as to be saved again.
- * @note This is called after every call to FEvent, i.e. Trigger, UpdateEvent, Stop, etc.
- */
- protected virtual void PostEvent()
- {
- #if UNITY_EDITOR
- if( !Application.isPlaying )
- Owner.gameObject.hideFlags = HideFlags.None;
- #endif
- }
- /// @brief Returns \e true if it is the first event of the track it belongs to.
- public bool IsFirstEvent { get { return GetId() == 0; } }
- /// @brief Returns \e true if it is the last event of the track it belongs to.
- public bool IsLastEvent { get { return GetId() == _track.Events.Count-1; } }
- /// @brief Shortcut to FrameRange.Start
- public int Start
- {
- get{ return _frameRange.Start; }
- set{ _frameRange.Start = value; }
- }
- /// @brief Shortcut to FrameRange.End
- public int End
- {
- get { return _frameRange.End; }
- set{ _frameRange.End = value; }
- }
- /// @brief Shortcut to FrameRange.Length
- public int Length
- {
- get{ return _frameRange.Length; }
- set{ _frameRange.Length = value; }
- }
- /// @brief What this the event starts.
- /// @note This value isn't cached.
- public float StartTime
- {
- get { return _frameRange.Start * Sequence.InverseFrameRate; }
- }
- /// @brief What this the event ends.
- /// @note This value isn't cached.
- public float EndTime
- {
- get { return _frameRange.End * Sequence.InverseFrameRate; }
- }
- /// @brief Length of the event in seconds.
- /// @note This value isn't cached.
- public float LengthTime
- {
- get { return _frameRange.Length * Sequence.InverseFrameRate; }
- }
- /// @brief What's the minimum length this event can have?
- /// @warning Events cannot be smaller than 1 frame.
- public virtual int GetMinLength()
- {
- return 1;
- }
- /// @brief What's the maximum length this event can have?
- public virtual int GetMaxLength()
- {
- return int.MaxValue;
- }
- public virtual SecurityElement SaveToXml()
- {
- int eventType = (int)EventType;
- SecurityElement node = new SecurityElement("event");
- node.AddAttribute("startFrame", this.FrameRange.Start.ToString());
- node.AddAttribute("endFrame", this.FrameRange.End.ToString());
- node.AddAttribute("type", eventType.ToString());
- return node;
- }
- public SecurityElement WriteParamNode(string paramName, string paramVal, string paramValueType)
- {
- if (string.IsNullOrEmpty(paramName) || string.IsNullOrEmpty(paramVal) || string.IsNullOrEmpty(paramValueType)) return null;
- SecurityElement paramNode = new SecurityElement("param");
- paramNode.AddAttribute("name", paramName);
- paramNode.AddAttribute("value", paramVal);
- paramNode.AddAttribute("valueType", paramValueType);
- return paramNode;
- }
- public virtual void LoadFromXml(SecurityElement eventNode)
- {
- if (eventNode == null || eventNode.Children == null) return;
- _eventParams = new List<FEventParam>();
- for (int idx = 0; idx < eventNode.Children.Count; idx++)
- {
- var paramNode = eventNode.Children[idx] as SecurityElement;
- FEventParam param = new FEventParam();
- param.name = paramNode.Attribute("name");
- param.val = paramNode.Attribute("value");
- param.valType = paramNode.Attribute("valueType");
- if (string.IsNullOrEmpty(param.valType))
- param.valType = paramNode.Attribute("valType");
- _eventParams.Add(param);
- }
- }
- protected string GetSParam(string paramName)
- {
- if (_eventParams == null) return null;
- for(int idx =0; idx < _eventParams.Count;idx++)
- {
- if (_eventParams[idx].name == paramName) return _eventParams[idx].val;
- }
- return null;
- }
- protected int GetNParam(string paramName)
- {
- string strVal = GetSParam(paramName);
- if (string.IsNullOrEmpty(strVal)) return 0;
- int iVal = 0;
- int.TryParse(strVal, out iVal);
- return iVal;
- }
- protected float GetFParam(string paramName)
- {
- string strVal = GetSParam(paramName);
- if (string.IsNullOrEmpty(strVal)) return 0;
- float fVal = 0;
- float.TryParse(strVal, out fVal);
- return fVal;
- }
- protected Vector3 GetVParam(string paramName)
- {
- string strVal = GetSParam(paramName);
- if (string.IsNullOrEmpty(strVal)) return Vector3.zero;
- Vector3 vec = StringUtil.convertVector3(strVal);
- return vec;
- }
- /// @brief Does the Event collides the \e e?
- public bool Collides( FEvent e )
- {
- return _frameRange.Collides( e.FrameRange );
- }
- /// @brief Returns the biggest frame range this event can have
- public FrameRange GetMaxFrameRange()
- {
- FrameRange range = new FrameRange(0, 0);
- int id = GetId();
- if( id == 0 )
- {
- range.Start = 0;
- }
- else
- {
- range.Start = _track.Events[id-1].End;
- }
- if( id == _track.Events.Count-1 ) // last one?
- {
- range.End = _track.Timeline.Sequence.Length;
- }
- else
- {
- range.End = _track.Events[id+1].Start;
- }
- return range;
- }
- /// @brief Compares events based on their start frame, basically used to order them.
- /// @param e1 Event
- /// @param e2 Event
- public static int Compare( FEvent e1, FEvent e2 )
- {
- return e1.Start.CompareTo( e2.Start );
- }
- }
- /**
- * @brief Attribute that adds an Event to the add event menu.
- */
- public class FEventAttribute : System.Attribute
- {
- // menu path
- public string menu;
- // type of track to be used
- public Type trackType;
- // public object _color = null;
- public FEventAttribute( string menu )
- :this( menu, typeof(FTrack) )
- {
- }
- public FEventAttribute( string menu, Type trackType )
- {
- this.menu = menu;
- this.trackType = trackType;
- }
- // public FEventAttribute( string menu, Color color )
- // :this( menu )
- // {
- // _color = color;
- // }
- }
- }
|