├── .gitignore
├── Assets
├── Timers.meta
└── Timers
│ ├── Example.meta
│ ├── Example
│ ├── Test.cs
│ ├── Test.cs.meta
│ ├── test.unity
│ └── test.unity.meta
│ ├── Special.meta
│ ├── Special
│ ├── Ability.cs
│ └── Ability.cs.meta
│ ├── Timer.cs
│ ├── Timer.cs.meta
│ ├── TimerHelper.cs
│ ├── TimerHelper.cs.meta
│ ├── Timer_Behaviors.cs
│ └── Timer_Behaviors.cs.meta
├── LICENSE
├── LICENSE.meta
├── ProjectSettings
├── AudioManager.asset
├── ClusterInputManager.asset
├── DynamicsManager.asset
├── EditorBuildSettings.asset
├── EditorSettings.asset
├── GraphicsSettings.asset
├── InputManager.asset
├── NavMeshAreas.asset
├── NetworkManager.asset
├── Physics2DSettings.asset
├── ProjectSettings.asset
├── ProjectVersion.txt
├── QualitySettings.asset
├── TagManager.asset
├── TimeManager.asset
├── UnityAdsSettings.asset
└── UnityConnectSettings.asset
├── README.md
├── Test.meta
├── Timer.cs.meta
├── TimerHelper.cs.meta
└── Timer_Behaviors.cs.meta
/.gitignore:
--------------------------------------------------------------------------------
1 | /[Ll]ibrary/
2 | /[Tt]emp/
3 | /[Oo]bj/
4 | /[Bb]uild/
5 | /[Bb]uilds/
6 | /Assets/AssetStoreTools*
7 |
8 | # Autogenerated VS/MD solution and project files
9 | ExportedObj/
10 | *.csproj
11 | *.unityproj
12 | *.sln
13 | *.suo
14 | *.tmp
15 | *.user
16 | *.userprefs
17 | *.pidb
18 | *.booproj
19 | *.svd
20 |
21 |
22 | # Unity3D generated meta files
23 | *.pidb.meta
24 |
25 | # Unity3D Generated File On Crash Reports
26 | sysinfo.txt
27 |
--------------------------------------------------------------------------------
/Assets/Timers.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c487c5b02ac763a45a5b72c73c3240bb
3 | folderAsset: yes
4 | timeCreated: 1473339839
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Assets/Timers/Example.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9b925090b4f7a3e49a7b6e7b3c5d20e7
3 | folderAsset: yes
4 | timeCreated: 1473339839
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Assets/Timers/Example/Test.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | public class Test : MonoBehaviour
5 | {
6 |
7 | // Use this for initialization
8 | void Start()
9 | {
10 | //Start simple repeater
11 | Timer.Repeater(5f, () => Debug.Log("Repeater test"));
12 | //Start countdown and call Draw in 2.5 seconds
13 | Timer.Countdown(2.5f, Draw);
14 |
15 | //Start countdown and tell it to ignore Time Scale
16 | Timer.Countdown(10f, () => Debug.Log("Terminating Countdown #2")).SetIgnoreTimeScale(true);
17 | //Start a repeater, if we try to destroy it manually it wont take effect as countdown self destructs on reaching end.
18 | Timer timer = Timer.Countdown(1f, null);
19 | timer.SetCallbacks(() =>
20 | {
21 | Debug.Log("Destroyed timer:" + timer.GetHashCode()); timer.Destroy();
22 | });
23 | //After we launched sphere repeater we will change its update speed in 8 seconds
24 | Timer.Countdown(8f, () => sphereRepeater.MainInterval = 0.01f);
25 | //Create a timer and modify callback afterwards
26 | Timer t = Timer.Countdown(10f, null);
27 | t.SetCallbacks(() => Debug.Log("Delayed Callback"));
28 | //Pause it
29 | t.Pause();
30 | //Resume it
31 | t.Unpause();
32 |
33 | //Make eternal self reseting timer
34 | Timer toreset = Timer.Countdown(1f, null);
35 | //mark as non disposable
36 | toreset.DontDisposeOnComplete = true;
37 | //in callback it resets itself
38 | toreset.SetCallbacks(() =>
39 | {
40 | print("resetting timer" + toreset.GetHashCode().ToString());
41 | toreset.Reset();
42 | });
43 |
44 | //Test performance this will create ~500 timers and will rotate them afterwards in the pool eternally with no GC
45 | Timer.Repeater(.01f, SpawnTimers);
46 | }
47 |
48 | void SpawnTimers()
49 | {
50 | Timer t = Timer.Countdown(5f, null);
51 | t.SetCallbacks(() => t.GetHashCode());
52 | }
53 |
54 | Timer sphereRepeater;
55 | void Draw()
56 | {
57 | //premake some data
58 | GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
59 | //Start new repeater with parameters that will update our data this is completely stupid in this scenario but it shows the usage.
60 | Debug.Log("Started RepositioningSphere");
61 | sphereRepeater = Timer.RepeaterParam(
62 | .1f
63 | , x => Reposition(x)
64 | , new object[1] { go });
65 | }
66 |
67 | //Casting is costly, this is just example
68 | void Reposition(object[] args)
69 | {
70 | //Receive data and process it
71 | var go = args[0] as GameObject;
72 |
73 | var pos = go.transform.position;
74 | pos.y = Mathf.Sin(Time.time) * 2.5f;
75 | go.transform.position = pos;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Assets/Timers/Example/Test.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ab048a25e87eef34992701885c16974e
3 | timeCreated: 1461235087
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Assets/Timers/Example/test.unity:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!29 &1
4 | SceneSettings:
5 | m_ObjectHideFlags: 0
6 | m_PVSData:
7 | m_PVSObjectsArray: []
8 | m_PVSPortalsArray: []
9 | m_OcclusionBakeSettings:
10 | smallestOccluder: 5
11 | smallestHole: 0.25
12 | backfaceThreshold: 100
13 | --- !u!104 &2
14 | RenderSettings:
15 | m_ObjectHideFlags: 0
16 | serializedVersion: 7
17 | m_Fog: 0
18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
19 | m_FogMode: 3
20 | m_FogDensity: 0.01
21 | m_LinearFogStart: 0
22 | m_LinearFogEnd: 300
23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
26 | m_AmbientIntensity: 1
27 | m_AmbientMode: 0
28 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
29 | m_HaloStrength: 0.5
30 | m_FlareStrength: 1
31 | m_FlareFadeSpeed: 3
32 | m_HaloTexture: {fileID: 0}
33 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
34 | m_DefaultReflectionMode: 0
35 | m_DefaultReflectionResolution: 128
36 | m_ReflectionBounces: 1
37 | m_ReflectionIntensity: 1
38 | m_CustomReflection: {fileID: 0}
39 | m_Sun: {fileID: 0}
40 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
41 | --- !u!157 &3
42 | LightmapSettings:
43 | m_ObjectHideFlags: 0
44 | serializedVersion: 7
45 | m_GIWorkflowMode: 0
46 | m_GISettings:
47 | serializedVersion: 2
48 | m_BounceScale: 1
49 | m_IndirectOutputScale: 1
50 | m_AlbedoBoost: 1
51 | m_TemporalCoherenceThreshold: 1
52 | m_EnvironmentLightingMode: 0
53 | m_EnableBakedLightmaps: 1
54 | m_EnableRealtimeLightmaps: 1
55 | m_LightmapEditorSettings:
56 | serializedVersion: 4
57 | m_Resolution: 2
58 | m_BakeResolution: 40
59 | m_TextureWidth: 1024
60 | m_TextureHeight: 1024
61 | m_AO: 0
62 | m_AOMaxDistance: 1
63 | m_CompAOExponent: 1
64 | m_CompAOExponentDirect: 0
65 | m_Padding: 2
66 | m_LightmapParameters: {fileID: 0}
67 | m_LightmapsBakeMode: 1
68 | m_TextureCompression: 1
69 | m_DirectLightInLightProbes: 1
70 | m_FinalGather: 0
71 | m_FinalGatherFiltering: 1
72 | m_FinalGatherRayCount: 256
73 | m_ReflectionCompression: 2
74 | m_LightingDataAsset: {fileID: 0}
75 | m_RuntimeCPUUsage: 25
76 | --- !u!196 &4
77 | NavMeshSettings:
78 | serializedVersion: 2
79 | m_ObjectHideFlags: 0
80 | m_BuildSettings:
81 | serializedVersion: 2
82 | agentRadius: 0.5
83 | agentHeight: 2
84 | agentSlope: 45
85 | agentClimb: 0.4
86 | ledgeDropHeight: 0
87 | maxJumpAcrossDistance: 0
88 | accuratePlacement: 0
89 | minRegionArea: 2
90 | cellSize: 0.16666667
91 | manualCellSize: 0
92 | m_NavMeshData: {fileID: 0}
93 | --- !u!1 &172517602
94 | GameObject:
95 | m_ObjectHideFlags: 0
96 | m_PrefabParentObject: {fileID: 0}
97 | m_PrefabInternal: {fileID: 0}
98 | serializedVersion: 4
99 | m_Component:
100 | - 4: {fileID: 172517604}
101 | - 114: {fileID: 172517603}
102 | m_Layer: 0
103 | m_Name: CLICKME
104 | m_TagString: Untagged
105 | m_Icon: {fileID: 0}
106 | m_NavMeshLayer: 0
107 | m_StaticEditorFlags: 0
108 | m_IsActive: 1
109 | --- !u!114 &172517603
110 | MonoBehaviour:
111 | m_ObjectHideFlags: 0
112 | m_PrefabParentObject: {fileID: 0}
113 | m_PrefabInternal: {fileID: 0}
114 | m_GameObject: {fileID: 172517602}
115 | m_Enabled: 1
116 | m_EditorHideFlags: 0
117 | m_Script: {fileID: 11500000, guid: ab048a25e87eef34992701885c16974e, type: 3}
118 | m_Name:
119 | m_EditorClassIdentifier:
120 | --- !u!4 &172517604
121 | Transform:
122 | m_ObjectHideFlags: 0
123 | m_PrefabParentObject: {fileID: 0}
124 | m_PrefabInternal: {fileID: 0}
125 | m_GameObject: {fileID: 172517602}
126 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
127 | m_LocalPosition: {x: 0.43013096, y: -0.8892231, z: 0.50918865}
128 | m_LocalScale: {x: 1, y: 1, z: 1}
129 | m_Children: []
130 | m_Father: {fileID: 0}
131 | m_RootOrder: 0
132 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
133 | --- !u!1 &734489118
134 | GameObject:
135 | m_ObjectHideFlags: 0
136 | m_PrefabParentObject: {fileID: 0}
137 | m_PrefabInternal: {fileID: 0}
138 | serializedVersion: 4
139 | m_Component:
140 | - 4: {fileID: 734489123}
141 | - 20: {fileID: 734489122}
142 | - 92: {fileID: 734489121}
143 | - 124: {fileID: 734489120}
144 | - 81: {fileID: 734489119}
145 | m_Layer: 0
146 | m_Name: Main Camera
147 | m_TagString: MainCamera
148 | m_Icon: {fileID: 0}
149 | m_NavMeshLayer: 0
150 | m_StaticEditorFlags: 0
151 | m_IsActive: 1
152 | --- !u!81 &734489119
153 | AudioListener:
154 | m_ObjectHideFlags: 0
155 | m_PrefabParentObject: {fileID: 0}
156 | m_PrefabInternal: {fileID: 0}
157 | m_GameObject: {fileID: 734489118}
158 | m_Enabled: 1
159 | --- !u!124 &734489120
160 | Behaviour:
161 | m_ObjectHideFlags: 0
162 | m_PrefabParentObject: {fileID: 0}
163 | m_PrefabInternal: {fileID: 0}
164 | m_GameObject: {fileID: 734489118}
165 | m_Enabled: 1
166 | --- !u!92 &734489121
167 | Behaviour:
168 | m_ObjectHideFlags: 0
169 | m_PrefabParentObject: {fileID: 0}
170 | m_PrefabInternal: {fileID: 0}
171 | m_GameObject: {fileID: 734489118}
172 | m_Enabled: 1
173 | --- !u!20 &734489122
174 | Camera:
175 | m_ObjectHideFlags: 0
176 | m_PrefabParentObject: {fileID: 0}
177 | m_PrefabInternal: {fileID: 0}
178 | m_GameObject: {fileID: 734489118}
179 | m_Enabled: 1
180 | serializedVersion: 2
181 | m_ClearFlags: 1
182 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
183 | m_NormalizedViewPortRect:
184 | serializedVersion: 2
185 | x: 0
186 | y: 0
187 | width: 1
188 | height: 1
189 | near clip plane: 0.3
190 | far clip plane: 1000
191 | field of view: 60
192 | orthographic: 0
193 | orthographic size: 5
194 | m_Depth: -1
195 | m_CullingMask:
196 | serializedVersion: 2
197 | m_Bits: 4294967295
198 | m_RenderingPath: -1
199 | m_TargetTexture: {fileID: 0}
200 | m_TargetDisplay: 0
201 | m_TargetEye: 3
202 | m_HDR: 0
203 | m_OcclusionCulling: 1
204 | m_StereoConvergence: 10
205 | m_StereoSeparation: 0.022
206 | m_StereoMirrorMode: 0
207 | --- !u!4 &734489123
208 | Transform:
209 | m_ObjectHideFlags: 0
210 | m_PrefabParentObject: {fileID: 0}
211 | m_PrefabInternal: {fileID: 0}
212 | m_GameObject: {fileID: 734489118}
213 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
214 | m_LocalPosition: {x: 0, y: 1, z: -10}
215 | m_LocalScale: {x: 1, y: 1, z: 1}
216 | m_Children: []
217 | m_Father: {fileID: 0}
218 | m_RootOrder: 1
219 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
220 | --- !u!1 &1773092979
221 | GameObject:
222 | m_ObjectHideFlags: 0
223 | m_PrefabParentObject: {fileID: 0}
224 | m_PrefabInternal: {fileID: 0}
225 | serializedVersion: 4
226 | m_Component:
227 | - 4: {fileID: 1773092982}
228 | - 108: {fileID: 1773092981}
229 | m_Layer: 0
230 | m_Name: Directional Light
231 | m_TagString: Untagged
232 | m_Icon: {fileID: 0}
233 | m_NavMeshLayer: 0
234 | m_StaticEditorFlags: 0
235 | m_IsActive: 1
236 | --- !u!108 &1773092981
237 | Light:
238 | m_ObjectHideFlags: 0
239 | m_PrefabParentObject: {fileID: 0}
240 | m_PrefabInternal: {fileID: 0}
241 | m_GameObject: {fileID: 1773092979}
242 | m_Enabled: 1
243 | serializedVersion: 7
244 | m_Type: 1
245 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
246 | m_Intensity: 1
247 | m_Range: 10
248 | m_SpotAngle: 30
249 | m_CookieSize: 10
250 | m_Shadows:
251 | m_Type: 2
252 | m_Resolution: -1
253 | m_Strength: 1
254 | m_Bias: 0.05
255 | m_NormalBias: 0.4
256 | m_NearPlane: 0.2
257 | m_Cookie: {fileID: 0}
258 | m_DrawHalo: 0
259 | m_Flare: {fileID: 0}
260 | m_RenderMode: 0
261 | m_CullingMask:
262 | serializedVersion: 2
263 | m_Bits: 4294967295
264 | m_Lightmapping: 4
265 | m_AreaSize: {x: 1, y: 1}
266 | m_BounceIntensity: 1
267 | m_ShadowRadius: 0
268 | m_ShadowAngle: 0
269 | --- !u!4 &1773092982
270 | Transform:
271 | m_ObjectHideFlags: 0
272 | m_PrefabParentObject: {fileID: 0}
273 | m_PrefabInternal: {fileID: 0}
274 | m_GameObject: {fileID: 1773092979}
275 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
276 | m_LocalPosition: {x: 0, y: 3, z: 0}
277 | m_LocalScale: {x: 1, y: 1, z: 1}
278 | m_Children: []
279 | m_Father: {fileID: 0}
280 | m_RootOrder: 2
281 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
282 |
--------------------------------------------------------------------------------
/Assets/Timers/Example/test.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 54f7720cb4277694b9b382703a233c06
3 | timeCreated: 1461235188
4 | licenseType: Free
5 | DefaultImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Assets/Timers/Special.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9d9ca31be44594a4d88ed5b9f3b96029
3 | folderAsset: yes
4 | timeCreated: 1473340860
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Assets/Timers/Special/Ability.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 |
5 | ///
6 | /// Object that is used to control if action can be fired or not based on internal timer.
7 | /// ON cooldown - means you are cooling down the ability and cant use it yet
8 | /// OFF cooldown - means you finised cooling down and are ready to use it
9 | ///
10 | ///
11 | /// USAGE
12 | /// 1. Create Cooldown object with a constructor and provide starting parameters
13 | /// 2. Use available events to specify cooldown functionality
14 | /// 3. Call "Use" method for "casting" something
15 | /// 4. When not needed anymore, use Destroy
16 | /// 5. parameters are read only, if you need to modify cooldown on runtime, create new one
17 | ///
18 | [Serializable]
19 | public class Ability {
20 |
21 | Timer cooldown_timer;
22 | Timer cast_timer;
23 |
24 | ///
25 | /// What happens right the moment we start action, ignoring the cast time/delay
26 | ///
27 | public event Action onStart;
28 | ///
29 | /// What will happen if cooldown allows action
30 | ///
31 | public event Action onCast;
32 | ///
33 | /// What happens after cooldown ends
34 | ///
35 | public event Action onOffCooldown;
36 |
37 | ///
38 | /// When cancel was explicitly called
39 | ///
40 | public event Action onCancel;
41 |
42 | ///
43 | /// For errors and other purposes
44 | ///
45 | public string name { get; private set; }
46 |
47 | ///
48 | /// Actual cooldown time
49 | ///
50 | public float cooldown_time { get; private set; }
51 | public float cooldown_left { get; private set; }
52 |
53 | public CooldownType cooldowntype;
54 |
55 | ///
56 | /// When does the cooldown start?
57 | ///
58 | public enum CooldownType
59 | {
60 | ///
61 | /// Cooldown begins from the moment we Use this cooldown, not waiting for delay
62 | ///
63 | fromStart,
64 | ///
65 | /// Cooldown begins after the cast timer finished, right at cast point
66 | ///
67 | fromCastPoint
68 | }
69 |
70 |
71 | ///
72 | /// The time from start till actual cast, think of it as delay in which you play cast animation and you can cancel
73 | ///
74 | public float castTime{ get; private set; }
75 |
76 | ///
77 | /// Initialization of timer should happen AFTER first use
78 | ///
79 | bool firstUse;
80 |
81 | ///
82 | /// When we are on cooldown, we cant use action, when we are off the cooldown, means action is ready
83 | ///
84 | public bool OnCooldown { get; private set; }
85 |
86 | ///
87 | /// Are we currently casting this ability?
88 | ///
89 | public bool isCasting { get; private set; }
90 | ///
91 | /// Is the ability completely suspended? (muted/stunned/frozen cooldown/disabled)
92 | ///
93 | public bool LockCasting { get; set; }
94 |
95 | bool has_cast_time;
96 |
97 | public Ability(string _name, float _cooldown_time, float _cast_time, Action _onActivate, CooldownType _type)
98 | {
99 | if(_onActivate == null)
100 | {
101 | Debug.LogError("Tried to create ability without callback" + name);
102 | return;
103 | }
104 | if (_cooldown_time <= 0f)
105 | {
106 | Debug.LogError("Resulting cooldown for " + _name + " is less or equal to zero, which is incorrect.");
107 | Debug.Break();
108 | }
109 | //we treat ability as immutable object, so we only accept the callback in constructor
110 | onCast = _onActivate;
111 | //use for error reports and other things
112 | name = _name;
113 | //do we have a cast time?
114 | has_cast_time = _cast_time > 0f ? true : false;
115 | //if yes, create cast timer
116 | if (has_cast_time && cast_timer == null)
117 | {
118 | cast_timer = Timer.Countdown(_cast_time, actual_cast).Pause();
119 | }
120 |
121 | cooldown_time = _cooldown_time;
122 | //switch (_type)
123 | //{
124 | // case CooldownType.fromStart:
125 | // cooldown_time = _cooldown_time + _cast_time;
126 | // break;
127 | // case CooldownType.fromCastPoint:
128 | // cooldown_time = _cooldown_time;
129 | // break;
130 | // default:
131 | // break;
132 | //}
133 |
134 | castTime = _cast_time;
135 | cooldowntype = _type;
136 | firstUse = true;
137 | }
138 |
139 | ///
140 | /// This will activate attached action
141 | ///
142 | public bool Use()
143 | {
144 | if (!OnCooldown && !LockCasting)
145 | {
146 | activate();
147 | return true;
148 | }
149 | else
150 | return false;
151 | }
152 |
153 | ///
154 | /// this activates attached action
155 | ///
156 | void activate()
157 | {
158 | if (onStart != null)
159 | onStart();
160 | //on first use we Activate, and create a cooldown timer
161 | if (firstUse)
162 | {
163 | if (has_cast_time && cooldowntype == CooldownType.fromStart)
164 | cooldown_timer = Timer.Countdown(cooldown_time + castTime, put_offcooldown);
165 | else
166 | cooldown_timer = Timer.Countdown(cooldown_time, put_offcooldown);
167 |
168 | cooldown_timer.OnUpdate += () => cooldown_left = cooldown_timer.TimeLeft;
169 | //Dont let the pool reclaim this timer
170 | cooldown_timer.DontDisposeOnComplete = true;
171 | firstUse = false;
172 | }
173 |
174 | if (has_cast_time)
175 | {
176 | isCasting = true;
177 | if (cooldowntype == CooldownType.fromStart)
178 | {
179 | //we already are on cooldown, from the start of animation
180 | PutOnCooldown();
181 | }
182 | //when cast timer countdown finished it will cast
183 | cast_timer.Unpause();
184 | return;
185 | }
186 |
187 | else
188 | {
189 | actual_cast();
190 | PutOnCooldown();
191 | }
192 | }
193 |
194 | ///
195 | /// If you are currently casting will go back to start of the ability
196 | ///
197 | public void CancelCast()
198 | {
199 | if (isCasting)
200 | {
201 | if (onCancel != null)
202 | onCancel();
203 | //reset the cast timer
204 | if (has_cast_time)
205 | cast_timer.Reset().Pause();
206 | }
207 | }
208 |
209 | void actual_cast()
210 | {
211 | onCast();
212 | isCasting = false;
213 | //reset the cast timer
214 | if (has_cast_time)
215 | cast_timer.Reset().Pause();
216 | }
217 | ///
218 | /// Skips cast and goes straight to cooldown, use when you need to "break" the spell with another thing (like stun)
219 | ///
220 | public void PutOnCooldown()
221 | {
222 | if(firstUse || OnCooldown)
223 | {
224 | Debug.Log(name + "Already on cooldown");
225 | return;
226 | }
227 | OnCooldown = true;
228 | cooldown_timer.Unpause();
229 |
230 | }
231 |
232 | void reset()
233 | {
234 | if (has_cast_time)
235 | cast_timer.Reset().Pause();
236 | OnCooldown = isCasting = false;
237 | cooldown_timer.Reset().Pause();
238 | }
239 |
240 | ///
241 | /// "deactivates" or rather, resets the cooldown
242 | ///
243 | void put_offcooldown()
244 | {
245 | //Event raised when cooldown stops
246 | if (onOffCooldown != null)
247 | onOffCooldown();
248 | OnCooldown = false;
249 | cooldown_timer.Reset().Pause();
250 | }
251 |
252 |
253 | void Destroy()
254 | {
255 | cast_timer.Destroy();
256 | cooldown_timer.Destroy();
257 | }
258 |
259 | }
260 |
--------------------------------------------------------------------------------
/Assets/Timers/Special/Ability.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dbb0cfcfc1d5b0b488ff211cc96b4358
3 | timeCreated: 1473340861
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Assets/Timers/Timer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System;
5 | ///
6 | /// Timer is both static pool manager and dynamic DI container for concrete behaviors
7 | ///
8 | public partial class Timer
9 | {
10 | ///
11 | /// Implementers create behavior
12 | ///
13 | public interface ITimerBehavior
14 | {
15 | void Initialize();
16 | void Update(float deltaTime);
17 | }
18 |
19 |
20 | public bool Paused { get; private set; }
21 | //DI defines what kind of timer this is
22 | ITimerBehavior behavior;
23 | //This base is shared between all types of timers
24 | TimerBehaviorBase behaviorBase;
25 | //Which time delta we are using for this timer
26 | TimeDeltaType type = TimeDeltaType.TimeScaleDependent;
27 | public TimeDeltaType timeDeltaType { get { return type; } }
28 | public enum TimeDeltaType { TimeScaleDependent, TimeScaleIndependent }
29 | //Event signaling when some timer finished work and is ready to be released
30 | event Action OnStopped;
31 | public event Action OnUpdate;
32 | public bool WasDestroyed { get; private set; }
33 | public bool DontDisposeOnComplete { get; set; }
34 |
35 | public float TimePassedTotal { get; private set; }
36 | public float TimePassed { get; private set; }
37 | public float TimeLeft { get; private set; }
38 | ///
39 | /// Not all timer have one fixed interval, this is the first "value" the timer will use, Countdown will use it as countdown time, Repeater will use it as
40 | /// main interval between repeats and so on
41 | ///
42 | public float MainInterval
43 | {
44 | get { return behaviorBase.MainInterval; }
45 | set { behaviorBase.MainInterval = value; }
46 | }
47 | ///
48 | /// Not all timers return this, how many cycles have passed
49 | ///
50 | ///
51 | public float ElapsedCycles { get { return behaviorBase.ElapsedCycles; } }
52 |
53 | void Update(float REAL_DELTA, float TIMESCALE_DELTA)
54 | {
55 | //skip the ones that were completed, works with DontDisposeOnComplete flag
56 | if (behaviorBase.Completed)
57 | return;
58 | //first check for potential problems
59 | behaviorBase.CheckErrors();
60 |
61 | if (type == TimeDeltaType.TimeScaleDependent)
62 | behavior.Update(TIMESCALE_DELTA);
63 | else
64 | behavior.Update(REAL_DELTA);
65 |
66 | TimePassedTotal = behaviorBase.TotalTimeActive;
67 | TimePassed = behaviorBase.TimePassed;
68 | TimeLeft = MainInterval - TimePassed;
69 |
70 | if (OnUpdate != null)
71 | OnUpdate();
72 | //Notify pool if we completed work
73 | if (behaviorBase.Completed)
74 | {
75 | if (DontDisposeOnComplete)
76 | return;
77 | OnStopped(this);
78 | return;
79 | }
80 | }
81 |
82 |
83 | //again shortening common actions
84 | Timer registerBehavior(ITimerBehavior behav)
85 | {
86 | behavior = behav;
87 | behaviorBase = (TimerBehaviorBase)behavior;
88 | behaviorBase.timer = this;
89 | return this;
90 | }
91 |
92 | Timer SetBehavior() where T : TimerBehaviorBase, new()
93 | {
94 | Type t = typeof(T);
95 | ITimerBehavior behav = null;
96 | if (TimerManager.behaviors.ContainsKey(t))
97 | {
98 | List list = TimerManager.behaviors[t];
99 | if (list.Count > 0)
100 | {
101 | behav = list[0];
102 | list.Remove(behav);
103 | }
104 | }
105 | if (behav == null)
106 | behav = (ITimerBehavior)new T();
107 |
108 | registerBehavior(behav);
109 | return this;
110 | }
111 |
112 | public void Destroy()
113 | {
114 | TimerManager.ReleaseTimer(this);
115 | }
116 |
117 |
118 | ///
119 | /// Do we use Time.deltaTime OR Time.unscaledTimeDelta
120 | /// unscaled means not affected by Time scale, by default all timers ARE affected by timescale
121 | ///
122 | ///
123 | ///
124 | public Timer SetIgnoreTimeScale(bool ignoreTimeScale)
125 | {
126 | type = ignoreTimeScale ? TimeDeltaType.TimeScaleIndependent : TimeDeltaType.TimeScaleDependent;
127 | return this;
128 | }
129 |
130 |
131 | public Timer SetCallbacks(Action c1)
132 | {
133 | behaviorBase.SetCallbacks(c1, null, null, null);
134 | return this;
135 | }
136 |
137 | public Timer SetCallbacks(Action c1, Action c2)
138 | {
139 | behaviorBase.SetCallbacks(c1, c2, null, null);
140 | return this;
141 | }
142 |
143 | public Timer SetCallbacks(Action c1, Action c2, Action c3)
144 | {
145 | behaviorBase.SetCallbacks(c1, c2, c3, null);
146 | return this;
147 | }
148 |
149 | public Timer SetCallbacks(Action c1, Action c2, Action c3, Action c4)
150 | {
151 | behaviorBase.SetCallbacks(c1, c2, c3, c4);
152 | return this;
153 | }
154 |
155 | public Timer Reset()
156 | {
157 | behaviorBase.ResetTime();
158 | return this;
159 | }
160 |
161 | public Timer Pause()
162 | {
163 | Paused = true;
164 | return this;
165 | }
166 |
167 | public Timer Unpause()
168 | {
169 | Paused = false;
170 | return this;
171 | }
172 |
173 | ///
174 | /// We use this class to create timer types. We use its variables in concrete implementations, as per implementation.
175 | ///
176 | ///
177 | public class TimerBehaviorBase
178 | {
179 |
180 | public bool Completed { get; protected set; }
181 | public Timer timer;
182 |
183 | //How long the timer is UP (with all the pauses, resets, basically how long it lives since taken from pool)
184 | public float TotalTimeActive { get; protected set; }
185 | //Implementers can use these variables as they need
186 | public float TimePassed { get; protected set; }
187 | //Internally used floats
188 | protected float f1, f2, f3, f4;
189 | //callbacks
190 | protected Action c1, c2, c3, c4;
191 | //callbacks with parameters
192 | protected Action