diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs b/FallUnity/Assets/Utils/SimpleTimer.cs new file mode 100644 index 0000000..e24678b --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs @@ -0,0 +1,138 @@ +using System; +using UnityEngine; + +public delegate void SimpleTimerTick(); + +public class SimpleTimer +{ + bool hasTime = false; + float t; + private int tSeconds; + public float TimeLeft { get { return t; } } + public bool Active = false; + public SimpleTimerTick OnFinish = null; + + public Action OnSecondsChanged = null; + + + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public bool IgnoreFirstUpdate = true; + + private float duration; + protected bool loop = false; + + private EnterFrameManager efm; + public SimpleTimer() + { + efm = GameObject.FindObjectOfType(); + } + + public SimpleTimer(float time, SimpleTimerTick callback, bool loop = false) + { + Start(time, callback, loop); + } + + public void Start(float time, SimpleTimerTick callback, bool loop = false) + { + hasTime = true; + this.loop = loop; + OnFinish = callback; + this.duration = time; + this.t = time; + SetTSeconds(); + efm.Add(this, delegate (float t) { Update(t); }); + Active = true; + IgnoreFirstUpdate = true; + } + + private void SetTSeconds() + { + int oldTSeconds = tSeconds; + this.tSeconds = Math.Max(0, (int)Math.Ceiling(t)); + if (oldTSeconds != tSeconds && this.OnSecondsChanged != null) + { + OnSecondsChanged(tSeconds); + } + } + + public void Stop() + { + if (!Active) return; + efm.Remove(this); + Active = false; + OnFinish = null; + } + + private int pauseCount = 0; + public bool Paused { get { return pauseCount > 0; } } + + public void Pause() + { + if (!Active) return; + pauseCount++; + if (pauseCount == 1) + { + efm.Remove(this); + } + } + + public void Resume() + { + if (pauseCount == 0 || !hasTime) return; + pauseCount--; + if (pauseCount == 0) + { + efm.Add(this, delegate (float t) { Update(t); }); + } + } + + public void SetTime(float t) + { + this.t = t; + SetTSeconds(); + } + + public void AddTime(float a) + { + this.t += a; + SetTSeconds(); + } + + public void Update(float timeElapsed) + { + if (IgnoreFirstUpdate) + { + IgnoreFirstUpdate = false; + return; + } + + if (!Active) return; + if (Paused) return; + + t -= (timeElapsed * timeScale); + SetTSeconds(); + + if (t <= 0) + { + float actualTime = duration - t; + if (loop) + { + t += duration; + SetTSeconds(); + } + else + { + t = 0; + SetTSeconds(); + + Active = false; + efm.Remove(this); + } + + if (OnFinish != null) OnFinish(); + } + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs b/FallUnity/Assets/Utils/SimpleTimer.cs new file mode 100644 index 0000000..e24678b --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs @@ -0,0 +1,138 @@ +using System; +using UnityEngine; + +public delegate void SimpleTimerTick(); + +public class SimpleTimer +{ + bool hasTime = false; + float t; + private int tSeconds; + public float TimeLeft { get { return t; } } + public bool Active = false; + public SimpleTimerTick OnFinish = null; + + public Action OnSecondsChanged = null; + + + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public bool IgnoreFirstUpdate = true; + + private float duration; + protected bool loop = false; + + private EnterFrameManager efm; + public SimpleTimer() + { + efm = GameObject.FindObjectOfType(); + } + + public SimpleTimer(float time, SimpleTimerTick callback, bool loop = false) + { + Start(time, callback, loop); + } + + public void Start(float time, SimpleTimerTick callback, bool loop = false) + { + hasTime = true; + this.loop = loop; + OnFinish = callback; + this.duration = time; + this.t = time; + SetTSeconds(); + efm.Add(this, delegate (float t) { Update(t); }); + Active = true; + IgnoreFirstUpdate = true; + } + + private void SetTSeconds() + { + int oldTSeconds = tSeconds; + this.tSeconds = Math.Max(0, (int)Math.Ceiling(t)); + if (oldTSeconds != tSeconds && this.OnSecondsChanged != null) + { + OnSecondsChanged(tSeconds); + } + } + + public void Stop() + { + if (!Active) return; + efm.Remove(this); + Active = false; + OnFinish = null; + } + + private int pauseCount = 0; + public bool Paused { get { return pauseCount > 0; } } + + public void Pause() + { + if (!Active) return; + pauseCount++; + if (pauseCount == 1) + { + efm.Remove(this); + } + } + + public void Resume() + { + if (pauseCount == 0 || !hasTime) return; + pauseCount--; + if (pauseCount == 0) + { + efm.Add(this, delegate (float t) { Update(t); }); + } + } + + public void SetTime(float t) + { + this.t = t; + SetTSeconds(); + } + + public void AddTime(float a) + { + this.t += a; + SetTSeconds(); + } + + public void Update(float timeElapsed) + { + if (IgnoreFirstUpdate) + { + IgnoreFirstUpdate = false; + return; + } + + if (!Active) return; + if (Paused) return; + + t -= (timeElapsed * timeScale); + SetTSeconds(); + + if (t <= 0) + { + float actualTime = duration - t; + if (loop) + { + t += duration; + SetTSeconds(); + } + else + { + t = 0; + SetTSeconds(); + + Active = false; + efm.Remove(this); + } + + if (OnFinish != null) OnFinish(); + } + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs.meta b/FallUnity/Assets/Utils/SimpleTimer.cs.meta new file mode 100644 index 0000000..b2a1537 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 10e69767606338742ac79d0548ef27b5 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs b/FallUnity/Assets/Utils/SimpleTimer.cs new file mode 100644 index 0000000..e24678b --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs @@ -0,0 +1,138 @@ +using System; +using UnityEngine; + +public delegate void SimpleTimerTick(); + +public class SimpleTimer +{ + bool hasTime = false; + float t; + private int tSeconds; + public float TimeLeft { get { return t; } } + public bool Active = false; + public SimpleTimerTick OnFinish = null; + + public Action OnSecondsChanged = null; + + + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public bool IgnoreFirstUpdate = true; + + private float duration; + protected bool loop = false; + + private EnterFrameManager efm; + public SimpleTimer() + { + efm = GameObject.FindObjectOfType(); + } + + public SimpleTimer(float time, SimpleTimerTick callback, bool loop = false) + { + Start(time, callback, loop); + } + + public void Start(float time, SimpleTimerTick callback, bool loop = false) + { + hasTime = true; + this.loop = loop; + OnFinish = callback; + this.duration = time; + this.t = time; + SetTSeconds(); + efm.Add(this, delegate (float t) { Update(t); }); + Active = true; + IgnoreFirstUpdate = true; + } + + private void SetTSeconds() + { + int oldTSeconds = tSeconds; + this.tSeconds = Math.Max(0, (int)Math.Ceiling(t)); + if (oldTSeconds != tSeconds && this.OnSecondsChanged != null) + { + OnSecondsChanged(tSeconds); + } + } + + public void Stop() + { + if (!Active) return; + efm.Remove(this); + Active = false; + OnFinish = null; + } + + private int pauseCount = 0; + public bool Paused { get { return pauseCount > 0; } } + + public void Pause() + { + if (!Active) return; + pauseCount++; + if (pauseCount == 1) + { + efm.Remove(this); + } + } + + public void Resume() + { + if (pauseCount == 0 || !hasTime) return; + pauseCount--; + if (pauseCount == 0) + { + efm.Add(this, delegate (float t) { Update(t); }); + } + } + + public void SetTime(float t) + { + this.t = t; + SetTSeconds(); + } + + public void AddTime(float a) + { + this.t += a; + SetTSeconds(); + } + + public void Update(float timeElapsed) + { + if (IgnoreFirstUpdate) + { + IgnoreFirstUpdate = false; + return; + } + + if (!Active) return; + if (Paused) return; + + t -= (timeElapsed * timeScale); + SetTSeconds(); + + if (t <= 0) + { + float actualTime = duration - t; + if (loop) + { + t += duration; + SetTSeconds(); + } + else + { + t = 0; + SetTSeconds(); + + Active = false; + efm.Remove(this); + } + + if (OnFinish != null) OnFinish(); + } + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs.meta b/FallUnity/Assets/Utils/SimpleTimer.cs.meta new file mode 100644 index 0000000..b2a1537 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 10e69767606338742ac79d0548ef27b5 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTween.cs b/FallUnity/Assets/Utils/SimpleTween.cs new file mode 100644 index 0000000..82b4657 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTween.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public delegate void SimpleTweenUpdate(float cVal); +public delegate void SimpleTweenFinish(); + +public class SimpleTween +{ + public delegate float TweenFunction(float t, float b, float c, float d); + + protected TweenFunction thisTween; + + float t; //current time + float c; //delta + float b; //start value + float d; //duration + + public float tweenValue; + bool toInt = false; + + bool instant = false; + + public float MaxTime = -1; + + protected int InstanceID; + protected static int NextID = 0; + + private bool active = false; + public bool Active { get { return active; } } + + public SimpleTweenFinish OnFinish = null; + public SimpleTweenUpdate OnUpdate = null; + public bool Loop = false; + + private bool ignoreFirstUpdate = true; + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + + public enum TweenType { EaseLinear, QuadEaseIn, QuadEaseOut, QuadEaseInOut, StrongEaseIn, StrongEaseOut, StrongEaseInOut, SineWaveIn }; + + + protected int paused = 0; + public void Pause() + { + paused++; + } + public void Resume() + { + if (paused > 0) + { + paused--; + } + } + public bool Paused { get { return paused > 0; } } + + private EnterFrameManager efm; + public SimpleTween() + { + efm = GameObject.FindObjectOfType(); + InstanceID = NextID++; + active = false; + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenType tType, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + TweenFunction func = GetTweenFunction(tType); + Init(onUpdate, func, start, end, time, toInt); + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + Init(onUpdate, tweenFunc, start, end, time, toInt); + } + + public void Stop() + { + active = false; + OnFinish = null; + OnUpdate = null; + efm.Remove(this); + } + + public void Init(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + if (Active) Stop(); + this.OnUpdate = onUpdate; + this.toInt = toInt; + + tweenValue = start; + + this.thisTween = tweenFunc; + + + t = 0; + c = end - start; + b = start; + d = time; + + instant = (d == 0); + efm.Add(this, delegate (float timeElapsed) { Update(timeElapsed); }); + active = true; + } + + public void Update(float timeElapsed) + { + if (ignoreFirstUpdate) + { + ignoreFirstUpdate = false; + return; + } + + if (MaxTime != -1) timeElapsed = Math.Min(timeElapsed, MaxTime); + + if (paused > 0) return; + if (!Active) return; + + t += (timeElapsed * timeScale); + + if (t >= d) t = d; + + float val = 0; + + val = thisTween(instant ? 1.0f : t, b, c, instant ? 1.0f : d); + /* + switch(this.tType) + { + case TweenType.EaseLinear : val = SimpleTween.EaseLinear(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseIn : val = SimpleTween.QuadEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseInOut : val = SimpleTween.QuadEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseOut : val = SimpleTween.QuadEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseIn : val = SimpleTween.StrongEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseInOut : val = SimpleTween.StrongEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseOut : val = SimpleTween.StrongEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + } + */ + + int intVal = (int)val; + if (toInt) val = intVal; + + tweenValue = val; + + if (OnUpdate != null) OnUpdate(tweenValue); + + if (t == d) + { + if (Loop) + { + t = 0; + } + else + { + active = false; + efm.Remove(this); + } + if (OnFinish != null) OnFinish(); + + } + + } + + public void ForceUpdateCall() + { + if (active) + { + if (OnUpdate != null) OnUpdate(tweenValue); + } + } + + private static Dictionary typesToFunctions = new Dictionary() + { + { TweenType.EaseLinear, EaseLinear }, + { TweenType.QuadEaseIn, QuadEaseIn }, + { TweenType.QuadEaseInOut, QuadEaseInOut }, + { TweenType.QuadEaseOut, QuadEaseOut }, + { TweenType.StrongEaseIn, StrongEaseIn }, + { TweenType.StrongEaseInOut, StrongEaseInOut }, + { TweenType.StrongEaseOut, StrongEaseOut }, + { TweenType.SineWaveIn, SineWaveIn }, + }; + public static TweenFunction GetTweenFunction(TweenType tweenType) + { + if (typesToFunctions.ContainsKey(tweenType)) return typesToFunctions[tweenType]; + return EaseLinear; + } + + public static float SineWaveIn(float t, float b, float c, float d) + { + float param = (t / d); + float s = (-( (float)Math.Pow(((param-0.774f)*1.4f), 2) )) + 1.1f; + return c * s + b; + } + + public static float EaseLinear(float t, float b, float c, float d) + { + return c * t / d + b; + } + + public static float QuadEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t + b; + } + + public static float QuadEaseOut(float t, float b, float c, float d) + { + return -c * (t /= d) * (t - 2) + b; + } + + public static float QuadEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t + b; + return -c * 0.5f * ((--t) * (t - 2) - 1) + b; + } + + public static float StrongEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t * t * t * t + b; + } + + public static float StrongEaseOut(float t, float b, float c, float d) + { + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; + } + + public static float StrongEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t * t * t * t + b; + return c * 0.5f * ((t -= 2) * t * t * t * t + 2) + b; + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs b/FallUnity/Assets/Utils/SimpleTimer.cs new file mode 100644 index 0000000..e24678b --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs @@ -0,0 +1,138 @@ +using System; +using UnityEngine; + +public delegate void SimpleTimerTick(); + +public class SimpleTimer +{ + bool hasTime = false; + float t; + private int tSeconds; + public float TimeLeft { get { return t; } } + public bool Active = false; + public SimpleTimerTick OnFinish = null; + + public Action OnSecondsChanged = null; + + + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public bool IgnoreFirstUpdate = true; + + private float duration; + protected bool loop = false; + + private EnterFrameManager efm; + public SimpleTimer() + { + efm = GameObject.FindObjectOfType(); + } + + public SimpleTimer(float time, SimpleTimerTick callback, bool loop = false) + { + Start(time, callback, loop); + } + + public void Start(float time, SimpleTimerTick callback, bool loop = false) + { + hasTime = true; + this.loop = loop; + OnFinish = callback; + this.duration = time; + this.t = time; + SetTSeconds(); + efm.Add(this, delegate (float t) { Update(t); }); + Active = true; + IgnoreFirstUpdate = true; + } + + private void SetTSeconds() + { + int oldTSeconds = tSeconds; + this.tSeconds = Math.Max(0, (int)Math.Ceiling(t)); + if (oldTSeconds != tSeconds && this.OnSecondsChanged != null) + { + OnSecondsChanged(tSeconds); + } + } + + public void Stop() + { + if (!Active) return; + efm.Remove(this); + Active = false; + OnFinish = null; + } + + private int pauseCount = 0; + public bool Paused { get { return pauseCount > 0; } } + + public void Pause() + { + if (!Active) return; + pauseCount++; + if (pauseCount == 1) + { + efm.Remove(this); + } + } + + public void Resume() + { + if (pauseCount == 0 || !hasTime) return; + pauseCount--; + if (pauseCount == 0) + { + efm.Add(this, delegate (float t) { Update(t); }); + } + } + + public void SetTime(float t) + { + this.t = t; + SetTSeconds(); + } + + public void AddTime(float a) + { + this.t += a; + SetTSeconds(); + } + + public void Update(float timeElapsed) + { + if (IgnoreFirstUpdate) + { + IgnoreFirstUpdate = false; + return; + } + + if (!Active) return; + if (Paused) return; + + t -= (timeElapsed * timeScale); + SetTSeconds(); + + if (t <= 0) + { + float actualTime = duration - t; + if (loop) + { + t += duration; + SetTSeconds(); + } + else + { + t = 0; + SetTSeconds(); + + Active = false; + efm.Remove(this); + } + + if (OnFinish != null) OnFinish(); + } + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs.meta b/FallUnity/Assets/Utils/SimpleTimer.cs.meta new file mode 100644 index 0000000..b2a1537 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 10e69767606338742ac79d0548ef27b5 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTween.cs b/FallUnity/Assets/Utils/SimpleTween.cs new file mode 100644 index 0000000..82b4657 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTween.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public delegate void SimpleTweenUpdate(float cVal); +public delegate void SimpleTweenFinish(); + +public class SimpleTween +{ + public delegate float TweenFunction(float t, float b, float c, float d); + + protected TweenFunction thisTween; + + float t; //current time + float c; //delta + float b; //start value + float d; //duration + + public float tweenValue; + bool toInt = false; + + bool instant = false; + + public float MaxTime = -1; + + protected int InstanceID; + protected static int NextID = 0; + + private bool active = false; + public bool Active { get { return active; } } + + public SimpleTweenFinish OnFinish = null; + public SimpleTweenUpdate OnUpdate = null; + public bool Loop = false; + + private bool ignoreFirstUpdate = true; + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + + public enum TweenType { EaseLinear, QuadEaseIn, QuadEaseOut, QuadEaseInOut, StrongEaseIn, StrongEaseOut, StrongEaseInOut, SineWaveIn }; + + + protected int paused = 0; + public void Pause() + { + paused++; + } + public void Resume() + { + if (paused > 0) + { + paused--; + } + } + public bool Paused { get { return paused > 0; } } + + private EnterFrameManager efm; + public SimpleTween() + { + efm = GameObject.FindObjectOfType(); + InstanceID = NextID++; + active = false; + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenType tType, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + TweenFunction func = GetTweenFunction(tType); + Init(onUpdate, func, start, end, time, toInt); + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + Init(onUpdate, tweenFunc, start, end, time, toInt); + } + + public void Stop() + { + active = false; + OnFinish = null; + OnUpdate = null; + efm.Remove(this); + } + + public void Init(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + if (Active) Stop(); + this.OnUpdate = onUpdate; + this.toInt = toInt; + + tweenValue = start; + + this.thisTween = tweenFunc; + + + t = 0; + c = end - start; + b = start; + d = time; + + instant = (d == 0); + efm.Add(this, delegate (float timeElapsed) { Update(timeElapsed); }); + active = true; + } + + public void Update(float timeElapsed) + { + if (ignoreFirstUpdate) + { + ignoreFirstUpdate = false; + return; + } + + if (MaxTime != -1) timeElapsed = Math.Min(timeElapsed, MaxTime); + + if (paused > 0) return; + if (!Active) return; + + t += (timeElapsed * timeScale); + + if (t >= d) t = d; + + float val = 0; + + val = thisTween(instant ? 1.0f : t, b, c, instant ? 1.0f : d); + /* + switch(this.tType) + { + case TweenType.EaseLinear : val = SimpleTween.EaseLinear(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseIn : val = SimpleTween.QuadEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseInOut : val = SimpleTween.QuadEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseOut : val = SimpleTween.QuadEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseIn : val = SimpleTween.StrongEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseInOut : val = SimpleTween.StrongEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseOut : val = SimpleTween.StrongEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + } + */ + + int intVal = (int)val; + if (toInt) val = intVal; + + tweenValue = val; + + if (OnUpdate != null) OnUpdate(tweenValue); + + if (t == d) + { + if (Loop) + { + t = 0; + } + else + { + active = false; + efm.Remove(this); + } + if (OnFinish != null) OnFinish(); + + } + + } + + public void ForceUpdateCall() + { + if (active) + { + if (OnUpdate != null) OnUpdate(tweenValue); + } + } + + private static Dictionary typesToFunctions = new Dictionary() + { + { TweenType.EaseLinear, EaseLinear }, + { TweenType.QuadEaseIn, QuadEaseIn }, + { TweenType.QuadEaseInOut, QuadEaseInOut }, + { TweenType.QuadEaseOut, QuadEaseOut }, + { TweenType.StrongEaseIn, StrongEaseIn }, + { TweenType.StrongEaseInOut, StrongEaseInOut }, + { TweenType.StrongEaseOut, StrongEaseOut }, + { TweenType.SineWaveIn, SineWaveIn }, + }; + public static TweenFunction GetTweenFunction(TweenType tweenType) + { + if (typesToFunctions.ContainsKey(tweenType)) return typesToFunctions[tweenType]; + return EaseLinear; + } + + public static float SineWaveIn(float t, float b, float c, float d) + { + float param = (t / d); + float s = (-( (float)Math.Pow(((param-0.774f)*1.4f), 2) )) + 1.1f; + return c * s + b; + } + + public static float EaseLinear(float t, float b, float c, float d) + { + return c * t / d + b; + } + + public static float QuadEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t + b; + } + + public static float QuadEaseOut(float t, float b, float c, float d) + { + return -c * (t /= d) * (t - 2) + b; + } + + public static float QuadEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t + b; + return -c * 0.5f * ((--t) * (t - 2) - 1) + b; + } + + public static float StrongEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t * t * t * t + b; + } + + public static float StrongEaseOut(float t, float b, float c, float d) + { + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; + } + + public static float StrongEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t * t * t * t + b; + return c * 0.5f * ((t -= 2) * t * t * t * t + 2) + b; + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTween.cs.meta b/FallUnity/Assets/Utils/SimpleTween.cs.meta new file mode 100644 index 0000000..07f1d47 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTween.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 7d6b6fbf6da8f2c47a76f1bcc6e2e446 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs b/FallUnity/Assets/Utils/EnterFrameManager.cs new file mode 100644 index 0000000..bb49857 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +public delegate void EnterFrameUpdate(float timeElapsed); + + +public class EnterFrameManager : MonoBehaviour +{ + private Dictionary enterFrameCallbacks = new Dictionary(); + private Dictionary addQueue = new Dictionary(); + private List removeQueue = new List(); + + public Action OnException = null; + + public void Add(object obj, EnterFrameUpdate func) + { + // If the item is marked for removal, cancel the removal. + if (removeQueue.Contains(obj)) + { + removeQueue.Remove(obj); + + // don't add to the queue if this item is already active + if (enterFrameCallbacks.ContainsKey(obj)) return; + } + + // Queue (if we aren't already adding this object...) + if (!addQueue.ContainsKey(obj)) + { + addQueue.Add(obj, func); + } + } + + + public void Remove(object obj) + { + + // If we haven't added this object yet, just remove it from the add queue + if (addQueue.ContainsKey(obj)) + { + addQueue.Remove(obj); + return; + } + + // Queue for removal + if (!removeQueue.Contains(obj)) + { + removeQueue.Add(obj); + } + } + + public int LastItemsUpdated = 0; + public float LastTimeUpdated = 0; + + void Update() + { + float timeElapsed = Time.deltaTime; + + foreach (object obj in removeQueue) + { + if (enterFrameCallbacks.ContainsKey(obj)) + { + enterFrameCallbacks.Remove(obj); + } + } + removeQueue.Clear(); + + foreach (KeyValuePair add in addQueue) + { + if (!enterFrameCallbacks.ContainsKey(add.Key)) + { + enterFrameCallbacks.Add(add.Key, add.Value); + } + } + addQueue.Clear(); + + LastItemsUpdated = 0; + foreach (KeyValuePair entry in enterFrameCallbacks) + { + + if (OnException == null) + { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + else + { + try { + entry.Value(timeElapsed); + LastItemsUpdated++; + } + catch (Exception e) + { + OnException(e); + } + } + + } + + LastTimeUpdated = timeElapsed; + + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/EnterFrameManager.cs.meta b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta new file mode 100644 index 0000000..61b0b64 --- /dev/null +++ b/FallUnity/Assets/Utils/EnterFrameManager.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a5d65a02d369bf745a855fa370a0dd24 +timeCreated: 1572195795 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/ObjectPool.cs b/FallUnity/Assets/Utils/ObjectPool.cs new file mode 100644 index 0000000..5d665c9 --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using UnityEngine; + +namespace UnityGameEngine.Utilities +{ + public class ObjectPoolWithConstructorInternal + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Type objectType; + private ConstructorInfo constructor; + private int numConstructorArgs = 0; + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + + public ObjectPoolWithConstructorInternal(Type objectType, Type[] constructorParams) + { + this.objectType = objectType; + ConstructorInfo constructor = objectType.GetConstructor(constructorParams); + + if (!typeof(T).IsAssignableFrom(objectType)) + { + Debug.LogError("Can't create an ObjectPool<" + typeof(T).Name + "> with a constructor from " + objectType.Name); + } + else if (constructor == null) + { + string err = "Can't construct an ObjectPool<" + objectType.Name + "> with constructor params ("; + err += String.Join(", ", constructorParams.Select(t => t.Name).ToArray()) + "): No such constructor exists!"; + Debug.LogError(err); + } + else + { + this.constructor = constructor; + numConstructorArgs = constructorParams.Length; + } + } + + public ObjectPoolWithConstructorInternal(Type[] constructorParams) : this(typeof(T), constructorParams) { } + + protected bool HasAvailableObject { get { return availableObjects.Count > 0; } } + + protected T GetObjectIfAvailable() + { + InUse++; + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + return obj; + } + return default(T); + } + + protected T GetNewObject(object[] constructorArgs) + { + ObjectsCreated++; + InUse++; + + if (constructorArgs.Length != numConstructorArgs) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: not enough arguments provided!"); + return default(T); + } + + bool valid = true; + object obj = null; + if (constructor == null) return default(T); + try + { + obj = constructor.Invoke(constructorArgs); + if (!(obj is T)) + { + valid = false; + } + } catch (Exception e) + { + valid = false; + } + if (!valid) + { + Debug.LogError("ObjectPool<" + objectType.Name + ">: Incorrect constructor parameters passsed!"); + return default(T); + } + return (T)obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + availableQueue.Enqueue(obj); + availableObjects.Add(obj); + InUse--; + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public abstract class ObjectPoolBase + { + public int ObjectsCreated { get; internal set; } + + public int InUse { get; internal set; } + + public int Available { get { return ObjectsCreated - InUse; } } + + private Queue availableQueue = new Queue(); + private HashSet availableObjects = new HashSet(); + private ConstructorInfo constructor; + + public ObjectPoolBase(Type newType = null) + { + if (newType != null) + { + constructor = newType.GetConstructor(Type.EmptyTypes); + } + } + + protected abstract T CreateNewObject(); + + public T GetNextObject() + { + InUse++; + + T obj = default(T); + if (availableObjects.Count > 0) + { + obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + } + else + { + ObjectsCreated++; + + obj = CreateNewObject(); + } + + return obj; + } + + public void ReturnObject(T obj) + { + if (!availableObjects.Contains(obj)) + { + InUse--; + availableObjects.Add(obj); + availableQueue.Enqueue(obj); + } + } + + public void ReturnObject(object obj) + { + if (obj is T) + { + if (!availableObjects.Contains((T)obj)) + { + InUse--; + availableObjects.Add((T)obj); + availableQueue.Enqueue((T)obj); + } + } + } + + public int AvailableObjectsRemoved { get; private set; } + public T RemoveAvailable() + { + if (availableObjects.Count > 0) + { + T obj = availableQueue.Dequeue(); + while (!availableObjects.Remove(obj)) obj = availableQueue.Dequeue(); + ObjectsCreated--; + AvailableObjectsRemoved++; + return obj; + } + return default(T); + } + public void RemoveAvailable(T obj) + { + if (availableObjects.Contains(obj)) + { + availableObjects.Remove(obj); + ObjectsCreated--; + AvailableObjectsRemoved++; + } + } + } + + public class ObjectPool : ObjectPoolBase where T : new() + { + protected override T CreateNewObject() + { + return new T(); + } + } + + public class ObjectPoolBaseType : ObjectPoolBase + { + private ConstructorInfo constructor; + public ObjectPoolBaseType(Type type) + { + constructor = type.GetConstructor(Type.EmptyTypes); + } + + protected override T CreateNewObject() + { + return (T)constructor.Invoke(null); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1) }) { } + + public T GetNextObject(TConstructArg1 arg1) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2 }); + } + } + + public class ObjectPool : ObjectPoolWithConstructorInternal + { + public ObjectPool() : base(new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public ObjectPool(Type objectType) : base(objectType, new Type[] { typeof(TConstructArg1), typeof(TConstructArg2), typeof(TConstructArg3) }) { } + + public T GetNextObject(TConstructArg1 arg1, TConstructArg2 arg2, TConstructArg3 arg3) + { + if (HasAvailableObject) + { + return GetObjectIfAvailable(); + } + return GetNewObject(new object[] { arg1, arg2, arg3 }); + } + } +} diff --git a/FallUnity/Assets/Utils/ObjectPool.cs.meta b/FallUnity/Assets/Utils/ObjectPool.cs.meta new file mode 100644 index 0000000..7a1a5bb --- /dev/null +++ b/FallUnity/Assets/Utils/ObjectPool.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 584d8a380075c2c4fbb4624ef71a566f +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs b/FallUnity/Assets/Utils/SimpleTimer.cs new file mode 100644 index 0000000..e24678b --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs @@ -0,0 +1,138 @@ +using System; +using UnityEngine; + +public delegate void SimpleTimerTick(); + +public class SimpleTimer +{ + bool hasTime = false; + float t; + private int tSeconds; + public float TimeLeft { get { return t; } } + public bool Active = false; + public SimpleTimerTick OnFinish = null; + + public Action OnSecondsChanged = null; + + + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public bool IgnoreFirstUpdate = true; + + private float duration; + protected bool loop = false; + + private EnterFrameManager efm; + public SimpleTimer() + { + efm = GameObject.FindObjectOfType(); + } + + public SimpleTimer(float time, SimpleTimerTick callback, bool loop = false) + { + Start(time, callback, loop); + } + + public void Start(float time, SimpleTimerTick callback, bool loop = false) + { + hasTime = true; + this.loop = loop; + OnFinish = callback; + this.duration = time; + this.t = time; + SetTSeconds(); + efm.Add(this, delegate (float t) { Update(t); }); + Active = true; + IgnoreFirstUpdate = true; + } + + private void SetTSeconds() + { + int oldTSeconds = tSeconds; + this.tSeconds = Math.Max(0, (int)Math.Ceiling(t)); + if (oldTSeconds != tSeconds && this.OnSecondsChanged != null) + { + OnSecondsChanged(tSeconds); + } + } + + public void Stop() + { + if (!Active) return; + efm.Remove(this); + Active = false; + OnFinish = null; + } + + private int pauseCount = 0; + public bool Paused { get { return pauseCount > 0; } } + + public void Pause() + { + if (!Active) return; + pauseCount++; + if (pauseCount == 1) + { + efm.Remove(this); + } + } + + public void Resume() + { + if (pauseCount == 0 || !hasTime) return; + pauseCount--; + if (pauseCount == 0) + { + efm.Add(this, delegate (float t) { Update(t); }); + } + } + + public void SetTime(float t) + { + this.t = t; + SetTSeconds(); + } + + public void AddTime(float a) + { + this.t += a; + SetTSeconds(); + } + + public void Update(float timeElapsed) + { + if (IgnoreFirstUpdate) + { + IgnoreFirstUpdate = false; + return; + } + + if (!Active) return; + if (Paused) return; + + t -= (timeElapsed * timeScale); + SetTSeconds(); + + if (t <= 0) + { + float actualTime = duration - t; + if (loop) + { + t += duration; + SetTSeconds(); + } + else + { + t = 0; + SetTSeconds(); + + Active = false; + efm.Remove(this); + } + + if (OnFinish != null) OnFinish(); + } + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTimer.cs.meta b/FallUnity/Assets/Utils/SimpleTimer.cs.meta new file mode 100644 index 0000000..b2a1537 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTimer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 10e69767606338742ac79d0548ef27b5 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/Utils/SimpleTween.cs b/FallUnity/Assets/Utils/SimpleTween.cs new file mode 100644 index 0000000..82b4657 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTween.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public delegate void SimpleTweenUpdate(float cVal); +public delegate void SimpleTweenFinish(); + +public class SimpleTween +{ + public delegate float TweenFunction(float t, float b, float c, float d); + + protected TweenFunction thisTween; + + float t; //current time + float c; //delta + float b; //start value + float d; //duration + + public float tweenValue; + bool toInt = false; + + bool instant = false; + + public float MaxTime = -1; + + protected int InstanceID; + protected static int NextID = 0; + + private bool active = false; + public bool Active { get { return active; } } + + public SimpleTweenFinish OnFinish = null; + public SimpleTweenUpdate OnUpdate = null; + public bool Loop = false; + + private bool ignoreFirstUpdate = true; + float timeScale = 1; + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + + public enum TweenType { EaseLinear, QuadEaseIn, QuadEaseOut, QuadEaseInOut, StrongEaseIn, StrongEaseOut, StrongEaseInOut, SineWaveIn }; + + + protected int paused = 0; + public void Pause() + { + paused++; + } + public void Resume() + { + if (paused > 0) + { + paused--; + } + } + public bool Paused { get { return paused > 0; } } + + private EnterFrameManager efm; + public SimpleTween() + { + efm = GameObject.FindObjectOfType(); + InstanceID = NextID++; + active = false; + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenType tType, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + TweenFunction func = GetTweenFunction(tType); + Init(onUpdate, func, start, end, time, toInt); + } + + public SimpleTween(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + InstanceID = NextID++; + Init(onUpdate, tweenFunc, start, end, time, toInt); + } + + public void Stop() + { + active = false; + OnFinish = null; + OnUpdate = null; + efm.Remove(this); + } + + public void Init(SimpleTweenUpdate onUpdate, TweenFunction tweenFunc, float start, float end, float time, bool toInt = false) + { + if (Active) Stop(); + this.OnUpdate = onUpdate; + this.toInt = toInt; + + tweenValue = start; + + this.thisTween = tweenFunc; + + + t = 0; + c = end - start; + b = start; + d = time; + + instant = (d == 0); + efm.Add(this, delegate (float timeElapsed) { Update(timeElapsed); }); + active = true; + } + + public void Update(float timeElapsed) + { + if (ignoreFirstUpdate) + { + ignoreFirstUpdate = false; + return; + } + + if (MaxTime != -1) timeElapsed = Math.Min(timeElapsed, MaxTime); + + if (paused > 0) return; + if (!Active) return; + + t += (timeElapsed * timeScale); + + if (t >= d) t = d; + + float val = 0; + + val = thisTween(instant ? 1.0f : t, b, c, instant ? 1.0f : d); + /* + switch(this.tType) + { + case TweenType.EaseLinear : val = SimpleTween.EaseLinear(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseIn : val = SimpleTween.QuadEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseInOut : val = SimpleTween.QuadEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.QuadEaseOut : val = SimpleTween.QuadEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseIn : val = SimpleTween.StrongEaseIn(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseInOut : val = SimpleTween.StrongEaseInOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + case TweenType.StrongEaseOut : val = SimpleTween.StrongEaseOut(instant ? 1.0f : t, b, c, instant ? 1.0f : d); break; + } + */ + + int intVal = (int)val; + if (toInt) val = intVal; + + tweenValue = val; + + if (OnUpdate != null) OnUpdate(tweenValue); + + if (t == d) + { + if (Loop) + { + t = 0; + } + else + { + active = false; + efm.Remove(this); + } + if (OnFinish != null) OnFinish(); + + } + + } + + public void ForceUpdateCall() + { + if (active) + { + if (OnUpdate != null) OnUpdate(tweenValue); + } + } + + private static Dictionary typesToFunctions = new Dictionary() + { + { TweenType.EaseLinear, EaseLinear }, + { TweenType.QuadEaseIn, QuadEaseIn }, + { TweenType.QuadEaseInOut, QuadEaseInOut }, + { TweenType.QuadEaseOut, QuadEaseOut }, + { TweenType.StrongEaseIn, StrongEaseIn }, + { TweenType.StrongEaseInOut, StrongEaseInOut }, + { TweenType.StrongEaseOut, StrongEaseOut }, + { TweenType.SineWaveIn, SineWaveIn }, + }; + public static TweenFunction GetTweenFunction(TweenType tweenType) + { + if (typesToFunctions.ContainsKey(tweenType)) return typesToFunctions[tweenType]; + return EaseLinear; + } + + public static float SineWaveIn(float t, float b, float c, float d) + { + float param = (t / d); + float s = (-( (float)Math.Pow(((param-0.774f)*1.4f), 2) )) + 1.1f; + return c * s + b; + } + + public static float EaseLinear(float t, float b, float c, float d) + { + return c * t / d + b; + } + + public static float QuadEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t + b; + } + + public static float QuadEaseOut(float t, float b, float c, float d) + { + return -c * (t /= d) * (t - 2) + b; + } + + public static float QuadEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t + b; + return -c * 0.5f * ((--t) * (t - 2) - 1) + b; + } + + public static float StrongEaseIn(float t, float b, float c, float d) + { + return c * (t /= d) * t * t * t * t + b; + } + + public static float StrongEaseOut(float t, float b, float c, float d) + { + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; + } + + public static float StrongEaseInOut(float t, float b, float c, float d) + { + if ((t /= d * 0.5f) < 1) return c * 0.5f * t * t * t * t * t + b; + return c * 0.5f * ((t -= 2) * t * t * t * t + 2) + b; + } + +} \ No newline at end of file diff --git a/FallUnity/Assets/Utils/SimpleTween.cs.meta b/FallUnity/Assets/Utils/SimpleTween.cs.meta new file mode 100644 index 0000000..07f1d47 --- /dev/null +++ b/FallUnity/Assets/Utils/SimpleTween.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 7d6b6fbf6da8f2c47a76f1bcc6e2e446 +timeCreated: 1572195732 +licenseType: Free +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/FallUnity/Assets/level.unity b/FallUnity/Assets/level.unity index 803d461..ebcd424 100755 --- a/FallUnity/Assets/level.unity +++ b/FallUnity/Assets/level.unity @@ -1026,6 +1026,48 @@ m_Father: {fileID: 1832090302} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1394804103 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1394804105} + - component: {fileID: 1394804104} + m_Layer: 0 + m_Name: EFM + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1394804104 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1394804103} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5d65a02d369bf745a855fa370a0dd24, type: 3} + m_Name: + m_EditorClassIdentifier: + LastItemsUpdated: 0 + LastTimeUpdated: 0 +--- !u!4 &1394804105 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1394804103} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -3.3688889, y: 3.63, z: -1.544} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1464748116 GameObject: m_ObjectHideFlags: 0