├── .gitignore ├── Audio ├── AudioController.cs ├── AudioType.cs └── TestAudio.cs ├── Data ├── DataController.cs └── TestData.cs ├── Menu ├── Page.cs ├── PageController.cs ├── PageType.cs └── TestMenu.cs ├── README.md ├── Scene ├── SceneController.cs ├── SceneType.cs └── TestScene.cs ├── Session └── SessionController.cs └── Tween ├── ColorTween.cs ├── FloatTween.cs ├── ImageColorTween.cs ├── ImageFillTween.cs ├── Keyframe.cs ├── PositionTween.cs ├── RotationTween.cs ├── ScaleTween.cs ├── SpriteColorTween.cs ├── TextColorTween.cs ├── Tweener.cs └── Vector3Tween.cs /.gitignore: -------------------------------------------------------------------------------- 1 | *.meta 2 | .idea 3 | -------------------------------------------------------------------------------- /Audio/AudioController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | 4 | namespace UnityCore { 5 | 6 | namespace Audio { 7 | 8 | public class AudioController : MonoBehaviour 9 | { 10 | public static AudioController instance; 11 | 12 | public bool debug; 13 | public AudioTrack[] tracks; 14 | 15 | private Hashtable m_AudioTable; // relationship of audio types (key) and tracks (value) 16 | private Hashtable m_JobTable; // relationship between audio types (key) and jobs (value) 17 | 18 | private enum AudioAction { 19 | START, 20 | STOP, 21 | RESTART 22 | } 23 | 24 | [System.Serializable] 25 | public class AudioObject { 26 | public AudioType type; 27 | public AudioClip clip; 28 | } 29 | 30 | [System.Serializable] 31 | public class AudioTrack 32 | { 33 | public AudioSource source; 34 | public AudioObject[] audio; 35 | } 36 | 37 | private class AudioJob { 38 | public AudioAction action; 39 | public AudioType type; 40 | public bool fade; 41 | public WaitForSeconds delay; 42 | 43 | public AudioJob(AudioAction _action, AudioType _type, bool _fade, float _delay) { 44 | action = _action; 45 | type = _type; 46 | fade = _fade; 47 | delay = _delay > 0f ? new WaitForSeconds(_delay) : null; 48 | } 49 | } 50 | 51 | #region Unity Functions 52 | private void Awake() { 53 | if (!instance) { 54 | Configure(); 55 | } 56 | } 57 | 58 | private void OnDisable() { 59 | Dispose(); 60 | } 61 | #endregion 62 | 63 | #region Public Functions 64 | public void PlayAudio(AudioType _type, bool _fade=false, float _delay=0.0F) { 65 | AddJob(new AudioJob(AudioAction.START, _type, _fade, _delay)); 66 | } 67 | 68 | public void StopAudio(AudioType _type, bool _fade=false, float _delay=0.0F) { 69 | AddJob(new AudioJob(AudioAction.STOP, _type, _fade, _delay)); 70 | } 71 | 72 | public void RestartAudio(AudioType _type, bool _fade=false, float _delay=0.0F) { 73 | AddJob(new AudioJob(AudioAction.RESTART, _type, _fade, _delay)); 74 | } 75 | #endregion 76 | 77 | #region Private Functions 78 | private void Configure() { 79 | instance = this; 80 | m_AudioTable = new Hashtable(); 81 | m_JobTable = new Hashtable(); 82 | GenerateAudioTable(); 83 | } 84 | 85 | private void Dispose() { 86 | // cancel all jobs in progress 87 | foreach(DictionaryEntry _kvp in m_JobTable) { 88 | Coroutine _job = (Coroutine)_kvp.Value; 89 | StopCoroutine(_job); 90 | } 91 | } 92 | 93 | private void AddJob(AudioJob _job) { 94 | // cancel any job that might be using this job's audio source 95 | RemoveConflictingJobs(_job.type); 96 | 97 | Coroutine _jobRunner = StartCoroutine(RunAudioJob(_job)); 98 | m_JobTable.Add(_job.type, _jobRunner); 99 | Log("Starting job on ["+_job.type+"] with operation: "+_job.action); 100 | } 101 | 102 | private void RemoveJob(AudioType _type) { 103 | if (!m_JobTable.ContainsKey(_type)) { 104 | Log("Trying to stop a job ["+_type+"] that is not running."); 105 | return; 106 | } 107 | Coroutine _runningJob = (Coroutine)m_JobTable[_type]; 108 | StopCoroutine(_runningJob); 109 | m_JobTable.Remove(_type); 110 | } 111 | 112 | private void RemoveConflictingJobs(AudioType _type) { 113 | // cancel the job if one exists with the same type 114 | if (m_JobTable.ContainsKey(_type)) { 115 | RemoveJob(_type); 116 | } 117 | 118 | // cancel jobs that share the same audio track 119 | AudioType _conflictAudio = AudioType.None; 120 | AudioTrack _audioTrackNeeded = GetAudioTrack(_type, "Get Audio Track Needed"); 121 | foreach (DictionaryEntry _entry in m_JobTable) { 122 | AudioType _audioType = (AudioType)_entry.Key; 123 | AudioTrack _audioTrackInUse = GetAudioTrack(_audioType, "Get Audio Track In Use"); 124 | if (_audioTrackInUse.source == _audioTrackNeeded.source) { 125 | _conflictAudio = _audioType; 126 | break; 127 | } 128 | } 129 | if (_conflictAudio != AudioType.None) { 130 | RemoveJob(_conflictAudio); 131 | } 132 | } 133 | 134 | private IEnumerator RunAudioJob(AudioJob _job) { 135 | if (_job.delay != null) yield return _job.delay; 136 | 137 | AudioTrack _track = GetAudioTrack(_job.type); // track existence should be verified by now 138 | _track.source.clip = GetAudioClipFromAudioTrack(_job.type, _track); 139 | 140 | float _initial = 0f; 141 | float _target = 1f; 142 | switch (_job.action) { 143 | case AudioAction.START: 144 | _track.source.Play(); 145 | break; 146 | case AudioAction.STOP when !_job.fade: 147 | _track.source.Stop(); 148 | break; 149 | case AudioAction.STOP: 150 | _initial = 1f; 151 | _target = 0f; 152 | break; 153 | case AudioAction.RESTART: 154 | _track.source.Stop(); 155 | _track.source.Play(); 156 | break; 157 | } 158 | 159 | // fade volume 160 | if (_job.fade) { 161 | float _duration = 1.0f; 162 | float _timer = 0.0f; 163 | 164 | while (_timer <= _duration) { 165 | _track.source.volume = Mathf.Lerp(_initial, _target, _timer / _duration); 166 | _timer += Time.deltaTime; 167 | yield return null; 168 | } 169 | 170 | // if _timer was 0.9999 and Time.deltaTime was 0.01 we would not have reached the target 171 | // make sure the volume is set to the value we want 172 | _track.source.volume = _target; 173 | 174 | if (_job.action == AudioAction.STOP) { 175 | _track.source.Stop(); 176 | } 177 | } 178 | 179 | m_JobTable.Remove(_job.type); 180 | Log("Job count: "+m_JobTable.Count); 181 | } 182 | 183 | private void GenerateAudioTable() { 184 | foreach(AudioTrack _track in tracks) { 185 | foreach(AudioObject _obj in _track.audio) { 186 | // do not duplicate keys 187 | if (m_AudioTable.ContainsKey(_obj.type)) { 188 | LogWarning("You are trying to register audio ["+_obj.type+"] that has already been registered."); 189 | } else { 190 | m_AudioTable.Add(_obj.type, _track); 191 | Log("Registering audio ["+_obj.type+"]"); 192 | } 193 | } 194 | } 195 | } 196 | 197 | private AudioTrack GetAudioTrack(AudioType _type, string _job="") { 198 | if (!m_AudioTable.ContainsKey(_type)) { 199 | LogWarning("You are trying to "+_job+" for ["+_type+"] but no track was found supporting this audio type."); 200 | return null; 201 | } 202 | return (AudioTrack)m_AudioTable[_type]; 203 | } 204 | 205 | private AudioClip GetAudioClipFromAudioTrack(AudioType _type, AudioTrack _track) { 206 | foreach (AudioObject _obj in _track.audio) { 207 | if (_obj.type == _type) { 208 | return _obj.clip; 209 | } 210 | } 211 | return null; 212 | } 213 | 214 | private void Log(string _msg) { 215 | if (!debug) return; 216 | Debug.Log("[Audio Controller]: "+_msg); 217 | } 218 | 219 | private void LogWarning(string _msg) { 220 | if (!debug) return; 221 | Debug.LogWarning("[Audio Controller]: "+_msg); 222 | } 223 | #endregion 224 | } 225 | } 226 | } -------------------------------------------------------------------------------- /Audio/AudioType.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace UnityCore { 3 | 4 | namespace Audio { 5 | 6 | public enum AudioType { 7 | None, 8 | SFX_01, 9 | ST_01 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Audio/TestAudio.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace UnityCore { 5 | 6 | namespace Audio { 7 | 8 | public class TestAudio : MonoBehaviour 9 | { 10 | 11 | public AudioController audioController; 12 | 13 | #region Unity Functions 14 | #if UNITY_EDITOR 15 | private void Update() { 16 | if (Input.GetKeyUp(KeyCode.T)) { 17 | audioController.PlayAudio(AudioType.ST_01, true); 18 | } 19 | if (Input.GetKeyUp(KeyCode.G)) { 20 | audioController.StopAudio(AudioType.ST_01, true); 21 | } 22 | if (Input.GetKeyUp(KeyCode.B)) { 23 | audioController.RestartAudio(AudioType.ST_01, true); 24 | } 25 | if (Input.GetKeyUp(KeyCode.Y)) { 26 | audioController.PlayAudio(AudioType.SFX_01, true); 27 | } 28 | if (Input.GetKeyUp(KeyCode.H)) { 29 | audioController.StopAudio(AudioType.SFX_01, true); 30 | } 31 | if (Input.GetKeyUp(KeyCode.N)) { 32 | audioController.RestartAudio(AudioType.SFX_01, true); 33 | } 34 | } 35 | #endif 36 | #endregion 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Data/DataController.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace UnityCore { 5 | 6 | namespace Data { 7 | 8 | public class DataController : MonoBehaviour 9 | { 10 | private static readonly string DATA_SCORE = "score"; 11 | private static readonly string DATA_HIGHSCORE = "highscore"; 12 | private static readonly int DEFAULT_INT = 0; 13 | 14 | public static DataController instance; 15 | 16 | public bool debug; 17 | 18 | #region Properties 19 | public int Highscore { 20 | get { 21 | return GetInt(DATA_HIGHSCORE); 22 | } 23 | private set { 24 | SaveInt(DATA_HIGHSCORE, value); 25 | } 26 | } 27 | 28 | public int Score { 29 | get { 30 | return GetInt(DATA_SCORE); 31 | } 32 | set { 33 | // soft clamp value at 0 34 | if (value < 0) { 35 | value = 0; 36 | } 37 | 38 | SaveInt(DATA_SCORE, value); 39 | int _score = this.Score; 40 | if (_score > this.Highscore) { 41 | this.Highscore = _score; 42 | } 43 | } 44 | } 45 | #endregion 46 | 47 | #region Unity Functions 48 | private void Awake() { 49 | if (!instance) { 50 | instance = this; 51 | } 52 | } 53 | #endregion 54 | 55 | #region Private Functions 56 | private void SaveInt(string _data, int _value) { 57 | PlayerPrefs.SetInt(_data, _value); 58 | } 59 | 60 | private int GetInt(string _data) { 61 | return PlayerPrefs.GetInt(_data, DEFAULT_INT); 62 | } 63 | #endregion 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /Data/TestData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace UnityCore { 6 | 7 | namespace Data { 8 | 9 | public class TestData : MonoBehaviour 10 | { 11 | public DataController data; 12 | 13 | #region Unity Functions 14 | #if UNITY_EDITOR 15 | private void Update() { 16 | if (Input.GetKeyUp(KeyCode.R)) { 17 | TestAddScore(1); 18 | Debug.Log("[Test] Score = "+data.Score+" | Highscore = "+data.Highscore); 19 | } 20 | 21 | if (Input.GetKeyUp(KeyCode.T)) { 22 | TestAddScore(-1); 23 | Debug.Log("[Test] Score = "+data.Score+" | Highscore = "+data.Highscore); 24 | } 25 | 26 | if (Input.GetKeyUp(KeyCode.Space)) { 27 | TestResetScore(); 28 | Debug.Log("[Test] Score = "+data.Score+" | Highscore = "+data.Highscore); 29 | } 30 | } 31 | #endif 32 | #endregion 33 | 34 | private void TestAddScore(int _delta) { 35 | data.Score += _delta; 36 | } 37 | 38 | private void TestResetScore() { 39 | data.Score = 0; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Menu/Page.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | 4 | namespace UnityCore { 5 | 6 | namespace Menu { 7 | 8 | public class Page : MonoBehaviour 9 | { 10 | public static readonly string FLAG_ON = "On"; 11 | public static readonly string FLAG_OFF = "Off"; 12 | public static readonly string FLAG_NONE = "None"; 13 | 14 | public PageType type; 15 | public bool useAnimation; 16 | public string targetState {get;private set;} 17 | 18 | /* 19 | * Animaton Requirements... 20 | * - This class uses certain controls to determine page state 21 | * - Pages have three core states: 22 | * 1. Resting 23 | * 2. Turning On 24 | * 3. Turning Off 25 | * - The animator must have a control boolean called 'on'. Otherwise the animator will not work. 26 | */ 27 | private Animator m_Animator; 28 | private bool m_IsOn; 29 | 30 | public bool isOn { 31 | get { 32 | return m_IsOn; 33 | } 34 | private set { 35 | m_IsOn = value; 36 | } 37 | } 38 | 39 | #region Unity Functions 40 | private void OnEnable() { 41 | CheckAnimatorIntegrity(); 42 | } 43 | #endregion 44 | 45 | #region Public Functions 46 | /// 47 | /// Call this to turn the page on or off by setting the control '_on' 48 | /// 49 | public void Animate(bool _on) { 50 | if (useAnimation) { 51 | m_Animator.SetBool("on", _on); 52 | 53 | StopCoroutine("AwaitAnimation"); 54 | StartCoroutine("AwaitAnimation", _on); 55 | } else { 56 | if (!_on) { 57 | isOn = false; 58 | gameObject.SetActive(false); 59 | } else { 60 | isOn = true; 61 | } 62 | } 63 | } 64 | #endregion 65 | 66 | #region Private Functions 67 | private IEnumerator AwaitAnimation(bool _on) { 68 | targetState = _on ? FLAG_ON : FLAG_OFF; 69 | 70 | while (!m_Animator.GetCurrentAnimatorStateInfo(0).IsName(targetState)) { 71 | yield return null; 72 | } 73 | while (m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1) { 74 | yield return null; 75 | } 76 | 77 | targetState = FLAG_NONE; 78 | 79 | Log("Page ["+type+"] finished transitioning to "+(_on ? "on." : "off.")); 80 | 81 | if (!_on) { 82 | isOn = false; 83 | gameObject.SetActive(false); 84 | } else { 85 | isOn = true; 86 | } 87 | } 88 | 89 | private void CheckAnimatorIntegrity() { 90 | if (useAnimation) { 91 | // try to get animator 92 | m_Animator = GetComponent(); 93 | if (!m_Animator) { 94 | LogWarning("You opted to animate page ["+type+"], but no Animator component exists on the object."); 95 | } 96 | } 97 | } 98 | 99 | private void Log(string _msg) { 100 | Debug.Log("[Page]: "+_msg); 101 | } 102 | 103 | private void LogWarning(string _msg) { 104 | Debug.LogWarning("[Page]: "+_msg); 105 | } 106 | #endregion 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /Menu/PageController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections; 3 | using UnityEngine; 4 | 5 | namespace UnityCore { 6 | 7 | namespace Menu { 8 | 9 | public class PageController : MonoBehaviour 10 | { 11 | public static PageController instance; 12 | 13 | public bool debug; 14 | public PageType entryPage; 15 | public Page[] pages; 16 | 17 | private Hashtable m_Pages; 18 | private List m_OnList; 19 | private List m_OffList; 20 | 21 | #region Unity Functions 22 | private void Awake() { 23 | if (!instance) { 24 | instance = this; 25 | m_Pages = new Hashtable(); 26 | m_OnList = new List(); 27 | m_OffList = new List(); 28 | RegisterAllPages(); 29 | 30 | if (entryPage != PageType.None) { 31 | TurnPageOn(entryPage); 32 | } 33 | 34 | DontDestroyOnLoad(gameObject); 35 | } else { 36 | Destroy(gameObject); 37 | } 38 | } 39 | #endregion 40 | 41 | #region Public Functions 42 | /// 43 | /// Turn on page with type '_type' 44 | /// 45 | public void TurnPageOn(PageType _type) { 46 | if (_type == PageType.None) return; 47 | if (!PageExists(_type)) { 48 | LogWarning("You are trying to turn a page on ["+_type+"] that has not been registered."); 49 | return; 50 | } 51 | 52 | Page _page = GetPage(_type); 53 | _page.gameObject.SetActive(true); 54 | _page.Animate(true); 55 | } 56 | 57 | /// 58 | /// Turn off page with type '_off' 59 | /// Optionally turn page with type '_on' on 60 | /// Optionally wait for page to exit before turning on optional page 61 | /// 62 | public void TurnPageOff(PageType _off, PageType _on=PageType.None, bool _waitForExit=false) { 63 | if (_off == PageType.None) return; 64 | if (!PageExists(_off)) { 65 | LogWarning("You are trying to turn a page off ["+_on+"] that has not been registered."); 66 | return; 67 | } 68 | 69 | Page _offPage = GetPage(_off); 70 | if (_offPage.gameObject.activeSelf) { 71 | _offPage.Animate(false); 72 | } 73 | 74 | if (_waitForExit && _offPage.useAnimation) { 75 | Page _onPage = GetPage(_on); 76 | StopCoroutine("WaitForPageExit"); 77 | StartCoroutine(WaitForPageExit(_onPage, _offPage)); 78 | } else { 79 | TurnPageOn(_on); 80 | } 81 | } 82 | 83 | public bool PageIsOn(PageType _type) { 84 | if (!PageExists(_type)) { 85 | LogWarning("You are trying to detect if a page is on ["+_type+"], but it has not been registered."); 86 | return false; 87 | } 88 | 89 | return GetPage(_type).isOn; 90 | } 91 | #endregion 92 | 93 | #region Private Functions 94 | private IEnumerator WaitForPageExit(Page _on, Page _off) { 95 | while (_off.targetState != Page.FLAG_NONE) { 96 | yield return null; 97 | } 98 | 99 | TurnPageOn(_on.type); 100 | } 101 | 102 | private void RegisterAllPages() { 103 | foreach(Page _page in pages) { 104 | RegisterPage(_page); 105 | } 106 | } 107 | 108 | private void RegisterPage(Page _page) { 109 | if (PageExists(_page.type)) { 110 | LogWarning("You are trying to register a page ["+_page.type+"] that has already been registered: "+_page.gameObject.name+"."); 111 | return; 112 | } 113 | 114 | m_Pages.Add(_page.type, _page); 115 | Log("Registered new page ["+_page.type+"]."); 116 | } 117 | 118 | private Page GetPage(PageType _type) { 119 | if (!PageExists(_type)) { 120 | LogWarning("You are trying to get a page ["+_type+"] that has not been registered."); 121 | return null; 122 | } 123 | 124 | return (Page)m_Pages[_type]; 125 | } 126 | 127 | private bool PageExists(PageType _type) { 128 | return m_Pages.ContainsKey(_type); 129 | } 130 | 131 | private void Log(string _msg) { 132 | if (!debug) return; 133 | Debug.Log("[Page Controller]: "+_msg); 134 | } 135 | 136 | private void LogWarning(string _msg) { 137 | if (!debug) return; 138 | Debug.LogWarning("[Page Controller]: "+_msg); 139 | } 140 | #endregion 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /Menu/PageType.cs: -------------------------------------------------------------------------------- 1 | namespace UnityCore { 2 | 3 | namespace Menu { 4 | 5 | public enum PageType { 6 | None, 7 | Loading, 8 | Menu 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Menu/TestMenu.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace UnityCore { 6 | 7 | namespace Menu { 8 | 9 | public class TestMenu : MonoBehaviour 10 | { 11 | public PageController pageController; 12 | 13 | #if UNITY_EDITOR 14 | private void Update() { 15 | if (Input.GetKeyUp(KeyCode.F)) { 16 | pageController.TurnPageOn(PageType.Loading); 17 | } 18 | if (Input.GetKeyUp(KeyCode.G)) { 19 | pageController.TurnPageOff(PageType.Loading); 20 | } 21 | if (Input.GetKeyUp(KeyCode.H)) { 22 | pageController.TurnPageOff(PageType.Loading, PageType.Menu); 23 | } 24 | if (Input.GetKeyUp(KeyCode.J)) { 25 | pageController.TurnPageOff(PageType.Loading, PageType.Menu, true); 26 | } 27 | } 28 | #endif 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Core 2 | 3 | Unity Core is a set of highly useful, generic tools built for the Unity 3D game engine. You can pull this source directly into your project's Assets/Scripts directory. 4 | 5 | There are 5 categories of tooling in this package: 6 | 7 | 1. Menu Management 8 | 2. Audio Management 9 | 3. Scene Management 10 | 4. Data Management 11 | 5. Session Management 12 | 6. Tween (Bonus Content) 13 | 14 | ### Menu Management 15 | 16 | Managing menus and other various UI elements is hugely important. At a high level, we want to create a system of switches for menu content, or various pages in our projects. To get more control, we may also want to create control structures for animation queueing. 17 | 18 | Watch the tutorial: https://youtu.be/qkKuGmGRF2k 19 | 20 | ### Data Management 21 | 22 | This implementation of data management is very basic. We simply take advantage of Unity's PlayerPrefs tool to abstract local data with simple class properties. 23 | 24 | Watch the tutorial: https://youtu.be/Vhuf1e0PVH0 25 | 26 | ### Audio Management 27 | 28 | Audio management can get complex, but our implementation here is highly streamlined. This audio package is capable of managing multiple audio tracks, each with their own set of audio type playables. 29 | 30 | Watch the tutorial: https://youtu.be/3hsBFxrIgQI 31 | 32 | ### Scene Management 33 | 34 | The scene tools in this package will let you easily switch scenes and subscribe to scene load events. The user can optionally choose to integrate the menu management system by passing a loading page PageType into the load method. 35 | 36 | Watch the tutorial: https://youtu.be/4oTluGCOgOM 37 | 38 | ### Session Management 39 | 40 | Sessions are definitely the more abstract system in the bunch. Without an application to manage, it is difficult to foresee what goes in the session controller. However, in this package you'll see a couple of examples of what you may want to store during the session. Here, we store sessionStartTime, fps, and manage the core game loop. 41 | 42 | Watch the tutorial: https://youtu.be/M6xy272-axM 43 | 44 | ### Tween (Bonus) 45 | 46 | This package is bonus content for this repo. There are some easy scripts to get started with the following tween styles: 47 | 48 | 1. PositionTween 49 | 2. RotationTween 50 | 3. ScaleTween 51 | 4. ImageFillTween 52 | 5. ImageColorTween 53 | -------------------------------------------------------------------------------- /Scene/SceneController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Threading.Tasks; 3 | using UnityEngine; 4 | using UnityEngine.SceneManagement; 5 | using UnityCore.Menu; 6 | 7 | namespace UnityCore { 8 | 9 | namespace Scene { 10 | 11 | public class SceneController : MonoBehaviour 12 | { 13 | public delegate void SceneLoadDelegate(SceneType _scene); 14 | 15 | public static SceneController instance; 16 | 17 | public bool debug; 18 | 19 | private PageController m_Menu; 20 | private SceneType m_TargetScene; 21 | private PageType m_LoadingPage; 22 | private SceneLoadDelegate m_SceneLoadDelegate; 23 | private bool m_SceneIsLoading; 24 | 25 | // get menu with integrity 26 | private PageController menu { 27 | get { 28 | if (m_Menu == null) { 29 | m_Menu = PageController.instance; 30 | } 31 | if (m_Menu == null) { 32 | LogWarning("You are trying to access the PageController, but no instance was found."); 33 | } 34 | return m_Menu; 35 | } 36 | } 37 | 38 | private string currentSceneName { 39 | get { 40 | return SceneManager.GetActiveScene().name; 41 | } 42 | } 43 | 44 | #region Unity Functions 45 | private void Awake() { 46 | if (!instance) { 47 | Configure(); 48 | DontDestroyOnLoad(gameObject); 49 | } else { 50 | Destroy(gameObject); 51 | } 52 | } 53 | 54 | private void OnDisable() { 55 | Dispose(); 56 | } 57 | #endregion 58 | 59 | #region Public Functions 60 | public void Load(SceneType _scene, SceneLoadDelegate _sceneLoadDelegate=null, bool _reload=false, PageType _loadingPage=PageType.None) { 61 | if (_loadingPage != PageType.None && !menu) { 62 | return; 63 | } 64 | 65 | if (!SceneCanBeLoaded(_scene, _reload)) { 66 | return; 67 | } 68 | 69 | m_SceneIsLoading = true; 70 | m_TargetScene = _scene; 71 | m_LoadingPage = _loadingPage; 72 | m_SceneLoadDelegate = _sceneLoadDelegate; 73 | StartCoroutine("LoadScene"); 74 | } 75 | #endregion 76 | 77 | #region Private Functions 78 | private void Configure() { 79 | instance = this; 80 | SceneManager.sceneLoaded += OnSceneLoaded; 81 | } 82 | 83 | private void Dispose() { 84 | SceneManager.sceneLoaded -= OnSceneLoaded; 85 | } 86 | 87 | private async void OnSceneLoaded(UnityEngine.SceneManagement.Scene _scene, LoadSceneMode _mode) { 88 | if (m_TargetScene == SceneType.None) { 89 | return; 90 | } 91 | 92 | SceneType _sceneType = StringToSceneType(_scene.name); 93 | if (m_TargetScene != _sceneType) { 94 | return; 95 | } 96 | 97 | if (m_SceneLoadDelegate != null) { 98 | try { 99 | m_SceneLoadDelegate(_sceneType); // it is possible the delegate is no longer accessible 100 | } catch (System.Exception) { 101 | LogWarning("Unable to respond with sceneLoadDelegate after scene ["+_sceneType+"] loaded."); 102 | } 103 | } 104 | 105 | if (m_LoadingPage != PageType.None) { 106 | await Task.Delay(1000); 107 | menu.TurnPageOff(m_LoadingPage); 108 | } 109 | 110 | m_SceneIsLoading = false; 111 | } 112 | 113 | private IEnumerator LoadScene() { 114 | if (m_LoadingPage != PageType.None) { 115 | menu.TurnPageOn(m_LoadingPage); 116 | while (!menu.PageIsOn(m_LoadingPage)) { 117 | yield return null; 118 | } 119 | } 120 | 121 | string _targetSceneName = m_TargetScene; 122 | // string _targetSceneName = SceneTypeToString(m_TargetScene); 123 | SceneManager.LoadScene(_targetSceneName); 124 | } 125 | 126 | private bool SceneCanBeLoaded(SceneType _scene, bool _reload) { 127 | string _targetSceneName = _scene; 128 | // string _targetSceneName = SceneTypeToString(_scene); 129 | if (currentSceneName == _targetSceneName && !_reload) { 130 | LogWarning("You are trying to load a scene ["+_scene+"] which is already active."); 131 | return false; 132 | } else if (_targetSceneName == string.Empty) { 133 | LogWarning("The scene you are trying to load ["+_scene+"] is not valid."); 134 | return false; 135 | } else if (m_SceneIsLoading) { 136 | LogWarning("Unable to load scene ["+_scene+"]. Another scene ["+m_TargetScene+"] is already loading."); 137 | return false; 138 | } 139 | 140 | return true; 141 | } 142 | 143 | // No longer needed if scene type enums are named like the scene files in Unity 144 | // private string SceneTypeToString(SceneType _scene) { 145 | // switch (_scene) { 146 | // case SceneType.Game: return "Game"; 147 | // case SceneType.Menu: return "Menu"; 148 | // default: 149 | // LogWarning("Scene ["+_scene+"] does not contain a string for a valid scene."); 150 | // return string.Empty; 151 | // } 152 | // } 153 | 154 | private SceneType StringToSceneType(string _scene) { 155 | // Dynamic enumeration so you wouldn't have to manually add case for each individual scene you create in game (just add the type in SceneType) 156 | foreach (string name in Enum.GetNames(typeof(SceneType))) { 157 | if (name == _scene) { 158 | return (SceneType) Enum.Parse(typeof(SceneType), name); 159 | } 160 | } 161 | return SceneType.None 162 | // switch (_scene) { 163 | // case "Game": return SceneType.Game; 164 | // case "Menu": return SceneType.Menu; 165 | // default: 166 | // LogWarning("Scene ["+_scene+"] does not contain a type for a valid scene."); 167 | // return SceneType.None; 168 | // } 169 | } 170 | 171 | private void Log(string _msg) { 172 | if (!debug) return; 173 | Debug.Log("[Scene Controller]: "+_msg); 174 | } 175 | 176 | private void LogWarning(string _msg) { 177 | if (!debug) return; 178 | Debug.LogWarning("[Scene Controller]: "+_msg); 179 | } 180 | #endregion 181 | } 182 | } 183 | } -------------------------------------------------------------------------------- /Scene/SceneType.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace UnityCore { 3 | 4 | namespace Scene { 5 | 6 | // Note: Name your SceneType enumerations just like the scene files in your Unity Scenes folder 7 | // i.e. MainMenuScene, Level01Scene, etc 8 | public enum SceneType { 9 | None, 10 | Menu, 11 | Game, 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Scene/TestScene.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | using UnityCore.Menu; 4 | 5 | namespace UnityCore { 6 | 7 | namespace Scene { 8 | 9 | public class TestScene : MonoBehaviour 10 | { 11 | 12 | public SceneController sceneController; 13 | 14 | #region Unity Functions 15 | #if UNITY_EDITOR 16 | private void Update() { 17 | if (Input.GetKeyUp(KeyCode.M)) { 18 | sceneController.Load(SceneType.Menu, (_scene) => {Debug.Log("Scene ["+_scene+"] loaded from test script!");}, false, PageType.Loading); 19 | } 20 | if (Input.GetKeyUp(KeyCode.G)) { 21 | sceneController.Load(SceneType.Game); 22 | } 23 | } 24 | #endif 25 | #endregion 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Session/SessionController.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | using UnityCore.Menu; 4 | 5 | namespace UnityCore { 6 | 7 | namespace Session { 8 | 9 | public class SessionController : MonoBehaviour 10 | { 11 | public static SessionController instance; 12 | 13 | private long m_SessionStartTime; 14 | private bool m_IsPaused; 15 | // private GameController m_Game; 16 | private float m_FPS; 17 | 18 | public long sessionStartTime { 19 | get { 20 | return m_SessionStartTime; 21 | } 22 | } 23 | 24 | public float fps { 25 | get { 26 | return m_FPS; 27 | } 28 | } 29 | 30 | #region Unity Functions 31 | private void Awake() { 32 | Configure(); 33 | } 34 | 35 | private void OnApplicationFocus(bool _focus) { 36 | if (_focus) { 37 | // Open a window to unpause the game 38 | // PageController.instance.TurnPageOn(PageType.PausePopup); 39 | } else { 40 | // Flag the game paused 41 | m_IsPaused = true; 42 | } 43 | } 44 | 45 | private void Update() { 46 | if (m_IsPaused) return; 47 | // m_Game.OnUpdate(); 48 | m_FPS = Time.frameCount / Time.time; 49 | } 50 | #endregion 51 | 52 | #region Public Functions 53 | // public void InitializeGame(GameController _game) { 54 | // m_Game = _game; 55 | // m_Game.OnInit(); 56 | // } 57 | 58 | public void UnPause() { 59 | m_IsPaused = false; 60 | } 61 | #endregion 62 | 63 | #region Private Functions 64 | /// 65 | /// Initialize the singleton pattern! 66 | /// 67 | private void Configure() { 68 | if (!instance) { 69 | instance = this; 70 | StartSession(); 71 | DontDestroyOnLoad(gameObject); 72 | } else { 73 | Destroy(gameObject); 74 | } 75 | } 76 | 77 | private void StartSession() { 78 | m_SessionStartTime = EpochSeconds(); 79 | } 80 | 81 | private long EpochSeconds() { 82 | var _epoch = new System.DateTimeOffset(System.DateTime.UtcNow); 83 | return _epoch.ToUnixTimeSeconds(); 84 | } 85 | #endregion 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Tween/ColorTween.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Tween { 6 | 7 | /// 8 | /// ColorTween is a MonoBehaviour wrapper class for Color tween objects 9 | /// It is responsible for responding to events from the tween process 10 | /// 11 | public abstract class ColorTween : MonoBehaviour 12 | { 13 | 14 | //public Keyframe[] keys; 15 | public ColorKeyframe[] keys; 16 | public float duration; 17 | public float delay; 18 | public bool wrap; 19 | public bool runOnEnable=true; 20 | 21 | protected Tweener m_Tween; 22 | 23 | #region Unity Functions 24 | private void OnEnable() { 25 | if (runOnEnable) 26 | StartTween(); 27 | } 28 | 29 | private void OnDisable() { 30 | StopTween(); 31 | } 32 | #endregion 33 | 34 | #region Private Functions 35 | private Keyframe[] GenericKeys(ColorKeyframe[] _keys) { 36 | var _ret = new List>(); 37 | foreach (ColorKeyframe _frame in _keys) { 38 | _ret.Add(new Keyframe(_frame.value, _frame.nTime)); 39 | } 40 | return _ret.ToArray(); 41 | } 42 | #endregion 43 | 44 | #region Public Functions 45 | public void StartTween() { 46 | Init(); 47 | } 48 | 49 | public void StopTween() { 50 | Dispose(); 51 | } 52 | #endregion 53 | 54 | #region Override Functions 55 | protected virtual void Init() { 56 | m_Tween = new Tweener(GenericKeys(keys), duration, delay, wrap); 57 | if (m_Tween.Loop != null) { 58 | m_Tween.OnSetValue += OnSetValue; 59 | m_Tween.OnMoveValue += OnMoveValue; 60 | StartCoroutine(m_Tween.Loop); 61 | } 62 | } 63 | 64 | protected virtual void Dispose() { 65 | if (m_Tween.Loop != null) { 66 | m_Tween.OnSetValue -= OnSetValue; 67 | m_Tween.OnMoveValue -= OnMoveValue; 68 | StopCoroutine(m_Tween.Loop); 69 | } 70 | } 71 | 72 | protected abstract void OnSetValue(Color _val); 73 | protected abstract void OnMoveValue(Color _curr, Color _target, float _nTime); 74 | #endregion 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Tween/FloatTween.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Tween { 6 | 7 | /// 8 | /// FloatTween is a MonoBehaviour wrapper class for float tween objects 9 | /// It is responsible for responding to events from the tween process 10 | /// 11 | public abstract class FloatTween : MonoBehaviour 12 | { 13 | 14 | //public Keyframe[] keys; 15 | public FloatKeyframe[] keys; 16 | public float duration; 17 | public float delay; 18 | public bool wrap; 19 | 20 | protected Tweener m_Tween; 21 | 22 | #region Unity Functions 23 | private void OnEnable() { 24 | Init(); 25 | } 26 | 27 | private void OnDisable() { 28 | Dispose(); 29 | } 30 | #endregion 31 | 32 | #region Private Functions 33 | private Keyframe[] GenericKeys(FloatKeyframe[] _keys) { 34 | var _ret = new List>(); 35 | foreach (FloatKeyframe _frame in _keys) { 36 | _ret.Add(new Keyframe(_frame.value, _frame.nTime)); 37 | } 38 | return _ret.ToArray(); 39 | } 40 | #endregion 41 | 42 | #region Override Functions 43 | protected virtual void Init() { 44 | m_Tween = new Tweener(GenericKeys(keys), duration, delay, wrap); 45 | if (m_Tween.Loop != null) { 46 | m_Tween.OnSetValue += OnSetValue; 47 | m_Tween.OnMoveValue += OnMoveValue; 48 | StartCoroutine(m_Tween.Loop); 49 | } 50 | } 51 | 52 | protected virtual void Dispose() { 53 | if (m_Tween.Loop != null) { 54 | m_Tween.OnSetValue -= OnSetValue; 55 | m_Tween.OnMoveValue -= OnMoveValue; 56 | StopCoroutine(m_Tween.Loop); 57 | } 58 | } 59 | 60 | protected abstract void OnSetValue(float _val); 61 | protected abstract void OnMoveValue(float _curr, float _target, float _nTime); 62 | #endregion 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tween/ImageColorTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Tween { 6 | 7 | [RequireComponent(typeof(Image))] 8 | public class ImageColorTween : ColorTween 9 | { 10 | private Image m_Image; 11 | 12 | #region Override Functions 13 | protected override void Init() { 14 | m_Image = GetComponent(); 15 | base.Init(); 16 | } 17 | 18 | protected override void OnSetValue(Color _val) { 19 | m_Image.color = _val; 20 | } 21 | 22 | protected override void OnMoveValue(Color _curr, Color _target, float _nTime) { 23 | m_Image.color = Color.Lerp(_curr, _target, _nTime); 24 | } 25 | #endregion 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Tween/ImageFillTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Tween { 6 | 7 | [RequireComponent(typeof(Image))] 8 | public class ImageFillTween : FloatTween 9 | { 10 | private Image m_Image; 11 | 12 | #region Override Functions 13 | protected override void Init() { 14 | m_Image = GetComponent(); 15 | base.Init(); 16 | } 17 | 18 | protected override void OnSetValue(float _val) { 19 | m_Image.fillAmount = _val; 20 | } 21 | 22 | protected override void OnMoveValue(float _curr, float _target, float _nTime) { 23 | m_Image.fillAmount = Mathf.Lerp(_curr, _target, _nTime); 24 | } 25 | #endregion 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Tween/Keyframe.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace Tween { 5 | 6 | public class Keyframe 7 | { 8 | public T value; 9 | [Range(0,1)] 10 | public float nTime; 11 | 12 | public Keyframe(T _val, float _n) { 13 | this.value = _val; 14 | this.nTime = _n; 15 | } 16 | } 17 | 18 | [System.Serializable] 19 | public class Vec3Keyframe 20 | { 21 | public Vector3 value; 22 | [Range(0,1)] 23 | public float nTime; 24 | } 25 | 26 | [System.Serializable] 27 | public class FloatKeyframe 28 | { 29 | public float value; 30 | [Range(0,1)] 31 | public float nTime; 32 | } 33 | 34 | [System.Serializable] 35 | public class ColorKeyframe 36 | { 37 | public Color value; 38 | [Range(0,1)] 39 | public float nTime; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tween/PositionTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace Tween { 5 | 6 | public class PositionTween : Vector3Tween 7 | { 8 | #region Override Functions 9 | protected override void OnSetValue(Vector3 _val) { 10 | transform.localPosition = _val; 11 | } 12 | 13 | protected override void OnMoveValue(Vector3 _curr, Vector3 _target, float _nTime) { 14 | transform.localPosition = Vector3.Lerp(_curr, _target, _nTime); 15 | } 16 | #endregion 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Tween/RotationTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace Tween { 5 | 6 | public class RotationTween : Vector3Tween 7 | { 8 | #region Override Functions 9 | protected override void OnSetValue(Vector3 _val) { 10 | transform.localRotation = Quaternion.Euler(_val); 11 | } 12 | 13 | protected override void OnMoveValue(Vector3 _curr, Vector3 _target, float _nTime) { 14 | transform.localRotation = Quaternion.Euler(Vector3.Lerp(_curr, _target, _nTime)); 15 | } 16 | #endregion 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Tween/ScaleTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace Tween { 5 | 6 | public class ScaleTween : Vector3Tween 7 | { 8 | #region Override Functions 9 | protected override void OnSetValue(Vector3 _val) { 10 | transform.localScale = _val; 11 | } 12 | 13 | protected override void OnMoveValue(Vector3 _curr, Vector3 _target, float _nTime) { 14 | transform.localScale = Vector3.Lerp(_curr, _target, _nTime); 15 | } 16 | #endregion 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Tween/SpriteColorTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | 4 | namespace Tween { 5 | 6 | [RequireComponent(typeof(SpriteRenderer))] 7 | public class SpriteColorTween : ColorTween 8 | { 9 | private SpriteRenderer m_Sprite; 10 | 11 | #region Override Functions 12 | protected override void Init() { 13 | m_Sprite = GetComponent(); 14 | base.Init(); 15 | } 16 | 17 | protected override void OnSetValue(Color _val) { 18 | m_Sprite.color = _val; 19 | } 20 | 21 | protected override void OnMoveValue(Color _curr, Color _target, float _nTime) { 22 | m_Sprite.color = Color.Lerp(_curr, _target, _nTime); 23 | } 24 | #endregion 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Tween/TextColorTween.cs: -------------------------------------------------------------------------------- 1 |  2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace Tween { 6 | 7 | [RequireComponent(typeof(Text))] 8 | public class TextColorTween : ColorTween 9 | { 10 | private Text m_Text; 11 | 12 | #region Override Functions 13 | protected override void Init() { 14 | m_Text = GetComponent(); 15 | base.Init(); 16 | } 17 | 18 | protected override void OnSetValue(Color _val) { 19 | m_Text.color = _val; 20 | } 21 | 22 | protected override void OnMoveValue(Color _curr, Color _target, float _nTime) { 23 | m_Text.color = Color.Lerp(_curr, _target, _nTime); 24 | } 25 | #endregion 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Tween/Tweener.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Tween { 6 | 7 | public class Tweener 8 | { 9 | 10 | public delegate void SetValueDelegate(T _val); 11 | public delegate void MoveValueDelegate(T _curr, T _target, float _nTime); 12 | public event SetValueDelegate OnSetValue; 13 | public event MoveValueDelegate OnMoveValue; 14 | 15 | private Keyframe[] m_Keys; 16 | private float m_Duration; 17 | private float m_Delay; 18 | private IEnumerator m_Loop; 19 | private int m_Index = -1; 20 | private bool m_Wrap; 21 | 22 | public IEnumerator Loop { 23 | get { 24 | return m_Loop; 25 | } 26 | } 27 | 28 | #region Constructors 29 | public Tweener(Keyframe[] _keys, float _duration, float _delay, bool _wrap) { 30 | m_Keys = _keys; 31 | m_Duration = _duration; 32 | m_Delay = _delay; 33 | m_Wrap = _wrap; 34 | 35 | if (m_Keys.Length > 0) { 36 | m_Loop = RunTween(); 37 | } 38 | } 39 | #endregion 40 | 41 | #region Private Functions 42 | private IEnumerator RunTween() { 43 | yield return new WaitForSeconds(m_Delay); 44 | 45 | var _key = GetNextKey(); 46 | var _nextKey = GetNextKey(); 47 | float _timer = 0; 48 | float _time = Mathf.Abs(_nextKey.nTime - _key.nTime) * m_Duration; 49 | 50 | SetValue(_key.value); 51 | 52 | // run until coroutine is stopped 53 | while (true) { 54 | _timer += Time.deltaTime; 55 | 56 | MoveValue(_key.value, _nextKey.value, _timer / _time); 57 | 58 | if (_timer > _time) { 59 | if (m_Wrap) { 60 | _key = _nextKey; 61 | } else { 62 | _key = GetNextKey(); 63 | } 64 | _nextKey = GetNextKey(); 65 | _time = Mathf.Abs(_nextKey.nTime - _key.nTime) * m_Duration; 66 | _timer = 0; 67 | } 68 | 69 | yield return null; 70 | } 71 | } 72 | 73 | private Keyframe GetNextKey() { 74 | m_Index ++; 75 | if (m_Index > m_Keys.Length - 1) { 76 | m_Index = 0; 77 | } 78 | return m_Keys[m_Index]; 79 | } 80 | 81 | private void SetValue(T _val) { 82 | try { 83 | OnSetValue(_val); 84 | } catch (System.Exception) {} 85 | } 86 | 87 | private void MoveValue(T _current, T _target, float _nTime) { 88 | try { 89 | OnMoveValue(_current, _target, _nTime); 90 | } catch (System.Exception) {} 91 | } 92 | #endregion 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Tween/Vector3Tween.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Tween { 6 | 7 | /// 8 | /// Vector3Tween is a MonoBehaviour wrapper class for Vector3 tween objects 9 | /// It is responsible for responding to events from the tween process 10 | /// 11 | public abstract class Vector3Tween : MonoBehaviour 12 | { 13 | //public Keyframe[] keys; 14 | public Vec3Keyframe[] keys; 15 | public float duration; 16 | public float delay; 17 | public bool wrap; 18 | 19 | protected Tweener m_Tween; 20 | 21 | #region Unity Functions 22 | private void OnEnable() { 23 | Init(); 24 | } 25 | 26 | private void OnDisable() { 27 | Dispose(); 28 | } 29 | #endregion 30 | 31 | #region Private Functions 32 | private Keyframe[] GenericKeys(Vec3Keyframe[] _keys) { 33 | var _ret = new List>(); 34 | foreach (Vec3Keyframe _frame in _keys) { 35 | _ret.Add(new Keyframe(_frame.value, _frame.nTime)); 36 | } 37 | return _ret.ToArray(); 38 | } 39 | #endregion 40 | 41 | #region Override Functions 42 | protected virtual void Init() { 43 | m_Tween = new Tweener(GenericKeys(keys), duration, delay, wrap); 44 | if (m_Tween.Loop != null) { 45 | m_Tween.OnSetValue += OnSetValue; 46 | m_Tween.OnMoveValue += OnMoveValue; 47 | StartCoroutine(m_Tween.Loop); 48 | } 49 | } 50 | 51 | protected virtual void Dispose() { 52 | if (m_Tween.Loop != null) { 53 | m_Tween.OnSetValue -= OnSetValue; 54 | m_Tween.OnMoveValue -= OnMoveValue; 55 | StopCoroutine(m_Tween.Loop); 56 | } 57 | } 58 | 59 | protected abstract void OnSetValue(Vector3 _val); 60 | protected abstract void OnMoveValue(Vector3 _curr, Vector3 _target, float _nTime); 61 | #endregion 62 | } 63 | } 64 | --------------------------------------------------------------------------------