提交Unity 联机Pro

This commit is contained in:
PC-20230316NUNE\Administrator
2024-08-17 14:27:18 +08:00
parent f00193b000
commit 894100ae37
7448 changed files with 854473 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 713ffa030c417a84190555e6aef2e0b2
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,346 @@
namespace SRF
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
/// <summary>
/// IList implementation which does not release the buffer when clearing/removing elements. Based on the NGUI BetterList
/// </summary>
[Serializable]
public class SRList<T> : IList<T>, ISerializationCallbackReceiver
{
[SerializeField] private T[] _buffer;
[SerializeField] private int _count;
private EqualityComparer<T> _equalityComparer;
private ReadOnlyCollection<T> _readOnlyWrapper;
public SRList() {}
public SRList(int capacity)
{
Buffer = new T[capacity];
}
/// <summary>
/// Create a new list with the range of values. Contains a foreach loop, which will allocate garbage when used with most
/// generic collection types.
/// </summary>
public SRList(IEnumerable<T> source)
{
AddRange(source);
}
public T[] Buffer
{
get { return _buffer; }
private set { _buffer = value; }
}
private EqualityComparer<T> EqualityComparer
{
get
{
if (_equalityComparer == null)
{
_equalityComparer = EqualityComparer<T>.Default;
}
return _equalityComparer;
}
}
public int Count
{
get { return _count; }
private set { _count = value; }
}
public IEnumerator<T> GetEnumerator()
{
if (Buffer != null)
{
for (var i = 0; i < Count; ++i)
{
yield return Buffer[i];
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T item)
{
if (Buffer == null || Count == Buffer.Length)
{
Expand();
}
Buffer[Count++] = item;
}
public void Clear()
{
Count = 0;
}
public bool Contains(T item)
{
if (Buffer == null)
{
return false;
}
for (var i = 0; i < Count; ++i)
{
if (EqualityComparer.Equals(Buffer[i], item))
{
return true;
}
}
return false;
}
public void CopyTo(T[] array, int arrayIndex)
{
Trim();
Buffer.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
if (Buffer == null)
{
return false;
}
var index = IndexOf(item);
if (index < 0)
{
return false;
}
RemoveAt(index);
return true;
}
public bool IsReadOnly
{
get { return false; }
}
public int IndexOf(T item)
{
if (Buffer == null)
{
return -1;
}
for (var i = 0; i < Count; ++i)
{
if (EqualityComparer.Equals(Buffer[i], item))
{
return i;
}
}
return -1;
}
public void Insert(int index, T item)
{
if (Buffer == null || Count == Buffer.Length)
{
Expand();
}
if (index < Count)
{
for (var i = Count; i > index; --i)
{
Buffer[i] = Buffer[i - 1];
}
Buffer[index] = item;
++Count;
}
else
{
Add(item);
}
}
public void RemoveAt(int index)
{
if (Buffer != null && index < Count)
{
--Count;
Buffer[index] = default(T);
for (var b = index; b < Count; ++b)
{
Buffer[b] = Buffer[b + 1];
}
}
}
public T this[int index]
{
get
{
if (Buffer == null)
{
throw new IndexOutOfRangeException();
}
return Buffer[index];
}
set
{
if (Buffer == null)
{
throw new IndexOutOfRangeException();
}
Buffer[index] = value;
}
}
public void OnBeforeSerialize()
{
// Clean buffer of unused elements before serializing
Clean();
}
public void OnAfterDeserialize()
{
}
/// <summary>
/// Add range of values to the list. Contains a foreach loop, which will allocate garbage when used with most
/// generic collection types.
/// </summary>
/// <param name="range"></param>
public void AddRange(IEnumerable<T> range)
{
foreach (var item in range)
{
Add(item);
}
}
/// <summary>
/// Clear the list, optionally setting each element to default(T)
/// </summary>
public void Clear(bool clean)
{
Clear();
if (!clean)
{
return;
}
Clean();
}
public void Clean()
{
if (Buffer == null)
{
return;
}
for (var i = Count; i < _buffer.Length; i++)
{
_buffer[i] = default(T);
}
}
/// <summary>
/// Get a read-only wrapper of this list. This is cached, so very little cost after first called.
/// </summary>
/// <returns></returns>
public ReadOnlyCollection<T> AsReadOnly()
{
if (_readOnlyWrapper == null)
{
_readOnlyWrapper = new ReadOnlyCollection<T>(this);
}
return _readOnlyWrapper;
}
/// <summary>
/// Helper function that expands the size of the array, maintaining the content.
/// </summary>
private void Expand()
{
var newList = (Buffer != null) ? new T[Mathf.Max(Buffer.Length << 1, 32)] : new T[32];
if (Buffer != null && Count > 0)
{
Buffer.CopyTo(newList, 0);
}
Buffer = newList;
}
/// <summary>
/// Trim the unnecessary memory, resizing the buffer to be of 'Length' size.
/// Call this function only if you are sure that the buffer won't need to resize anytime soon.
/// </summary>
public void Trim()
{
if (Count > 0)
{
if (Count >= Buffer.Length)
{
return;
}
var newList = new T[Count];
for (var i = 0; i < Count; ++i)
{
newList[i] = Buffer[i];
}
Buffer = newList;
}
else
{
Buffer = new T[0];
}
}
/// <summary>
/// List.Sort equivalent.
/// </summary>
public void Sort(Comparison<T> comparer)
{
var changed = true;
while (changed)
{
changed = false;
for (var i = 1; i < Count; ++i)
{
if (comparer.Invoke(Buffer[i - 1], Buffer[i]) > 0)
{
var temp = Buffer[i];
Buffer[i] = Buffer[i - 1];
Buffer[i - 1] = temp;
changed = true;
}
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5201015973137a64986d1c3a21aa95bd
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: b492ab4aeb29c06468a92411414d3647
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,74 @@
namespace SRF.Components
{
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
/// <summary>
/// Singleton MonoBehaviour class which automatically creates an instance if one does not already exist.
/// </summary>
public abstract class SRAutoSingleton<T> : SRMonoBehaviour where T : SRAutoSingleton<T>
{
private static T _instance;
/// <summary>
/// Get (or create) the instance of this Singleton
/// </summary>
public static T Instance
{
[DebuggerStepThrough]
get
{
// Instance required for the first time, we look for it
if (_instance == null && Application.isPlaying)
{
#if UNITY_EDITOR
// Support reloading scripts after a recompile - static reference will be cleared, but we can find it again.
T autoSingleton = FindObjectOfType<T>();
if (autoSingleton != null)
{
_instance = autoSingleton;
return _instance;
}
#endif
var go = new GameObject("_" + typeof (T).Name);
go.AddComponent<T>(); // _instance set by Awake() constructor
}
return _instance;
}
}
public static bool HasInstance
{
get { return _instance != null; }
}
// If no other monobehaviour request the instance in an awake function
// executing before this one, no need to search the object.
protected virtual void Awake()
{
if (_instance != null)
{
Debug.LogWarning("More than one singleton object of type {0} exists.".Fmt(typeof (T).Name));
return;
}
_instance = (T) this;
}
protected virtual void OnEnable()
{
#if UNITY_EDITOR
// Restore reference after C# recompile.
_instance = (T) this;
#endif
}
// Make sure the instance isn't referenced anymore when the user quit, just in case.
private void OnApplicationQuit()
{
_instance = null;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 73f72db4fa1856540bbe92740280c8e2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,202 @@
namespace SRF
{
using System.Diagnostics;
using UnityEngine;
/// <summary>
/// Base MonoBehaviour which provides useful common functionality
/// </summary>
public abstract class SRMonoBehaviour : MonoBehaviour
{
/// <summary>
/// Get the Transform component, using a cached reference if possible.
/// </summary>
public Transform CachedTransform
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_transform == null)
{
_transform = base.transform;
}
return _transform;
}
}
/// <summary>
/// Get the Collider component, using a cached reference if possible.
/// </summary>
public Collider CachedCollider
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_collider == null)
{
_collider = GetComponent<Collider>();
}
return _collider;
}
}
/// <summary>
/// Get the Collider component, using a cached reference if possible.
/// </summary>
public Collider2D CachedCollider2D
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_collider2D == null)
{
_collider2D = GetComponent<Collider2D>();
}
return _collider2D;
}
}
/// <summary>
/// Get the Rigidbody component, using a cached reference if possible.
/// </summary>
public Rigidbody CachedRigidBody
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_rigidBody == null)
{
_rigidBody = GetComponent<Rigidbody>();
}
return _rigidBody;
}
}
/// <summary>
/// Get the Rigidbody2D component, using a cached reference if possible.
/// </summary>
public Rigidbody2D CachedRigidBody2D
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_rigidbody2D == null)
{
_rigidbody2D = GetComponent<Rigidbody2D>();
}
return _rigidbody2D;
}
}
/// <summary>
/// Get the GameObject this behaviour is attached to, using a cached reference if possible.
/// </summary>
public GameObject CachedGameObject
{
[DebuggerStepThrough]
[DebuggerNonUserCode]
get
{
if (_gameObject == null)
{
_gameObject = base.gameObject;
}
return _gameObject;
}
}
// Override existing getters for legacy usage
// ReSharper disable InconsistentNaming
public new Transform transform
{
get { return CachedTransform; }
}
#if !UNITY_5 && !UNITY_2017_1_OR_NEWER
public new Collider collider
{
get { return CachedCollider; }
}
public new Collider2D collider2D
{
get { return CachedCollider2D; }
}
public new Rigidbody rigidbody
{
get { return CachedRigidBody; }
}
public new Rigidbody2D rigidbody2D
{
get { return CachedRigidBody2D; }
}
public new GameObject gameObject
{
get { return CachedGameObject; }
}
#endif
// ReSharper restore InconsistentNaming
private Collider _collider;
private Transform _transform;
private Rigidbody _rigidBody;
private GameObject _gameObject;
private Rigidbody2D _rigidbody2D;
private Collider2D _collider2D;
/// <summary>
/// Assert that the value is not null, disable the object and print a debug error message if it is.
/// </summary>
/// <param name="value">Object to check</param>
/// <param name="fieldName">Debug name to pass in</param>
[DebuggerNonUserCode]
[DebuggerStepThrough]
protected void AssertNotNull(object value, string fieldName = null)
{
SRDebugUtil.AssertNotNull(value, fieldName, this);
}
[DebuggerNonUserCode]
[DebuggerStepThrough]
protected void Assert(bool condition, string message = null)
{
SRDebugUtil.Assert(condition, message, this);
}
/// <summary>
/// Assert that the value is not null, disable the object and print a debug error message if it is.
/// </summary>
/// <param name="value">Object to check</param>
/// <param name="fieldName">Debug name to pass in</param>
/// <returns>True if object is not null</returns>
[Conditional("UNITY_EDITOR")]
[DebuggerNonUserCode]
[DebuggerStepThrough]
protected void EditorAssertNotNull(object value, string fieldName = null)
{
AssertNotNull(value, fieldName);
}
[Conditional("UNITY_EDITOR")]
[DebuggerNonUserCode]
[DebuggerStepThrough]
protected void EditorAssert(bool condition, string message = null)
{
Assert(condition, message);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a97a8611d5d683b4aa89a5054bc3774e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,215 @@
// ReSharper disable once RedundantUsingDirective
using System.Linq;
namespace SRF
{
using System;
using System.Collections.Generic;
using System.Reflection;
using Helpers;
using Service;
using UnityEngine;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field)]
public sealed class RequiredFieldAttribute : Attribute
{
private bool _autoCreate;
private bool _autoSearch;
private bool _editorOnly = true;
public RequiredFieldAttribute(bool autoSearch)
{
AutoSearch = autoSearch;
}
public RequiredFieldAttribute() {}
public bool AutoSearch
{
get { return _autoSearch; }
set { _autoSearch = value; }
}
public bool AutoCreate
{
get { return _autoCreate; }
set { _autoCreate = value; }
}
[Obsolete]
public bool EditorOnly
{
get { return _editorOnly; }
set { _editorOnly = value; }
}
}
/// <summary>
/// Add to a field to attempt to use SRServiceManager to get an instance of the field type
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class ImportAttribute : Attribute
{
public readonly Type Service;
public ImportAttribute() {}
public ImportAttribute(Type serviceType)
{
Service = serviceType;
}
}
public abstract class SRMonoBehaviourEx : SRMonoBehaviour
{
private static Dictionary<Type, IList<FieldInfo>> _checkedFields;
private static void CheckFields(SRMonoBehaviourEx instance, bool justSet = false)
{
if (_checkedFields == null)
{
_checkedFields = new Dictionary<Type, IList<FieldInfo>>();
}
var t = instance.GetType();
IList<FieldInfo> cache;
if (!_checkedFields.TryGetValue(instance.GetType(), out cache))
{
cache = ScanType(t);
_checkedFields.Add(t, cache);
}
PopulateObject(cache, instance, justSet);
}
private static void PopulateObject(IList<FieldInfo> cache, SRMonoBehaviourEx instance, bool justSet)
{
for (var i = 0; i < cache.Count; i++)
{
var f = cache[i];
if (!EqualityComparer<object>.Default.Equals(f.Field.GetValue(instance), null))
{
continue;
}
// If import is enabled, use SRServiceManager to import the reference
if (f.Import)
{
var t = f.ImportType ?? f.Field.FieldType;
var service = SRServiceManager.GetService(t);
if (service == null)
{
Debug.LogWarning("Field {0} import failed (Type {1})".Fmt(f.Field.Name, t));
continue;
}
f.Field.SetValue(instance, service);
continue;
}
// If autoset is enabled on field, try and find the component on the GameObject
if (f.AutoSet)
{
var newValue = instance.GetComponent(f.Field.FieldType);
if (!EqualityComparer<object>.Default.Equals(newValue, null))
{
f.Field.SetValue(instance, newValue);
continue;
}
}
if (justSet)
{
continue;
}
if (f.AutoCreate)
{
var newValue = instance.CachedGameObject.AddComponent(f.Field.FieldType);
f.Field.SetValue(instance, newValue);
}
throw new UnassignedReferenceException(
"Field {0} is unassigned, but marked with RequiredFieldAttribute".Fmt(f.Field.Name));
}
}
private static List<FieldInfo> ScanType(Type t)
{
var cache = new List<FieldInfo>();
// Check for attribute added to the class
var globalAttr = SRReflection.GetAttribute<RequiredFieldAttribute>(t);
#if NETFX_CORE
var fields = t.GetTypeInfo().DeclaredFields.Where(f => !f.IsStatic);
#else
// Check each field for the attribute
var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
#endif
foreach (var f in fields)
{
var requiredFieldAttribute = SRReflection.GetAttribute<RequiredFieldAttribute>(f);
var importAttribute = SRReflection.GetAttribute<ImportAttribute>(f);
if (globalAttr == null && requiredFieldAttribute == null && importAttribute == null)
{
continue; // Early out if no attributes found.
}
var info = new FieldInfo();
info.Field = f;
if (importAttribute != null)
{
info.Import = true;
info.ImportType = importAttribute.Service;
}
else if (requiredFieldAttribute != null)
{
info.AutoSet = requiredFieldAttribute.AutoSearch;
info.AutoCreate = requiredFieldAttribute.AutoCreate;
}
else
{
info.AutoSet = globalAttr.AutoSearch;
info.AutoCreate = globalAttr.AutoCreate;
}
cache.Add(info);
}
return cache;
}
protected virtual void Awake()
{
CheckFields(this);
}
protected virtual void Start() {}
protected virtual void Update() {}
protected virtual void FixedUpdate() {}
protected virtual void OnEnable() {}
protected virtual void OnDisable() {}
protected virtual void OnDestroy() {}
private struct FieldInfo
{
public bool AutoCreate;
public bool AutoSet;
public System.Reflection.FieldInfo Field;
public bool Import;
public Type ImportType;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 82088ea802108344da1e919daa6881fd
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,82 @@
namespace SRF.Components
{
using System;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
/// <summary>
/// Inherit from this component to easily create a singleton gameobject.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class SRSingleton<T> : SRMonoBehaviour where T : SRSingleton<T>
{
private static T _instance;
/// <summary>
/// Get the instance of this singleton.
/// </summary
public static T Instance
{
[DebuggerStepThrough]
get
{
// Instance requiered for the first time, we look for it
if (_instance == null)
{
throw new InvalidOperationException("No instance of {0} present in scene".Fmt(typeof (T).Name));
}
return _instance;
}
}
public static bool HasInstance
{
[DebuggerStepThrough] get { return _instance != null; }
}
private void Register()
{
if (_instance != null)
{
Debug.LogWarning("More than one singleton object of type {0} exists.".Fmt(typeof (T).Name));
// Check if gameobject only contains Transform and this component
if (GetComponents<Component>().Length == 2)
{
Destroy(gameObject);
}
else
{
Destroy(this);
}
return;
}
_instance = (T) this;
}
// If no other monobehaviour request the instance in an awake function
// executing before this one, no need to search the object.
protected virtual void Awake()
{
Register();
}
protected virtual void OnEnable()
{
// In case of code-reload, this should restore the single instance
if (_instance == null)
{
Register();
}
}
// Make sure the instance isn't referenced anymore when the user quit, just in case.
private void OnApplicationQuit()
{
_instance = null;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ca9e6e61f807f3442b520b02db3a48c7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,18 @@
namespace SRF
{
using System.Collections;
using UnityEngine;
public static class Coroutines
{
public static IEnumerator WaitForSecondsRealTime(float time)
{
var endTime = Time.realtimeSinceStartup + time;
while (Time.realtimeSinceStartup < endTime)
{
yield return null;
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 83ca528cafb0d2e40866729c49dc2d76
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 5a242390cef216543a4fa08843e88004
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,27 @@
namespace SRF
{
using UnityEngine;
public static class SRFFloatExtensions
{
public static float Sqr(this float f)
{
return f*f;
}
public static float SqrRt(this float f)
{
return Mathf.Sqrt(f);
}
public static bool ApproxZero(this float f)
{
return Mathf.Approximately(0, f);
}
public static bool Approx(this float f, float f2)
{
return Mathf.Approximately(f, f2);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bb221a6020786a841a6f7f1ea19a7eb7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,100 @@
namespace SRF
{
using UnityEngine;
public static class SRFGameObjectExtensions
{
public static T GetIComponent<T>(this GameObject t) where T : class
{
return t.GetComponent(typeof (T)) as T;
}
/// <summary>
/// Get the component T, or add it to the GameObject if none exists
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetComponentOrAdd<T>(this GameObject obj) where T : Component
{
var t = obj.GetComponent<T>();
if (t == null)
{
t = obj.AddComponent<T>();
}
return t;
}
/// <summary>
/// Removed component of type T if it exists on the GameObject
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
public static void RemoveComponentIfExists<T>(this GameObject obj) where T : Component
{
var t = obj.GetComponent<T>();
if (t != null)
{
Object.Destroy(t);
}
}
/// <summary>
/// Removed components of type T if it exists on the GameObject
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
public static void RemoveComponentsIfExists<T>(this GameObject obj) where T : Component
{
var t = obj.GetComponents<T>();
for (var i = 0; i < t.Length; i++)
{
Object.Destroy(t[i]);
}
}
/// <summary>
/// Set enabled property MonoBehaviour of type T if it exists
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <param name="enable"></param>
/// <returns>True if the component exists</returns>
public static bool EnableComponentIfExists<T>(this GameObject obj, bool enable = true) where T : MonoBehaviour
{
var t = obj.GetComponent<T>();
if (t == null)
{
return false;
}
t.enabled = enable;
return true;
}
/// <summary>
/// Set the layer of a gameobject and all child objects
/// </summary>
/// <param name="o"></param>
/// <param name="layer"></param>
public static void SetLayerRecursive(this GameObject o, int layer)
{
SetLayerInternal(o.transform, layer);
}
private static void SetLayerInternal(Transform t, int layer)
{
t.gameObject.layer = layer;
foreach (Transform o in t)
{
SetLayerInternal(o, layer);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 57a08f4d800e4384fac80b0ecf63a7a0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,47 @@
namespace SRF
{
using System;
using System.Collections.Generic;
public static class SRFIListExtensions
{
public static T Random<T>(this IList<T> list)
{
if (list.Count == 0)
{
throw new IndexOutOfRangeException("List needs at least one entry to call Random()");
}
if (list.Count == 1)
{
return list[0];
}
return list[UnityEngine.Random.Range(0, list.Count)];
}
public static T RandomOrDefault<T>(this IList<T> list)
{
if (list.Count == 0)
{
return default(T);
}
return list.Random();
}
public static T PopLast<T>(this IList<T> list)
{
if (list.Count == 0)
{
throw new InvalidOperationException();
}
var t = list[list.Count - 1];
list.RemoveAt(list.Count - 1);
return t;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c196b9d1bba9e9e44939cf8776545577
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,32 @@

#if NETFX_CORE
using System;
using System.Reflection;
namespace SRF
{
public static class NetFxExtensions
{
public static bool IsAssignableFrom(this Type @this, Type t)
{
return @this.GetTypeInfo().IsAssignableFrom(t.GetTypeInfo());
}
public static bool IsInstanceOfType(this Type @this, object obj)
{
return @this.IsAssignableFrom(obj.GetType());
}
}
}
#endif

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f503b1a2564101f4f96417c97debaaf5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,13 @@
namespace SRF
{
public static class SRFStringExtensions
{
#if UNITY_EDITOR
[JetBrains.Annotations.StringFormatMethod("formatString")]
#endif
public static string Fmt(this string formatString, params object[] args)
{
return string.Format(formatString, args);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 71e45638ff7335744a6554752b778f39
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,91 @@
namespace SRF
{
using System.Collections.Generic;
using UnityEngine;
public static class SRFTransformExtensions
{
public static IEnumerable<Transform> GetChildren(this Transform t)
{
var i = 0;
while (i < t.childCount)
{
yield return t.GetChild(i);
++i;
}
}
/// <summary>
/// Reset all local values on a transform to identity
/// </summary>
/// <param name="t"></param>
public static void ResetLocal(this Transform t)
{
t.localPosition = Vector3.zero;
t.localRotation = Quaternion.identity;
t.localScale = Vector3.one;
}
/// <summary>
/// Create an empty child object of this transform
/// </summary>
/// <param name="t"></param>
/// <param name="name"></param>
/// <returns></returns>
public static GameObject CreateChild(this Transform t, string name)
{
var go = new GameObject(name);
go.transform.parent = t;
go.transform.ResetLocal();
go.gameObject.layer = t.gameObject.layer;
return go;
}
/// <summary>
/// Set the parent of this transform, but maintain the localScale, localPosition, localRotation values.
/// </summary>
/// <param name="t"></param>
/// <param name="parent"></param>
public static void SetParentMaintainLocals(this Transform t, Transform parent)
{
t.SetParent(parent, false);
}
/// <summary>
/// Copy local position,rotation,scale from other transform
/// </summary>
/// <param name="t"></param>
/// <param name="from"></param>
public static void SetLocals(this Transform t, Transform from)
{
t.localPosition = from.localPosition;
t.localRotation = from.localRotation;
t.localScale = from.localScale;
}
/// <summary>
/// Set position/rotation to from. Scale is unchanged
/// </summary>
/// <param name="t"></param>
/// <param name="from"></param>
public static void Match(this Transform t, Transform from)
{
t.position = from.position;
t.rotation = from.rotation;
}
/// <summary>
/// Destroy all child game objects
/// </summary>
/// <param name="t"></param>
public static void DestroyChildren(this Transform t)
{
foreach (var child in t)
{
Object.Destroy(((Transform) child).gameObject);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 891f8206d8bca304fbbf298c6a37648e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 5354a62e7d1e47949b07ff9e9b123080
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,63 @@
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace SRF.Helpers
{
using System.IO;
using UnityEngine;
public static class AssetUtil
{
#if UNITY_EDITOR
// This makes it easy to create, name and place unique new ScriptableObject asset files.
/// <summary>
/// </summary>
public static T CreateAsset<T>() where T : ScriptableObject
{
var path = AssetDatabase.GetAssetPath(Selection.activeObject);
if (path == "")
{
path = "Assets";
}
else if (Path.GetExtension(path) != "")
{
path = path.Replace(Path.GetFileName(path), "");
}
return CreateAsset<T>(path, "New " + typeof (T).Name);
}
public static T CreateAsset<T>(string path, string name) where T : ScriptableObject
{
if (string.IsNullOrEmpty(path))
{
path = "Assets";
}
if (!name.EndsWith(".asset"))
{
name += ".asset";
}
var assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + name);
var asset = ScriptableObject.CreateInstance<T>();
AssetDatabase.CreateAsset(asset, assetPathAndName);
AssetDatabase.SaveAssets();
return asset;
}
public static void SelectAssetInProjectView(Object asset)
{
EditorUtility.FocusProjectWindow();
Selection.activeObject = asset;
}
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: de28cc9633260c54a9ba062b7ad82e63
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,73 @@
namespace SRF
{
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Hierarchy
{
private static readonly char[] Seperator = {'/'};
private static readonly Dictionary<string, Transform> Cache = new Dictionary<string, Transform>();
[Obsolete("Use static Get() instead")]
public Transform this[string key]
{
get { return Get(key); }
}
/// <summary>
/// Pass in a path (e.g. /Test/Me/One) and get a transform with the hierarchy Test->Me->One.
/// Any Transforms required below this path will be auto-created.
/// This is a very slow method, so use only on initialisation.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static Transform Get(string key)
{
Transform t;
// Check cache
if (Cache.TryGetValue(key, out t))
{
return t;
}
var find = GameObject.Find(key);
if (find)
{
t = find.transform;
Cache.Add(key, t);
return t;
}
// Find container parent
var elements = key.Split(Seperator, StringSplitOptions.RemoveEmptyEntries);
// Create new container
t = new GameObject(elements.Last()).transform;
Cache.Add(key, t);
// If root
if (elements.Length == 1)
{
return t;
}
t.parent = Get(string.Join("/", elements, 0, elements.Length - 1));
return t;
}
#if (!UNITY_2017 && !UNITY_2018 && !UNITY_2019) || UNITY_2019_3_OR_NEWER
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
public static void RuntimeInitialize()
{
// To handle entering play mode without a domain reload, need to reset the state of the service manager.
Cache.Clear();
}
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ecf392c4c08d14543b90300c27422d60
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,37 @@
using System;
namespace SRF.Helpers
{
using System.Reflection;
public sealed class MethodReference
{
private readonly Func<object[], object> _method;
public MethodReference(object target, MethodInfo method)
{
SRDebugUtil.AssertNotNull(target);
_method = o => method.Invoke(target, o);
}
public MethodReference(Func<object[], object> method)
{
_method = method;
}
public object Invoke(object[] parameters)
{
return _method.Invoke(parameters);
}
public static implicit operator MethodReference(Action action)
{
return new MethodReference(args =>
{
action();
return null;
});
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3ed7f46979ff4b3418a838a6b940a9ab
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,208 @@
using System.Collections.Generic;
using System.ComponentModel;
using JetBrains.Annotations;
using UnityEngine;
namespace SRF.Helpers
{
using System;
using System.Linq;
using System.Reflection;
public delegate void PropertyValueChangedHandler(PropertyReference property);
public sealed class PropertyReference
{
public event PropertyValueChangedHandler ValueChanged
{
add
{
if (_valueChangedListeners == null)
{
_valueChangedListeners = new List<PropertyValueChangedHandler>();
}
_valueChangedListeners.Add(value);
if (_valueChangedListeners.Count == 1 && _target is INotifyPropertyChanged)
{
// Subscribe to value changed event on target.
((INotifyPropertyChanged)_target).PropertyChanged += OnTargetPropertyChanged;
}
}
remove
{
if (_valueChangedListeners == null)
{
return;
}
if (_valueChangedListeners.Remove(value) && _valueChangedListeners.Count == 0 &&
_target is INotifyPropertyChanged)
{
// Unsubscribe from value changed event on target.
((INotifyPropertyChanged) _target).PropertyChanged -= OnTargetPropertyChanged;
}
}
}
[CanBeNull] private readonly PropertyInfo _property;
[CanBeNull] private readonly object _target;
[CanBeNull] private readonly Attribute[] _attributes;
[CanBeNull] private readonly Func<object> _getter;
[CanBeNull] private readonly Action<object> _setter;
[CanBeNull] private List<PropertyValueChangedHandler> _valueChangedListeners;
public static PropertyReference FromLambda<T>(Func<T> getter, Action<T> setter = null, params Attribute[] attributes)
{
Action<object> internalSetter = null;
if (setter != null)
{
internalSetter = o => setter((T)o);
}
return new PropertyReference(typeof(T), () => getter(), internalSetter, attributes);
}
/// <summary>
/// Create a property reference from an object target and reflection PropertyInfo.
/// This represents a property on an object.
/// </summary>
public PropertyReference(object target, PropertyInfo property)
{
SRDebugUtil.AssertNotNull(target);
SRDebugUtil.AssertNotNull(property);
PropertyType = property.PropertyType;
_property = property;
_target = target;
#if NETFX_CORE
if(_property.GetMethod != null && _property.GetMethod.IsPublic)
#else
if (property.GetGetMethod() != null)
#endif
{
_getter = () => SRReflection.GetPropertyValue(target, property);
}
#if NETFX_CORE
if(_property.SetMethod != null && _property.SetMethod.IsPublic)
#else
if (property.GetSetMethod() != null)
#endif
{
_setter = (v) => SRReflection.SetPropertyValue(target, property, v);
}
}
/// <summary>
/// Create a property reference from lambdas. This has no underlying reflection or object associated with it.
/// </summary>
public PropertyReference(Type type, Func<object> getter = null, Action<object> setter = null, Attribute[] attributes = null)
{
SRDebugUtil.AssertNotNull(type);
PropertyType = type;
_attributes = attributes;
_getter = getter;
_setter = setter;
}
public Type PropertyType { get; private set; }
public bool CanRead
{
get
{
return _getter != null;
}
}
public bool CanWrite
{
get
{
return _setter != null;
}
}
/// <summary>
/// Notify any listeners to <see cref="ValueChanged"/> that the value has been updated.
/// </summary>
public void NotifyValueChanged()
{
if (_valueChangedListeners == null)
{
return;
}
foreach (var handler in _valueChangedListeners)
{
handler(this);
}
}
public object GetValue()
{
if (_getter != null)
{
return _getter();
}
return null;
}
public void SetValue(object value)
{
if (_setter != null)
{
_setter(value);
}
else
{
throw new InvalidOperationException("Can not write to property");
}
}
public T GetAttribute<T>() where T : Attribute
{
if (_attributes != null)
{
return _attributes.FirstOrDefault(p => p is T) as T;
}
if (_property != null)
{
return _property.GetCustomAttributes(typeof(T), true).FirstOrDefault() as T;
}
return null;
}
private void OnTargetPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_valueChangedListeners == null || _valueChangedListeners.Count == 0)
{
Debug.LogWarning("[PropertyReference] Received property value changed event when there are no listeners. Did the event not get unsubscribed correctly?");
return;
}
NotifyValueChanged();
}
public override string ToString()
{
if (_property != null)
{
return "{0}.{1}".Fmt(_property.DeclaringType.Name, _property.Name);
}
return "<delegate>";
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dedbd84f93f7d4c4e86f2d3a238916c4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using SRF;
using UnityEngine;
using Debug = UnityEngine.Debug;
public static class SRDebugUtil
{
public const int LineBufferCount = 512;
public static bool IsFixedUpdate { get; set; }
[DebuggerNonUserCode]
[DebuggerStepThrough]
public static void AssertNotNull(object value, string message = null, MonoBehaviour instance = null)
{
if (!EqualityComparer<object>.Default.Equals(value, null))
{
return;
}
message = message != null ? "NotNullAssert Failed: {0}".Fmt(message) : "Assert Failed";
Debug.LogError(message, instance);
if (instance != null)
{
instance.enabled = false;
}
throw new NullReferenceException(message);
}
[DebuggerNonUserCode]
[DebuggerStepThrough]
public static void Assert(bool condition, string message = null, MonoBehaviour instance = null)
{
if (condition)
{
return;
}
message = message != null ? "Assert Failed: {0}".Fmt(message) : "Assert Failed";
Debug.LogError(message, instance);
throw new Exception(message);
}
[Conditional("UNITY_EDITOR")]
[DebuggerNonUserCode]
[DebuggerStepThrough]
public static void EditorAssertNotNull(object value, string message = null, MonoBehaviour instance = null)
{
AssertNotNull(value, message, instance);
}
[Conditional("UNITY_EDITOR")]
[DebuggerNonUserCode]
[DebuggerStepThrough]
public static void EditorAssert(bool condition, string message = null, MonoBehaviour instance = null)
{
Assert(condition, message, instance);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f74f500c46d2b60419e95b8bd0cb87b6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,73 @@
using System.IO;
using System.Threading;
public static class SRFileUtil
{
#if !UNITY_WEBPLAYER && !NETFX_CORE
public static void DeleteDirectory(string path)
{
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
}
#endif
/// <summary>
/// Returns the human-readable file size for an arbitrary, 64-bit file size
/// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
/// </summary>
/// <param name="i"></param>
/// <remarks>http://stackoverflow.com/a/281684/147003</remarks>
/// <returns></returns>
public static string GetBytesReadable(long i)
{
var sign = (i < 0 ? "-" : "");
double readable = (i < 0 ? -i : i);
string suffix;
if (i >= 0x1000000000000000) // Exabyte
{
suffix = "EB";
readable = i >> 50;
}
else if (i >= 0x4000000000000) // Petabyte
{
suffix = "PB";
readable = i >> 40;
}
else if (i >= 0x10000000000) // Terabyte
{
suffix = "TB";
readable = i >> 30;
}
else if (i >= 0x40000000) // Gigabyte
{
suffix = "GB";
readable = i >> 20;
}
else if (i >= 0x100000) // Megabyte
{
suffix = "MB";
readable = i >> 10;
}
else if (i >= 0x400) // Kilobyte
{
suffix = "KB";
readable = i;
}
else
{
return i.ToString(sign + "0 B"); // Byte
}
readable /= 1024;
return sign + readable.ToString("0.### ") + suffix;
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c5dd64a3a7854e4f948daaec7d318fa
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,19 @@
using UnityEngine;
public static class SRInstantiate
{
public static T Instantiate<T>(T prefab) where T : Component
{
return (T) Object.Instantiate(prefab);
}
public static GameObject Instantiate(GameObject prefab)
{
return (GameObject) Object.Instantiate(prefab);
}
public static T Instantiate<T>(T prefab, Vector3 position, Quaternion rotation) where T : Component
{
return (T) Object.Instantiate(prefab, position, rotation);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2b2502558f76a9a4b9d3fd4d26d4d2a6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,788 @@
using UnityEngine;
public static partial class SRMath
{
/**
*
* These tweening functions taken from https://wpf-animation.googlecode.com/svn/trunk/src/WPF/Animation/PennerDoubleAnimation.cs
* Licensed under the new BSD License
*
* @author Darren David darren-code@lookorfeel.com
* @version 1.0
*
* Credit/Thanks:
* Robert Penner - The easing equations we all know and love
* (http://robertpenner.com/easing/) [See License.txt for license info]
*
* Lee Brimelow - initial port of Penner's equations to WPF
* (http://thewpfblog.com/?p=12)
*
* Zeh Fernando - additional equations (out/in) from
* caurina.transitions.Tweener (http://code.google.com/p/tweener/)
* [See License.txt for license info]
*
*/
private static class TweenFunctions
{
#region Equations
#region Linear
/// <summary>
/// Easing equation function for a simple linear tweening, with no easing.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float Linear(float t, float b, float c, float d)
{
return c*t/d + b;
}
#endregion
#region Expo
/// <summary>
/// Easing equation function for an exponential (2^t) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ExpoEaseOut(float t, float b, float c, float d)
{
return (t == d) ? b + c : c*(-Mathf.Pow(2, -10*t/d) + 1) + b;
}
/// <summary>
/// Easing equation function for an exponential (2^t) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ExpoEaseIn(float t, float b, float c, float d)
{
return (t == 0) ? b : c*Mathf.Pow(2, 10*(t/d - 1)) + b;
}
/// <summary>
/// Easing equation function for an exponential (2^t) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ExpoEaseInOut(float t, float b, float c, float d)
{
if (t == 0)
{
return b;
}
if (t == d)
{
return b + c;
}
if ((t /= d/2) < 1)
{
return c/2*Mathf.Pow(2, 10*(t - 1)) + b;
}
return c/2*(-Mathf.Pow(2, -10*--t) + 2) + b;
}
/// <summary>
/// Easing equation function for an exponential (2^t) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ExpoEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return ExpoEaseOut(t*2, b, c/2, d);
}
return ExpoEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Circular
/// <summary>
/// Easing equation function for a circular (sqrt(1-t^2)) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CircEaseOut(float t, float b, float c, float d)
{
return c*Mathf.Sqrt(1 - (t = t/d - 1)*t) + b;
}
/// <summary>
/// Easing equation function for a circular (sqrt(1-t^2)) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CircEaseIn(float t, float b, float c, float d)
{
return -c*(Mathf.Sqrt(1 - (t /= d)*t) - 1) + b;
}
/// <summary>
/// Easing equation function for a circular (sqrt(1-t^2)) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CircEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return -c/2*(Mathf.Sqrt(1 - t*t) - 1) + b;
}
return c/2*(Mathf.Sqrt(1 - (t -= 2)*t) + 1) + b;
}
/// <summary>
/// Easing equation function for a circular (sqrt(1-t^2)) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CircEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return CircEaseOut(t*2, b, c/2, d);
}
return CircEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Quad
/// <summary>
/// Easing equation function for a quadratic (t^2) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuadEaseOut(float t, float b, float c, float d)
{
return -c*(t /= d)*(t - 2) + b;
}
/// <summary>
/// Easing equation function for a quadratic (t^2) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuadEaseIn(float t, float b, float c, float d)
{
return c*(t /= d)*t + b;
}
/// <summary>
/// Easing equation function for a quadratic (t^2) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuadEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return c/2*t*t + b;
}
return -c/2*((--t)*(t - 2) - 1) + b;
}
/// <summary>
/// Easing equation function for a quadratic (t^2) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuadEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return QuadEaseOut(t*2, b, c/2, d);
}
return QuadEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Sine
/// <summary>
/// Easing equation function for a sinusoidal (sin(t)) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float SineEaseOut(float t, float b, float c, float d)
{
return c*Mathf.Sin(t/d*(Mathf.PI/2)) + b;
}
/// <summary>
/// Easing equation function for a sinusoidal (sin(t)) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float SineEaseIn(float t, float b, float c, float d)
{
return -c*Mathf.Cos(t/d*(Mathf.PI/2)) + c + b;
}
/// <summary>
/// Easing equation function for a sinusoidal (sin(t)) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float SineEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return c/2*(Mathf.Sin(Mathf.PI*t/2)) + b;
}
return -c/2*(Mathf.Cos(Mathf.PI*--t/2) - 2) + b;
}
/// <summary>
/// Easing equation function for a sinusoidal (sin(t)) easing in/out:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float SineEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return SineEaseOut(t*2, b, c/2, d);
}
return SineEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Cubic
/// <summary>
/// Easing equation function for a cubic (t^3) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CubicEaseOut(float t, float b, float c, float d)
{
return c*((t = t/d - 1)*t*t + 1) + b;
}
/// <summary>
/// Easing equation function for a cubic (t^3) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CubicEaseIn(float t, float b, float c, float d)
{
return c*(t /= d)*t*t + b;
}
/// <summary>
/// Easing equation function for a cubic (t^3) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CubicEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return c/2*t*t*t + b;
}
return c/2*((t -= 2)*t*t + 2) + b;
}
/// <summary>
/// Easing equation function for a cubic (t^3) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float CubicEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return CubicEaseOut(t*2, b, c/2, d);
}
return CubicEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Quartic
/// <summary>
/// Easing equation function for a quartic (t^4) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuartEaseOut(float t, float b, float c, float d)
{
return -c*((t = t/d - 1)*t*t*t - 1) + b;
}
/// <summary>
/// Easing equation function for a quartic (t^4) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuartEaseIn(float t, float b, float c, float d)
{
return c*(t /= d)*t*t*t + b;
}
/// <summary>
/// Easing equation function for a quartic (t^4) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuartEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return c/2*t*t*t*t + b;
}
return -c/2*((t -= 2)*t*t*t - 2) + b;
}
/// <summary>
/// Easing equation function for a quartic (t^4) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuartEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return QuartEaseOut(t*2, b, c/2, d);
}
return QuartEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Quintic
/// <summary>
/// Easing equation function for a quintic (t^5) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuintEaseOut(float t, float b, float c, float d)
{
return c*((t = t/d - 1)*t*t*t*t + 1) + b;
}
/// <summary>
/// Easing equation function for a quintic (t^5) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuintEaseIn(float t, float b, float c, float d)
{
return c*(t /= d)*t*t*t*t + b;
}
/// <summary>
/// Easing equation function for a quintic (t^5) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuintEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) < 1)
{
return c/2*t*t*t*t*t + b;
}
return c/2*((t -= 2)*t*t*t*t + 2) + b;
}
/// <summary>
/// Easing equation function for a quintic (t^5) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float QuintEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return QuintEaseOut(t*2, b, c/2, d);
}
return QuintEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Elastic
/// <summary>
/// Easing equation function for an elastic (exponentially decaying sine wave) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ElasticEaseOut(float t, float b, float c, float d)
{
if ((t /= d) == 1)
{
return b + c;
}
var p = d*.3f;
var s = p/4;
return (c*Mathf.Pow(2, -10*t)*Mathf.Sin((t*d - s)*(2*Mathf.PI)/p) + c + b);
}
/// <summary>
/// Easing equation function for an elastic (exponentially decaying sine wave) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ElasticEaseIn(float t, float b, float c, float d)
{
if ((t /= d) == 1)
{
return b + c;
}
var p = d*.3f;
var s = p/4;
return -(c*Mathf.Pow(2, 10*(t -= 1))*Mathf.Sin((t*d - s)*(2*Mathf.PI)/p)) + b;
}
/// <summary>
/// Easing equation function for an elastic (exponentially decaying sine wave) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ElasticEaseInOut(float t, float b, float c, float d)
{
if ((t /= d/2) == 2)
{
return b + c;
}
var p = d*(.3f*1.5f);
var s = p/4;
if (t < 1)
{
return -.5f*(c*Mathf.Pow(2, 10*(t -= 1))*Mathf.Sin((t*d - s)*(2*Mathf.PI)/p)) + b;
}
return c*Mathf.Pow(2, -10*(t -= 1))*Mathf.Sin((t*d - s)*(2*Mathf.PI)/p)*.5f + c + b;
}
/// <summary>
/// Easing equation function for an elastic (exponentially decaying sine wave) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float ElasticEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return ElasticEaseOut(t*2, b, c/2, d);
}
return ElasticEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Bounce
/// <summary>
/// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BounceEaseOut(float t, float b, float c, float d)
{
if ((t /= d) < (1/2.75f))
{
return c*(7.5625f*t*t) + b;
}
if (t < (2/2.75))
{
return c*(7.5625f*(t -= (1.5f/2.75f))*t + .75f) + b;
}
if (t < (2.5/2.75))
{
return c*(7.5625f*(t -= (2.25f/2.75f))*t + .9375f) + b;
}
return c*(7.5625f*(t -= (2.625f/2.75f))*t + .984375f) + b;
}
/// <summary>
/// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BounceEaseIn(float t, float b, float c, float d)
{
return c - BounceEaseOut(d - t, 0, c, d) + b;
}
/// <summary>
/// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BounceEaseInOut(float t, float b, float c, float d)
{
if (t < d/2)
{
return BounceEaseIn(t*2, 0, c, d)*.5f + b;
}
return BounceEaseOut(t*2 - d, 0, c, d)*.5f + c*.5f + b;
}
/// <summary>
/// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BounceEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return BounceEaseOut(t*2, b, c/2, d);
}
return BounceEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#region Back
/// <summary>
/// Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out:
/// decelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BackEaseOut(float t, float b, float c, float d)
{
return c*((t = t/d - 1)*t*((1.70158f + 1)*t + 1.70158f) + 1) + b;
}
/// <summary>
/// Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in:
/// accelerating from zero velocity.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BackEaseIn(float t, float b, float c, float d)
{
return c*(t /= d)*t*((1.70158f + 1)*t - 1.70158f) + b;
}
/// <summary>
/// Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out:
/// acceleration until halfway, then deceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BackEaseInOut(float t, float b, float c, float d)
{
var s = 1.70158f;
if ((t /= d/2) < 1)
{
return c/2*(t*t*(((s *= (1.525f)) + 1)*t - s)) + b;
}
return c/2*((t -= 2)*t*(((s *= (1.525f)) + 1)*t + s) + 2) + b;
}
/// <summary>
/// Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in:
/// deceleration until halfway, then acceleration.
/// </summary>
/// <param name="t">Current time in seconds.</param>
/// <param name="b">Starting value.</param>
/// <param name="c">Final value.</param>
/// <param name="d">Duration of animation.</param>
/// <returns>The correct value.</returns>
public static float BackEaseOutIn(float t, float b, float c, float d)
{
if (t < d/2)
{
return BackEaseOut(t*2, b, c/2, d);
}
return BackEaseIn((t*2) - d, b + c/2, c/2, d);
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c0be6d36a29af844fa2d7584d66b374c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,209 @@
using System;
using UnityEngine;
public static partial class SRMath
{
public enum EaseType
{
Linear,
QuadEaseOut,
QuadEaseIn,
QuadEaseInOut,
QuadEaseOutIn,
ExpoEaseOut,
ExpoEaseIn,
ExpoEaseInOut,
ExpoEaseOutIn,
CubicEaseOut,
CubicEaseIn,
CubicEaseInOut,
CubicEaseOutIn,
QuartEaseOut,
QuartEaseIn,
QuartEaseInOut,
QuartEaseOutIn,
QuintEaseOut,
QuintEaseIn,
QuintEaseInOut,
QuintEaseOutIn,
CircEaseOut,
CircEaseIn,
CircEaseInOut,
CircEaseOutIn,
SineEaseOut,
SineEaseIn,
SineEaseInOut,
SineEaseOutIn,
ElasticEaseOut,
ElasticEaseIn,
ElasticEaseInOut,
ElasticEaseOutIn,
BounceEaseOut,
BounceEaseIn,
BounceEaseInOut,
BounceEaseOutIn,
BackEaseOut,
BackEaseIn,
BackEaseInOut,
BackEaseOutIn
}
public static float Ease(float from, float to, float t, EaseType type)
{
switch (type)
{
case EaseType.Linear:
return TweenFunctions.Linear(t, from, to, 1f);
case EaseType.QuadEaseOut:
return TweenFunctions.QuadEaseOut(t, from, to, 1f);
case EaseType.QuadEaseIn:
return TweenFunctions.QuadEaseIn(t, from, to, 1f);
case EaseType.QuadEaseInOut:
return TweenFunctions.QuadEaseInOut(t, from, to, 1f);
case EaseType.QuadEaseOutIn:
return TweenFunctions.QuadEaseOutIn(t, from, to, 1f);
case EaseType.ExpoEaseOut:
return TweenFunctions.ExpoEaseOut(t, from, to, 1f);
case EaseType.ExpoEaseIn:
return TweenFunctions.ExpoEaseIn(t, from, to, 1f);
case EaseType.ExpoEaseInOut:
return TweenFunctions.ExpoEaseInOut(t, from, to, 1f);
case EaseType.ExpoEaseOutIn:
return TweenFunctions.ExpoEaseOutIn(t, from, to, 1f);
case EaseType.CubicEaseOut:
return TweenFunctions.CubicEaseOut(t, from, to, 1f);
case EaseType.CubicEaseIn:
return TweenFunctions.CubicEaseIn(t, from, to, 1f);
case EaseType.CubicEaseInOut:
return TweenFunctions.CubicEaseInOut(t, from, to, 1f);
case EaseType.CubicEaseOutIn:
return TweenFunctions.CubicEaseOutIn(t, from, to, 1f);
case EaseType.QuartEaseOut:
return TweenFunctions.QuartEaseOut(t, from, to, 1f);
case EaseType.QuartEaseIn:
return TweenFunctions.QuartEaseIn(t, from, to, 1f);
case EaseType.QuartEaseInOut:
return TweenFunctions.QuartEaseInOut(t, from, to, 1f);
case EaseType.QuartEaseOutIn:
return TweenFunctions.QuartEaseOutIn(t, from, to, 1f);
case EaseType.QuintEaseOut:
return TweenFunctions.QuintEaseOut(t, from, to, 1f);
case EaseType.QuintEaseIn:
return TweenFunctions.QuintEaseIn(t, from, to, 1f);
case EaseType.QuintEaseInOut:
return TweenFunctions.QuintEaseInOut(t, from, to, 1f);
case EaseType.QuintEaseOutIn:
return TweenFunctions.QuintEaseOutIn(t, from, to, 1f);
case EaseType.CircEaseOut:
return TweenFunctions.CircEaseOut(t, from, to, 1f);
case EaseType.CircEaseIn:
return TweenFunctions.CircEaseIn(t, from, to, 1f);
case EaseType.CircEaseInOut:
return TweenFunctions.CircEaseInOut(t, from, to, 1f);
case EaseType.CircEaseOutIn:
return TweenFunctions.CircEaseOutIn(t, from, to, 1f);
case EaseType.SineEaseOut:
return TweenFunctions.SineEaseOut(t, from, to, 1f);
case EaseType.SineEaseIn:
return TweenFunctions.SineEaseIn(t, from, to, 1f);
case EaseType.SineEaseInOut:
return TweenFunctions.SineEaseInOut(t, from, to, 1f);
case EaseType.SineEaseOutIn:
return TweenFunctions.SineEaseOutIn(t, from, to, 1f);
case EaseType.ElasticEaseOut:
return TweenFunctions.ElasticEaseOut(t, from, to, 1f);
case EaseType.ElasticEaseIn:
return TweenFunctions.ElasticEaseIn(t, from, to, 1f);
case EaseType.ElasticEaseInOut:
return TweenFunctions.ElasticEaseInOut(t, from, to, 1f);
case EaseType.ElasticEaseOutIn:
return TweenFunctions.ElasticEaseOutIn(t, from, to, 1f);
case EaseType.BounceEaseOut:
return TweenFunctions.BounceEaseOut(t, from, to, 1f);
case EaseType.BounceEaseIn:
return TweenFunctions.BounceEaseIn(t, from, to, 1f);
case EaseType.BounceEaseInOut:
return TweenFunctions.BounceEaseInOut(t, from, to, 1f);
case EaseType.BounceEaseOutIn:
return TweenFunctions.BounceEaseOutIn(t, from, to, 1f);
case EaseType.BackEaseOut:
return TweenFunctions.BackEaseOut(t, from, to, 1f);
case EaseType.BackEaseIn:
return TweenFunctions.BackEaseIn(t, from, to, 1f);
case EaseType.BackEaseInOut:
return TweenFunctions.BackEaseInOut(t, from, to, 1f);
case EaseType.BackEaseOutIn:
return TweenFunctions.BackEaseOutIn(t, from, to, 1f);
default:
throw new ArgumentOutOfRangeException("type");
}
}
/// <summary>
/// Calculate a framerate-independent value to lerp by
/// </summary>
/// <param name="strength"></param>
/// <param name="deltaTime"></param>
/// <returns></returns>
public static float SpringLerp(float strength, float deltaTime)
{
var ms = Mathf.RoundToInt(deltaTime*1000f);
var step = 0.001f*strength;
var from = 0f;
var to = 1f;
for (var i = 0; i < ms; i++)
{
from = Mathf.Lerp(from, to, step);
}
return from;
}
/// <summary>
/// A frame-rate independent way of doing Mathf.Lerp(from, to, Time.deltaTime * strength). Based on NGUIMath.SpringLerp
/// </summary>
/// <param name="from">Starting Value</param>
/// <param name="to">End Value</param>
/// <param name="strength">How fast the spring will complete</param>
/// <param name="deltaTime">Pass in Time.deltaTime or RealTime.deltaTime</param>
/// <returns>Interpolated value</returns>
public static float SpringLerp(float from, float to, float strength, float deltaTime)
{
return Mathf.Lerp(from, to, SpringLerp(strength, deltaTime));
}
public static Vector3 SpringLerp(Vector3 from, Vector3 to, float strength, float deltaTime)
{
return Vector3.Lerp(from, to, SpringLerp(strength, deltaTime));
}
public static Quaternion SpringLerp(Quaternion from, Quaternion to, float strength, float deltaTime)
{
return Quaternion.Slerp(from, to, SpringLerp(strength, deltaTime));
}
/// <summary>
/// Smoothly clamp value between 0 and max, smoothing between min and max
/// </summary>
/// <param name="value"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <param name="easeType"></param>
/// <returns></returns>
public static float SmoothClamp(float value, float min, float max, float scrollMax,
EaseType easeType = EaseType.ExpoEaseOut)
{
if (value < min)
{
return value;
}
var p = Mathf.Clamp01((value - min)/(scrollMax - min));
Debug.Log(p);
return Mathf.Clamp(min + Mathf.Lerp(value - min, max, Ease(0, 1f, p, easeType)), 0, max);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 810c2c875ec6af345a04174ff5828880
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,151 @@
using System;
using UnityEngine;
public static partial class SRMath
{
/// <summary>
/// Lerp from one value to another, without clamping t to 0-1.
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="t"></param>
/// <returns></returns>
public static float LerpUnclamped(float from, float to, float t)
{
return (1.0f - t)*from + t*to;
}
/// <summary>
/// Lerp from one vector to another, without clamping t
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="t"></param>
/// <returns></returns>
public static Vector3 LerpUnclamped(Vector3 from, Vector3 to, float t)
{
return new Vector3(
LerpUnclamped(from.x, to.x, t),
LerpUnclamped(from.y, to.y, t),
LerpUnclamped(from.z, to.z, t)
);
}
/// <summary>
/// Value from 0.0f-1.0f, 0 when facing fully away and 1.0f when facing fully towards
/// </summary>
public static float FacingNormalized(Vector3 dir1, Vector3 dir2)
{
dir1.Normalize();
dir2.Normalize();
return Mathf.InverseLerp(-1, 1, Vector3.Dot(dir1, dir2));
}
/// <summary>
/// Reduces a given angle to a value between 180 and -180.
/// </summary>
/// <param name="angle">The angle to reduce, in radians.</param>
/// <returns>The new angle, in radians.</returns>
/// https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/MathHelper.cs
public static float WrapAngle(float angle)
{
if (angle <= -180f)
{
angle += 360f;
}
else
{
if (angle > 180f)
{
angle -= 360f;
}
}
return angle;
}
/// <summary>
/// Return the angle closest to 'to'
/// </summary>
/// <param name="to"></param>
/// <param name="angle1"></param>
/// <param name="angle2"></param>
/// <returns></returns>
public static float NearestAngle(float to, float angle1, float angle2)
{
if (Mathf.Abs(Mathf.DeltaAngle(to, angle1)) > Mathf.Abs(Mathf.DeltaAngle(to, angle2)))
{
return angle2;
}
return angle1;
}
/// <summary>
/// Wrap value to 0-max (non-inclusive)
/// </summary>
/// <param name="max">Max value (non-inclusive)</param>
/// <param name="value"></param>
/// <returns>Value wrapped from 0-max</returns>
public static int Wrap(int max, int value)
{
if (max < 0)
{
throw new ArgumentOutOfRangeException("max", "max must be greater than 0");
}
while (value < 0)
{
value += max;
}
while (value >= max)
{
value -= max;
}
return value;
}
/// <summary>
/// Wrap value to 0-max (non-inclusive)
/// </summary>
/// <param name="max">Max value (non-inclusive)</param>
/// <param name="value"></param>
/// <returns>Value wrapped from 0-max</returns>
public static float Wrap(float max, float value)
{
while (value < 0)
{
value += max;
}
while (value >= max)
{
value -= max;
}
return value;
}
public static float Average(float v1, float v2)
{
return (v1 + v2)*0.5f;
}
/// <summary>
/// Return an angle in range -180, 180 based on direction vector
/// </summary>
/// <param name="direction"></param>
/// <returns></returns>
public static float Angle(Vector2 direction)
{
var angle = Vector3.Angle(Vector3.up, direction);
if (Vector3.Cross(direction, Vector3.up).z > 0f)
{
angle *= -1;
}
return angle;
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc751da3d31975645847e0e4088ff560
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,46 @@
namespace SRF.Helpers
{
using System;
using System.Reflection;
public static class SRReflection
{
public static void SetPropertyValue(object obj, PropertyInfo p, object value)
{
#if NETFX_CORE
p.SetValue(obj, value, null);
#else
p.GetSetMethod().Invoke(obj, new[] {value});
#endif
}
public static object GetPropertyValue(object obj, PropertyInfo p)
{
#if NETFX_CORE
return p.GetValue(obj, null);
#else
return p.GetGetMethod().Invoke(obj, null);
#endif
}
public static T GetAttribute<T>(MemberInfo t) where T : Attribute
{
#if !NETFX_CORE
return Attribute.GetCustomAttribute(t, typeof (T)) as T;
#else
return t.GetCustomAttribute(typeof (T), true) as T;
#endif
}
#if NETFX_CORE
public static T GetAttribute<T>(Type t) where T : Attribute
{
return GetAttribute<T>(t.GetTypeInfo());
}
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6aaf1b857713dd44a955633b6458f1c2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 9107076f77b9a344d8c00028a350b6fb
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,39 @@
using UnityEngine.Scripting;
namespace SRF.Service
{
using System;
[AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceAttribute : PreserveAttribute
{
public ServiceAttribute(Type serviceType)
{
ServiceType = serviceType;
}
public Type ServiceType { get; private set; }
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class ServiceSelectorAttribute : PreserveAttribute
{
public ServiceSelectorAttribute(Type serviceType)
{
ServiceType = serviceType;
}
public Type ServiceType { get; private set; }
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class ServiceConstructorAttribute : PreserveAttribute
{
public ServiceConstructorAttribute(Type serviceType)
{
ServiceType = serviceType;
}
public Type ServiceType { get; private set; }
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 901f51b194db73d479d84ae26519fc20
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,7 @@
namespace SRF.Service
{
public interface IAsyncService
{
bool IsLoaded { get; }
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 08e9b59ff0ffb22488411ef5134ee325
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,91 @@
//#define ENABLE_LOGGING
namespace SRF.Service
{
using System;
using System.Collections;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
/// <summary>
/// A service which has async-loading dependencies
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class SRDependencyServiceBase<T> : SRServiceBase<T>, IAsyncService where T : class
{
private bool _isLoaded;
protected abstract Type[] Dependencies { get; }
public bool IsLoaded
{
get { return _isLoaded; }
}
[Conditional("ENABLE_LOGGING")]
private void Log(string msg, Object target)
{
//#if ENABLE_LOGGING
Debug.Log(msg, target);
//#endif
}
protected override void Start()
{
base.Start();
StartCoroutine(LoadDependencies());
}
/// <summary>
/// Invoked once all dependencies are loaded
/// </summary>
protected virtual void OnLoaded() {}
private IEnumerator LoadDependencies()
{
SRServiceManager.LoadingCount++;
Log("[Service] Loading service ({0})".Fmt(GetType().Name), this);
foreach (var d in Dependencies)
{
var hasService = SRServiceManager.HasService(d);
Log("[Service] Resolving Service ({0}) HasService: {1}".Fmt(d.Name, hasService), this);
if (hasService)
{
continue;
}
var service = SRServiceManager.GetService(d);
if (service == null)
{
Debug.LogError("[Service] Could not resolve dependency ({0})".Fmt(d.Name));
enabled = false;
yield break;
}
var a = service as IAsyncService;
if (a != null)
{
while (!a.IsLoaded)
{
yield return new WaitForEndOfFrame();
}
}
}
Log("[Service] Loading service ({0}) complete.".Fmt(GetType().Name), this);
_isLoaded = true;
SRServiceManager.LoadingCount--;
OnLoaded();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c5aaa1711d009f48a19f2db87d71b82
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,128 @@
//#define ENABLE_LOGGING
namespace SRF.Service
{
using System.Collections;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
public abstract class SRSceneServiceBase<T, TImpl> : SRServiceBase<T>, IAsyncService
where T : class
where TImpl : Component
{
private TImpl _rootObject;
/// <summary>
/// Name of the scene this service's contents are within
/// </summary>
protected abstract string SceneName { get; }
/// <summary>
/// Scene contents root object
/// </summary>
protected TImpl RootObject
{
get { return _rootObject; }
}
public bool IsLoaded
{
get { return _rootObject != null; }
}
[Conditional("ENABLE_LOGGING")]
private void Log(string msg, Object target)
{
//#if ENABLE_LOGGING
Debug.Log(msg, target);
//#endif
}
protected override void Start()
{
base.Start();
StartCoroutine(LoadCoroutine());
}
protected override void OnDestroy()
{
if (IsLoaded)
{
Destroy(_rootObject.gameObject);
}
base.OnDestroy();
}
protected virtual void OnLoaded() {}
private IEnumerator LoadCoroutine()
{
if (_rootObject != null)
{
yield break;
}
SRServiceManager.LoadingCount++;
#if UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
if (Application.loadedLevelName == SceneName)
#else
if (UnityEngine.SceneManagement.SceneManager.GetSceneByName(SceneName).isLoaded)
#endif
{
Log("[Service] Already in service scene {0}. Searching for root object...".Fmt(SceneName), this);
}
else
{
Log("[Service] Loading scene ({0})".Fmt(SceneName), this);
#if UNITY_PRO_LICENSE || UNITY_5 || UNITY_5_3_OR_NEWER
#if UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
yield return Application.LoadLevelAdditiveAsync(SceneName);
#else
yield return UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(SceneName, UnityEngine.SceneManagement.LoadSceneMode.Additive);
#endif
#else
Application.LoadLevelAdditive(SceneName);
yield return new WaitForEndOfFrame();
#endif
Log("[Service] Scene loaded. Searching for root object...", this);
}
var go = GameObject.Find(SceneName);
if (go == null)
{
goto Error;
}
var timpl = go.GetComponent<TImpl>();
if (timpl == null)
{
goto Error;
}
_rootObject = timpl;
_rootObject.transform.parent = CachedTransform;
DontDestroyOnLoad(go);
Debug.Log("[Service] Loading {0} complete. (Scene: {1})".Fmt(GetType().Name, SceneName), this);
SRServiceManager.LoadingCount--;
OnLoaded();
yield break;
Error:
SRServiceManager.LoadingCount--;
Debug.LogError("[Service] Root object ({0}) not found".Fmt(SceneName), this);
enabled = false;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ff0dcbb555990d24e9e3055e77395656
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,17 @@
namespace SRF.Service
{
public abstract class SRServiceBase<T> : SRMonoBehaviourEx where T : class
{
protected override void Awake()
{
base.Awake();
SRServiceManager.RegisterService<T>(this);
}
protected override void OnDestroy()
{
base.OnDestroy();
SRServiceManager.UnRegisterService<T>();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4f48d5ad0a809349bd5e46160a824d3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,530 @@
// Disable unreachable code warning caused by DEBUG
#pragma warning disable 0162
namespace SRF.Service
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Components;
using Helpers;
using Internal;
using UnityEngine;
using Object = UnityEngine.Object;
[AddComponentMenu(ComponentMenuPaths.SRServiceManager)]
public class SRServiceManager : SRAutoSingleton<SRServiceManager>
{
#if SRDEBUG
public const bool EnableLogging = true;
#else
public const bool EnableLogging = false;
#endif
#if UNITY_EDITOR && ((!UNITY_2017 && !UNITY_2018 && !UNITY_2019) || UNITY_2019_3_OR_NEWER)
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
public static void RuntimeInitialize()
{
// To handle entering play mode without a domain reload, need to reset the state of the service manager.
_hasQuit = false;
}
#endif
/// <summary>
/// Register the assembly that contains type <typeparamref name="TType"/> with the service manager.
/// </summary>
/// <typeparam name="TType"></typeparam>
public static void RegisterAssembly<TType>()
{
#if NETFX_CORE
var assembly = typeof(TType).GetTypeInfo().Assembly;
#else
var assembly = typeof(TType).Assembly;
#endif
if (_assemblies.Contains(assembly))
{
return;
}
_assemblies.Add(assembly);
}
/// <summary>
/// Is there a service loading?
/// </summary>
public static bool IsLoading
{
get { return LoadingCount > 0; }
}
public static int LoadingCount = 0;
public static T GetService<T>() where T : class
{
var s = GetServiceInternal(typeof(T)) as T;
if (s == null && (!_hasQuit || EnableLogging))
{
Debug.LogWarning("Service {0} not found. (HasQuit: {1})".Fmt(typeof(T).Name, _hasQuit));
}
return s;
}
public static object GetService(Type t)
{
var s = GetServiceInternal(t);
if (s == null && (!_hasQuit || EnableLogging))
{
Debug.LogWarning("Service {0} not found. (HasQuit: {1})".Fmt(t.Name, _hasQuit));
}
return s;
}
private static object GetServiceInternal(Type t)
{
if (_hasQuit || !Application.isPlaying)
{
return null;
}
var services = Instance._services;
for (var i = 0; i < services.Count; i++)
{
var s = services[i];
if (t.IsAssignableFrom(s.Type))
{
if (s.Object == null)
{
UnRegisterService(t);
break;
}
return s.Object;
}
}
return Instance.AutoCreateService(t);
}
public static bool HasService<T>() where T : class
{
return HasService(typeof(T));
}
public static bool HasService(Type t)
{
if (_hasQuit || !Application.isPlaying)
{
return false;
}
var services = Instance._services;
for (var i = 0; i < services.Count; i++)
{
var s = services[i];
if (t.IsAssignableFrom(s.Type))
{
return s.Object != null;
}
}
return false;
}
public static void RegisterService<T>(object service) where T : class
{
RegisterService(typeof(T), service);
}
private static void RegisterService(Type t, object service)
{
if (_hasQuit)
{
return;
}
if (HasService(t))
{
if (GetServiceInternal(t) == service)
{
return;
}
throw new Exception("Service already registered for type " + t.Name);
}
UnRegisterService(t);
if (!t.IsInstanceOfType(service))
{
throw new ArgumentException("service {0} must be assignable from type {1}".Fmt(service.GetType(), t));
}
Instance._services.Add(new Service {
Object = service,
Type = t
});
}
public static void UnRegisterService<T>() where T : class
{
UnRegisterService(typeof(T));
}
private static void UnRegisterService(Type t)
{
if (_hasQuit || !HasInstance)
{
return;
}
if (!HasService(t))
{
return;
}
var services = Instance._services;
for (var i = services.Count - 1; i >= 0; i--)
{
var s = services[i];
if (s.Type == t)
{
services.RemoveAt(i);
}
}
}
private class Service
{
public object Object;
public Type Type;
}
private class ServiceStub
{
public Func<object> Constructor;
public Type InterfaceType;
public Func<Type> Selector;
public Type Type;
public override string ToString()
{
var s = InterfaceType.Name + " (";
if (Type != null)
{
s += "Type: " + Type;
}
else if (Selector != null)
{
s += "Selector: " + Selector;
}
else if (Constructor != null)
{
s += "Constructor: " + Constructor;
}
s += ")";
return s;
}
}
private static readonly List<Assembly> _assemblies = new List<Assembly>(2);
private readonly SRList<Service> _services = new SRList<Service>();
private List<ServiceStub> _serviceStubs;
private static bool _hasQuit;
protected override void Awake()
{
_hasQuit = false;
base.Awake();
DontDestroyOnLoad(CachedGameObject);
CachedGameObject.hideFlags = HideFlags.NotEditable;
}
protected void UpdateStubs()
{
if (_serviceStubs != null)
{
return;
}
RegisterAssembly<SRServiceManager>();
_serviceStubs = new List<ServiceStub>();
var types = new List<Type>();
foreach (var assembly in _assemblies)
{
try
{
#if NETFX_CORE
types.AddRange(assembly.Types);
#else
types.AddRange(assembly.GetTypes());
#endif
}
catch (Exception e)
{
Debug.LogError("[SRServiceManager] Error loading assembly {0}".Fmt(assembly.FullName), this);
Debug.LogException(e);
}
}
foreach (var type in types)
{
ScanType(type);
}
if (EnableLogging)
{
var serviceStrings =
_serviceStubs.Select(p => " {0}".Fmt(p)).ToArray();
Debug.Log("[SRServiceManager] Services Discovered: {0} \n {1}".Fmt(serviceStrings.Length,
string.Join("\n ", serviceStrings)));
}
}
protected object AutoCreateService(Type t)
{
UpdateStubs();
foreach (var stub in _serviceStubs)
{
if (stub.InterfaceType != t)
{
continue;
}
object service = null;
if (stub.Constructor != null)
{
service = stub.Constructor();
}
else
{
var serviceType = stub.Type;
if (serviceType == null)
{
serviceType = stub.Selector();
}
service = DefaultServiceConstructor(t, serviceType);
}
if (!HasService(t))
{
RegisterService(t, service);
}
if (EnableLogging)
{
Debug.Log("[SRServiceManager] Auto-created service: {0} ({1})".Fmt(stub.Type, stub.InterfaceType),
service as Object);
}
return service;
}
return null;
}
protected void OnApplicationQuit()
{
_hasQuit = true;
_assemblies.Clear();
}
#if UNITY_EDITOR
protected void OnDisable()
{
if (EnableLogging)
{
Debug.Log("[SRServiceManager] Cleaning up services");
}
// Script recompile is likely in progress - clear up everything.
foreach (Service s in _services)
{
IDisposable disposable = s.Object as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
Behaviour behaviour = s.Object as Behaviour;
if (behaviour != null)
{
DestroyImmediate(behaviour.gameObject);
} else if (s.Object is Object)
{
DestroyImmediate(s.Object as Object);
}
}
_services.Clear(clean: true);
}
#endif
private static object DefaultServiceConstructor(Type serviceIntType, Type implType)
{
// If mono-behaviour based, create a gameobject for this service
if (typeof(MonoBehaviour).IsAssignableFrom(implType))
{
var go = new GameObject("_S_" + serviceIntType.Name);
return go.AddComponent(implType);
}
// If ScriptableObject based, create an instance
if (typeof(ScriptableObject).IsAssignableFrom(implType))
{
var obj = ScriptableObject.CreateInstance(implType);
return obj;
}
// If just a standard C# object, just create an instance
return Activator.CreateInstance(implType);
}
#region Type Scanning
private void ScanType(Type type)
{
var attribute = SRReflection.GetAttribute<ServiceAttribute>(type);
if (attribute != null)
{
_serviceStubs.Add(new ServiceStub {
Type = type,
InterfaceType = attribute.ServiceType
});
}
ScanTypeForConstructors(type, _serviceStubs);
ScanTypeForSelectors(type, _serviceStubs);
}
private static void ScanTypeForSelectors(Type t, List<ServiceStub> stubs)
{
var methods = GetStaticMethods(t);
foreach (var method in methods)
{
var attrib = SRReflection.GetAttribute<ServiceSelectorAttribute>(method);
if (attrib == null)
{
continue;
}
if (method.ReturnType != typeof(Type))
{
Debug.LogError("ServiceSelector must have return type of Type ({0}.{1}())".Fmt(t.Name, method.Name));
continue;
}
if (method.GetParameters().Length > 0)
{
Debug.LogError("ServiceSelector must have no parameters ({0}.{1}())".Fmt(t.Name, method.Name));
continue;
}
var stub = stubs.FirstOrDefault(p => p.InterfaceType == attrib.ServiceType);
if (stub == null)
{
stub = new ServiceStub {
InterfaceType = attrib.ServiceType
};
stubs.Add(stub);
}
#if NETFX_CORE
stub.Selector = (Func<Type>)method.CreateDelegate(typeof(Func<Type>));
#else
stub.Selector = (Func<Type>)Delegate.CreateDelegate(typeof(Func<Type>), method);
#endif
}
}
private static void ScanTypeForConstructors(Type t, List<ServiceStub> stubs)
{
var methods = GetStaticMethods(t);
foreach (var method in methods)
{
var attrib = SRReflection.GetAttribute<ServiceConstructorAttribute>(method);
if (attrib == null)
{
continue;
}
if (method.ReturnType != attrib.ServiceType)
{
Debug.LogError("ServiceConstructor must have return type of {2} ({0}.{1}())".Fmt(t.Name, method.Name,
attrib.ServiceType));
continue;
}
if (method.GetParameters().Length > 0)
{
Debug.LogError("ServiceConstructor must have no parameters ({0}.{1}())".Fmt(t.Name, method.Name));
continue;
}
var stub = stubs.FirstOrDefault(p => p.InterfaceType == attrib.ServiceType);
if (stub == null)
{
stub = new ServiceStub {
InterfaceType = attrib.ServiceType
};
stubs.Add(stub);
}
var m = method;
stub.Constructor = () => m.Invoke(null, null);
}
}
#endregion
#region Reflection
private static MethodInfo[] GetStaticMethods(Type t)
{
#if !NETFX_CORE
return t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
#else
return t.GetTypeInfo().DeclaredMethods.Where(p => p.IsStatic).ToArray();
#endif
}
#endregion
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 83920a42d6e0f814bacbc701ae8636a5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 16100
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: ed6eb48a67380fe40a3864e012ce762d
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,145 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof (RectTransform))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.ContentFitText)]
public class ContentFitText : UIBehaviour, ILayoutElement
{
public SRText CopySource;
public Vector2 Padding;
public float minWidth
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetMinWidth(CopySource.rectTransform) + Padding.x;
}
}
public float preferredWidth
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetPreferredWidth(CopySource.rectTransform) + Padding.x;
}
}
public float flexibleWidth
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetFlexibleWidth(CopySource.rectTransform);
}
}
public float minHeight
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetFlexibleHeight(CopySource.rectTransform) + Padding.y;
}
}
public float preferredHeight
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetPreferredHeight(CopySource.rectTransform) + Padding.y;
}
}
public float flexibleHeight
{
get
{
if (CopySource == null)
{
return -1f;
}
return LayoutUtility.GetFlexibleHeight(CopySource.rectTransform);
}
}
public int layoutPriority
{
get { return 0; }
}
public void CalculateLayoutInputHorizontal()
{
CopySource.CalculateLayoutInputHorizontal();
}
public void CalculateLayoutInputVertical()
{
CopySource.CalculateLayoutInputVertical();
}
protected override void OnEnable()
{
SetDirty();
CopySource.LayoutDirty += CopySourceOnLayoutDirty;
}
private void CopySourceOnLayoutDirty(SRText srText)
{
SetDirty();
}
protected override void OnTransformParentChanged()
{
SetDirty();
}
protected override void OnDisable()
{
CopySource.LayoutDirty -= CopySourceOnLayoutDirty;
SetDirty();
}
protected override void OnDidApplyAnimationProperties()
{
SetDirty();
}
protected override void OnBeforeTransformParentChanged()
{
SetDirty();
}
protected void SetDirty()
{
if (!IsActive())
{
return;
}
LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dced79525dbfa2b44b8d52b2cca6d745
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,95 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// Copies the preferred size of another layout element (useful for a parent object basing its sizing from a child
/// element).
/// This does have very quirky behaviour, though.
/// TODO: Write custom editor for this to match layout element editor
/// </summary>
[RequireComponent(typeof (RectTransform))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.CopyLayoutElement)]
public class CopyLayoutElement : UIBehaviour, ILayoutElement
{
public bool CopyMinHeight;
public bool CopyMinWidth;
public bool CopyPreferredHeight;
public bool CopyPreferredWidth;
public RectTransform CopySource;
public float PaddingMinHeight;
public float PaddingMinWidth;
public float PaddingPreferredHeight;
public float PaddingPreferredWidth;
public float preferredWidth
{
get
{
if (!CopyPreferredWidth || CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetPreferredWidth(CopySource) + PaddingPreferredWidth;
}
}
public float preferredHeight
{
get
{
if (!CopyPreferredHeight || CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetPreferredHeight(CopySource) + PaddingPreferredHeight;
}
}
public float minWidth
{
get
{
if (!CopyMinWidth || CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetMinWidth(CopySource) + PaddingMinWidth;
}
}
public float minHeight
{
get
{
if (!CopyMinHeight || CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetMinHeight(CopySource) + PaddingMinHeight;
}
}
public int layoutPriority
{
get { return 2; }
}
public float flexibleHeight
{
get { return -1; }
}
public float flexibleWidth
{
get { return -1; }
}
public void CalculateLayoutInputHorizontal() {}
public void CalculateLayoutInputVertical() {}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 525a40520606ceb469b7494cb8ddef87
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,50 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Copies the preferred size of another layout element (useful for a parent object basing its sizing from a child
/// element).
/// This does have very quirky behaviour, though.
/// </summary>
[RequireComponent(typeof (RectTransform))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.CopyPreferredSize)]
public class CopyPreferredSize : LayoutElement
{
public RectTransform CopySource;
public float PaddingHeight;
public float PaddingWidth;
public override float preferredWidth
{
get
{
if (CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetPreferredWidth(CopySource) + PaddingWidth;
}
}
public override float preferredHeight
{
get
{
if (CopySource == null || !IsActive())
{
return -1f;
}
return LayoutUtility.GetPreferredHeight(CopySource) + PaddingHeight;
}
}
public override int layoutPriority
{
get { return 2; }
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32609112f4257a740aa4b920a8556d24
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,107 @@
using System;
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Copies the preferred size of another layout element (useful for a parent object basing its sizing from a child
/// element).
/// This does have very quirky behaviour, though.
/// </summary>
[RequireComponent(typeof(RectTransform))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.CopyPreferredSizes)]
public class CopyPreferredSizes : LayoutElement
{
public enum Operations
{
Max,
Min
}
[Serializable]
public class CopySource
{
public RectTransform Rect;
public float PaddingHeight;
public float PaddingWidth;
}
public CopySource[] CopySources;
public Operations Operation;
public override float preferredWidth
{
get
{
if (CopySources == null || CopySources.Length == 0 || !IsActive())
{
return -1f;
}
float current = Operation == Operations.Max ? float.MinValue : float.MaxValue;
for (var i = 0; i < CopySources.Length; i++)
{
if (CopySources[i].Rect == null)
continue;
float width = LayoutUtility.GetPreferredWidth(CopySources[i].Rect) + CopySources[i].PaddingWidth;
if (Operation == Operations.Max && width > current)
current = width;
else if (Operation == Operations.Min && width < current)
current = width;
}
// ReSharper disable CompareOfFloatsByEqualityOperator
if (Operation == Operations.Max && current == float.MinValue) return -1;
if (Operation == Operations.Min && current == float.MaxValue) return -1;
// ReSharper restore CompareOfFloatsByEqualityOperator
return current;
}
}
public override float preferredHeight
{
get
{
if (CopySources == null || CopySources.Length == 0 || !IsActive())
{
return -1f;
}
float current = Operation == Operations.Max ? float.MinValue : float.MaxValue;
for (var i = 0; i < CopySources.Length; i++)
{
if (CopySources[i].Rect == null)
continue;
float height = LayoutUtility.GetPreferredHeight(CopySources[i].Rect) + CopySources[i].PaddingHeight;
if (Operation == Operations.Max && height > current)
current = height;
else if (Operation == Operations.Min && height < current)
current = height;
}
// ReSharper disable CompareOfFloatsByEqualityOperator
if (Operation == Operations.Max && current == float.MinValue) return -1;
if (Operation == Operations.Min && current == float.MaxValue) return -1;
// ReSharper restore CompareOfFloatsByEqualityOperator
return current;
}
}
public override int layoutPriority
{
get { return 2; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5c292f06a2fb3644aac9698b40bd348
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Copies the preferred size of another layout element (useful for a parent object basing its sizing from a child
/// element).
/// This does have very quirky behaviour, though.
/// </summary>
[RequireComponent(typeof(RectTransform))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.CopySizeIntoLayoutElement)]
public class CopySizeIntoLayoutElement : LayoutElement
{
public RectTransform CopySource;
public float PaddingHeight;
public float PaddingWidth;
public bool SetPreferredSize = false;
public bool SetMinimumSize = false;
public override float preferredWidth
{
get
{
if (!SetPreferredSize || CopySource == null || !IsActive())
{
return -1f;
}
return CopySource.rect.width + PaddingWidth;
}
}
public override float preferredHeight
{
get
{
if (!SetPreferredSize || CopySource == null || !IsActive())
{
return -1f;
}
return CopySource.rect.height + PaddingHeight;
}
}
public override float minWidth
{
get
{
if (!SetMinimumSize || CopySource == null || !IsActive())
{
return -1f;
}
return CopySource.rect.width + PaddingWidth;
}
}
public override float minHeight
{
get
{
if (!SetMinimumSize || CopySource == null || !IsActive())
{
return -1f;
}
return CopySource.rect.height + PaddingHeight;
}
}
public override int layoutPriority
{
get { return 2; }
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 65f264d1c98f61c4f9143ddeb0e74ff5
timeCreated: 1476961746
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,190 @@
namespace SRF.UI
{
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class DragHandle : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
private CanvasScaler _canvasScaler;
private float _delta;
private float _startValue;
public RectTransform.Axis Axis = RectTransform.Axis.Horizontal;
public bool Invert = false;
public float MaxSize = -1;
public LayoutElement TargetLayoutElement;
public RectTransform TargetRectTransform;
private float Mult
{
get { return Invert ? -1 : 1; }
}
public void OnBeginDrag(PointerEventData eventData)
{
if (!Verify())
{
return;
}
//Debug.Log("OnBeginDrag");
_startValue = GetCurrentValue();
_delta = 0;
}
public void OnDrag(PointerEventData eventData)
{
if (!Verify())
{
return;
}
//Debug.Log("OnDrag");
var delta = 0f;
if (Axis == RectTransform.Axis.Horizontal)
{
delta += eventData.delta.x;
}
else
{
delta += eventData.delta.y;
}
if (_canvasScaler != null)
{
delta /= _canvasScaler.scaleFactor;
}
delta *= Mult;
_delta += delta;
SetCurrentValue(Mathf.Clamp(_startValue + _delta, GetMinSize(), GetMaxSize()));
}
public void OnEndDrag(PointerEventData eventData)
{
if (!Verify())
{
return;
}
//Debug.Log("OnEndDrag");
SetCurrentValue(Mathf.Max(_startValue + _delta, GetMinSize()));
_delta = 0;
CommitCurrentValue();
}
private void Start()
{
Verify();
_canvasScaler = GetComponentInParent<CanvasScaler>();
}
private bool Verify()
{
if (TargetLayoutElement == null && TargetRectTransform == null)
{
Debug.LogWarning(
"DragHandle: TargetLayoutElement and TargetRectTransform are both null. Disabling behaviour.");
enabled = false;
return false;
}
return true;
}
private float GetCurrentValue()
{
if (TargetLayoutElement != null)
{
return Axis == RectTransform.Axis.Horizontal
? TargetLayoutElement.preferredWidth
: TargetLayoutElement.preferredHeight;
}
if (TargetRectTransform != null)
{
return Axis == RectTransform.Axis.Horizontal
? TargetRectTransform.sizeDelta.x
: TargetRectTransform.sizeDelta.y;
}
throw new InvalidOperationException();
}
private void SetCurrentValue(float value)
{
if (TargetLayoutElement != null)
{
if (Axis == RectTransform.Axis.Horizontal)
{
TargetLayoutElement.preferredWidth = value;
}
else
{
TargetLayoutElement.preferredHeight = value;
}
return;
}
if (TargetRectTransform != null)
{
var d = TargetRectTransform.sizeDelta;
if (Axis == RectTransform.Axis.Horizontal)
{
d.x = value;
}
else
{
d.y = value;
}
TargetRectTransform.sizeDelta = d;
return;
}
throw new InvalidOperationException();
}
private void CommitCurrentValue()
{
if (TargetLayoutElement != null)
{
if (Axis == RectTransform.Axis.Horizontal)
{
TargetLayoutElement.preferredWidth = ((RectTransform) TargetLayoutElement.transform).sizeDelta.x;
}
else
{
TargetLayoutElement.preferredHeight = ((RectTransform) TargetLayoutElement.transform).sizeDelta.y;
}
}
}
private float GetMinSize()
{
if (TargetLayoutElement == null)
{
return 0;
}
return Axis == RectTransform.Axis.Horizontal ? TargetLayoutElement.minWidth : TargetLayoutElement.minHeight;
}
private float GetMaxSize()
{
if (MaxSize > 0)
{
return MaxSize;
}
return float.MaxValue;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8faed27c04557e24e8aecd35f2b4d9d3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: fee397aaceb8d684a94ce2bae9b71aa1
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,39 @@
namespace SRF.UI.Editor
{
/*[CustomEditor(typeof(CopyLayoutElement))]
[CanEditMultipleObjects]
public class CopyLayoutElementEditor : UnityEditor.Editor
{
private SerializedProperty _copySourceProperty;
private SerializedProperty _paddingWidthProperty;
private SerializedProperty _paddingHeightProperty;
protected void OnEnable()
{
_paddingWidthProperty = serializedObject.FindProperty("PaddingWidth");
_paddingHeightProperty = serializedObject.FindProperty("PaddingHeight");
_copySourceProperty = serializedObject.FindProperty("CopySource");
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_copySourceProperty);
EditorGUILayout.PropertyField(_paddingWidthProperty);
EditorGUILayout.PropertyField(_paddingHeightProperty);
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
}*/
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 44df26ca5be5b5c468b5090cbe3df8ab
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,34 @@
using UnityEditor;
namespace SRF.UI.Editor
{
[CustomEditor(typeof (CopyPreferredSize))]
[CanEditMultipleObjects]
public class CopyPreferredSizeEditor : UnityEditor.Editor
{
private SerializedProperty _copySourceProperty;
private SerializedProperty _paddingHeightProperty;
private SerializedProperty _paddingWidthProperty;
protected void OnEnable()
{
_paddingWidthProperty = serializedObject.FindProperty("PaddingWidth");
_paddingHeightProperty = serializedObject.FindProperty("PaddingHeight");
_copySourceProperty = serializedObject.FindProperty("CopySource");
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_copySourceProperty);
EditorGUILayout.PropertyField(_paddingWidthProperty);
EditorGUILayout.PropertyField(_paddingHeightProperty);
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 776c60ba14d0d0242968c3258a3ba16c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,31 @@
using UnityEditor;
namespace SRF.UI.Editor
{
[CustomEditor(typeof(CopyPreferredSizes))]
[CanEditMultipleObjects]
public class CopyPreferredSizesEditor : UnityEditor.Editor
{
private SerializedProperty _copySourcesProperty;
private SerializedProperty _operationProperty;
protected void OnEnable()
{
_copySourcesProperty = serializedObject.FindProperty("CopySources");
_operationProperty = serializedObject.FindProperty("Operation");
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_operationProperty);
EditorGUILayout.PropertyField(_copySourcesProperty);
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 393fb435a5c8c8043a1cbc34b977e315
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEditor;
using UnityEditor.UI;
namespace SRF.UI.Editor
{
[CustomEditor(typeof (LongPressButton), true)]
[CanEditMultipleObjects]
public class LongPressButtonEditor : ButtonEditor
{
private SerializedProperty _onLongPressProperty;
protected override void OnEnable()
{
base.OnEnable();
_onLongPressProperty = serializedObject.FindProperty("_onLongPress");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space();
serializedObject.Update();
EditorGUILayout.PropertyField(_onLongPressProperty);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1d57f229ac662764aa4508a0d42ddede
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,32 @@
using UnityEditor;
using UnityEditor.UI;
namespace SRF.UI.Editor
{
[CustomEditor(typeof (SRNumberButton))]
[CanEditMultipleObjects]
public class SRNumberButtonEditor : ButtonEditor
{
private SerializedProperty _amountProperty;
private SerializedProperty _targetFieldProperty;
protected override void OnEnable()
{
base.OnEnable();
_targetFieldProperty = serializedObject.FindProperty("TargetField");
_amountProperty = serializedObject.FindProperty("Amount");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space();
serializedObject.Update();
EditorGUILayout.PropertyField(_targetFieldProperty);
EditorGUILayout.PropertyField(_amountProperty);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0d1845f798a1b5a47af337e37e463641
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,10 @@
{
"name": "StompyRobot.SRF.Editor",
"references": [
"StompyRobot.SRF"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": []
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 714123ebf07616740963b992cf10f84c
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace SRF.UI.Editor
{
[CustomEditor(typeof (StyleComponent))]
[CanEditMultipleObjects]
public class StyleComponentEditor : UnityEditor.Editor
{
private SerializedProperty _styleKeyProperty;
protected void OnEnable()
{
_styleKeyProperty = serializedObject.FindProperty("_styleKey");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var styleComponent = serializedObject.targetObject as StyleComponent;
if (styleComponent == null)
{
Debug.LogWarning("Target is null, expected StyleComponent");
return;
}
var styleRoot = styleComponent.GetComponentInParent<StyleRoot>();
if (styleRoot == null)
{
EditorGUILayout.HelpBox("There must be a StyleRoot component above this object in the hierarchy.",
MessageType.Error,
true);
return;
}
var styleSheet = styleRoot.StyleSheet;
if (styleSheet == null)
{
EditorGUILayout.HelpBox("Style Root has no stylesheet set.", MessageType.Warning);
EditorGUILayout.Popup("Key", 0,
new[] {string.IsNullOrEmpty(styleComponent.StyleKey) ? "--" : styleComponent.StyleKey});
return;
}
var options = styleRoot.StyleSheet.GetStyleKeys(true).ToList();
var index = _styleKeyProperty.hasMultipleDifferentValues
? 0
: options.IndexOf(_styleKeyProperty.stringValue) + 1;
options.Insert(0, "--");
EditorGUILayout.Separator();
GUI.enabled = _styleKeyProperty.editable;
var newIndex = EditorGUILayout.Popup("Key", index, options.ToArray());
GUI.enabled = true;
if (newIndex != index)
{
_styleKeyProperty.stringValue = "";
_styleKeyProperty.stringValue = newIndex == 0 ? "" : options[newIndex];
}
if (serializedObject.ApplyModifiedProperties())
{
foreach (var o in serializedObject.targetObjects)
{
var c = o as StyleComponent;
c.Refresh(true);
}
_styleKeyProperty.serializedObject.Update();
}
EditorGUILayout.Separator();
GUILayout.BeginHorizontal();
if (GUILayout.Button("Open StyleSheet"))
{
Selection.activeObject = styleRoot.StyleSheet;
}
EditorGUILayout.Separator();
if (GUILayout.Button("Select StyleRoot"))
{
Selection.activeGameObject = styleRoot.gameObject;
}
GUILayout.EndHorizontal();
EditorGUILayout.Separator();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ffea2a0fd78a7484f88b5b877c0d6659
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,178 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace SRF.UI.Editor
{
[CustomEditor(typeof (StyleSheet))]
public class StyleSheetEditor : UnityEditor.Editor
{
public const float ColourColumnWidth = 40f;
public const float OverrideColumnWidth = 20f;
private string _newKeyField = "";
public override void OnInspectorGUI()
{
var styleSheet = target as StyleSheet;
if (styleSheet == null)
{
Debug.LogWarning("Expected target to be StyleSheer", target);
return;
}
var parentStyleSheet = styleSheet.Parent;
styleSheet.Parent =
EditorGUILayout.ObjectField("Parent", styleSheet.Parent, typeof (StyleSheet), false) as StyleSheet;
EditorGUILayout.Separator();
EditorGUILayout.Separator();
EditorGUILayout.BeginVertical();
// Draw table header
EditorGUILayout.BeginHorizontal();
GUILayout.Space(OverrideColumnWidth);
GUILayout.Label("Name");
GUILayout.Label("Img", GUILayout.Width(ColourColumnWidth));
GUILayout.Label("Norm.", GUILayout.Width(ColourColumnWidth));
GUILayout.Label("Hov.", GUILayout.Width(ColourColumnWidth));
GUILayout.Label("Actv.", GUILayout.Width(ColourColumnWidth));
GUILayout.Label("Dsbld.", GUILayout.Width(ColourColumnWidth));
EditorGUILayout.EndHorizontal();
EditorGUILayout.Separator();
var keys = styleSheet.GetStyleKeys(false);
if (parentStyleSheet != null)
{
keys = keys.Union(parentStyleSheet.GetStyleKeys());
}
// Draw rows
foreach (var key in keys)
{
// Style from the current stylesheet
var style = styleSheet.GetStyle(key, false);
// Style from the parent stylesheet
Style parentStyle = null;
if (parentStyleSheet != null)
{
parentStyle = parentStyleSheet.GetStyle(key, true);
}
EditorGUILayout.BeginHorizontal();
var canEdit = style != null;
// If there is a parent stylesheet, and the parent contains this key
if (parentStyleSheet != null && parentStyle != null)
{
var overrideParent = GUILayout.Toggle(style != null, "", GUILayout.Width(OverrideColumnWidth));
if (overrideParent && style == null)
{
// Copy the style to the current stylesheet
Undo.RecordObject(styleSheet, "Override Style");
styleSheet.AddStyle(key);
style = styleSheet.GetStyle(key, false);
style.CopyFrom(parentStyle);
EditorUtility.SetDirty(styleSheet);
canEdit = true;
}
else if (!overrideParent && style != null)
{
Undo.RecordObject(styleSheet, "Delete Style");
styleSheet.DeleteStyle(key);
style = null;
EditorUtility.SetDirty(styleSheet);
canEdit = false;
}
}
else
{
// Otherwise display a delete button
if (GUILayout.Button("X", GUILayout.Width(OverrideColumnWidth)))
{
Undo.RecordObject(styleSheet, "Delete Style");
styleSheet.DeleteStyle(key);
EditorUtility.SetDirty(styleSheet);
continue;
}
}
GUI.enabled = canEdit;
GUILayout.Label(key);
EditorGUI.BeginChangeCheck();
var img =
EditorGUILayout.ObjectField(style != null ? style.Image : parentStyle.Image, typeof (Sprite), false,
GUILayout.Width(ColourColumnWidth)) as Sprite;
var normalColor = EditorGUILayout.ColorField(
style != null ? style.NormalColor : parentStyle.NormalColor,
GUILayout.Width(ColourColumnWidth));
var hoverColor = EditorGUILayout.ColorField(style != null ? style.HoverColor : parentStyle.HoverColor,
GUILayout.Width(ColourColumnWidth));
var activeColor = EditorGUILayout.ColorField(
style != null ? style.ActiveColor : parentStyle.ActiveColor,
GUILayout.Width(ColourColumnWidth));
var disabledColor =
EditorGUILayout.ColorField(style != null ? style.DisabledColor : parentStyle.DisabledColor,
GUILayout.Width(ColourColumnWidth));
if (EditorGUI.EndChangeCheck() && canEdit)
{
Undo.RecordObject(styleSheet, "Update Style");
style.Image = img;
style.NormalColor = normalColor;
style.HoverColor = hoverColor;
style.ActiveColor = activeColor;
style.DisabledColor = disabledColor;
EditorUtility.SetDirty(styleSheet);
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
EditorGUILayout.Separator();
EditorGUILayout.BeginHorizontal();
GUILayout.Label("New Style");
_newKeyField = EditorGUILayout.TextField(_newKeyField);
GUI.enabled = !string.IsNullOrEmpty(_newKeyField) && styleSheet.GetStyle(_newKeyField) == null;
if (GUILayout.Button("Add"))
{
Undo.RecordObject(styleSheet, "Add Style");
styleSheet.AddStyle(_newKeyField);
EditorUtility.SetDirty(styleSheet);
_newKeyField = "";
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7cc490d54f84d704f90e31d72e293018
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,71 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// Instantly sets colour to FlashColor on pointer down, then fades back to DefaultColour once pointer is released.
/// </summary>
[AddComponentMenu(ComponentMenuPaths.FlashGraphic)]
[ExecuteInEditMode]
public class FlashGraphic : UIBehaviour, IPointerDownHandler, IPointerUpHandler
{
public float DecayTime = 0.15f;
public Color DefaultColor = new Color(1, 1, 1, 0);
public Color FlashColor = Color.white;
public Graphic Target;
private bool _isHoldingUntilNextPress;
public void OnPointerDown(PointerEventData eventData)
{
Target.CrossFadeColor(FlashColor, 0f, true, true);
_isHoldingUntilNextPress = false;
}
public void OnPointerUp(PointerEventData eventData)
{
if (!_isHoldingUntilNextPress)
{
Target.CrossFadeColor(DefaultColor, DecayTime, true, true);
}
}
protected override void OnEnable()
{
base.OnEnable();
if (!_isHoldingUntilNextPress)
{
Target.CrossFadeColor(DefaultColor, 0f, true, true);
}
}
#if UNITY_EDITOR
protected void Update()
{
if (!Application.isPlaying && Target != null)
{
Target.CrossFadeColor(DefaultColor, 0, true, true);
}
}
#endif
public void Flash()
{
Target.CrossFadeColor(FlashColor, 0f, true, true);
Target.CrossFadeColor(DefaultColor, DecayTime, true, true);
_isHoldingUntilNextPress = false;
}
public void FlashAndHoldUntilNextPress()
{
Target.CrossFadeColor(FlashColor, 0f, true, true);
_isHoldingUntilNextPress = true;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 95878e800ddd366418edfb56a22f9d56
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,48 @@
namespace SRF.UI
{
using Internal;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof (Graphic))]
[ExecuteInEditMode]
[AddComponentMenu(ComponentMenuPaths.InheritColour)]
public class InheritColour : SRMonoBehaviour
{
private Graphic _graphic;
public Graphic From;
private Graphic Graphic
{
get
{
if (_graphic == null)
{
_graphic = GetComponent<Graphic>();
}
return _graphic;
}
}
private void Refresh()
{
if (From == null)
{
return;
}
Graphic.color = From.canvasRenderer.GetColor();
}
private void Update()
{
Refresh();
}
private void Start()
{
Refresh();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5ed84aa42fb48c9458d3942c1d059055
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: e77c380334ccc0d438d07473a296a1cc
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,304 @@
namespace SRF.UI.Layout
{
using System.Collections.Generic;
using Internal;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Layout Group controller that arranges children in rows, fitting as many on a line until total width exceeds parent
/// bounds
/// </summary>
[AddComponentMenu(ComponentMenuPaths.FlowLayoutGroup)]
public class FlowLayoutGroup : LayoutGroup
{
/// <summary>
/// Holds the rects that will make up the current row being processed
/// </summary>
private readonly IList<RectTransform> _rowList = new List<RectTransform>();
private float _layoutHeight;
public bool ChildForceExpandHeight = false;
public bool ChildForceExpandWidth = false;
public float Spacing = 0f;
protected bool IsCenterAlign
{
get
{
return childAlignment == TextAnchor.LowerCenter || childAlignment == TextAnchor.MiddleCenter ||
childAlignment == TextAnchor.UpperCenter;
}
}
protected bool IsRightAlign
{
get
{
return childAlignment == TextAnchor.LowerRight || childAlignment == TextAnchor.MiddleRight ||
childAlignment == TextAnchor.UpperRight;
}
}
protected bool IsMiddleAlign
{
get
{
return childAlignment == TextAnchor.MiddleLeft || childAlignment == TextAnchor.MiddleRight ||
childAlignment == TextAnchor.MiddleCenter;
}
}
protected bool IsLowerAlign
{
get
{
return childAlignment == TextAnchor.LowerLeft || childAlignment == TextAnchor.LowerRight ||
childAlignment == TextAnchor.LowerCenter;
}
}
public override void CalculateLayoutInputHorizontal()
{
base.CalculateLayoutInputHorizontal();
var minWidth = GetGreatestMinimumChildWidth() + padding.left + padding.right;
SetLayoutInputForAxis(minWidth, -1, -1, 0);
}
public override void SetLayoutHorizontal()
{
SetLayout(rectTransform.rect.width, 0, false);
}
public override void SetLayoutVertical()
{
SetLayout(rectTransform.rect.width, 1, false);
}
public override void CalculateLayoutInputVertical()
{
_layoutHeight = SetLayout(rectTransform.rect.width, 1, true);
}
/// <summary>
/// Main layout method
/// </summary>
/// <param name="width">Width to calculate the layout with</param>
/// <param name="axis">0 for horizontal axis, 1 for vertical</param>
/// <param name="layoutInput">If true, sets the layout input for the axis. If false, sets child position for axis</param>
public float SetLayout(float width, int axis, bool layoutInput)
{
var groupHeight = rectTransform.rect.height;
// Width that is available after padding is subtracted
var workingWidth = rectTransform.rect.width - padding.left - padding.right;
// Accumulates the total height of the rows, including spacing and padding.
var yOffset = IsLowerAlign ? padding.bottom : (float)padding.top;
var currentRowWidth = 0f;
var currentRowHeight = 0f;
for (var i = 0; i < rectChildren.Count; i++)
{
// LowerAlign works from back to front
var index = IsLowerAlign ? rectChildren.Count - 1 - i : i;
var child = rectChildren[index];
var childWidth = LayoutUtility.GetPreferredSize(child, 0);
var childHeight = LayoutUtility.GetPreferredSize(child, 1);
// Max child width is layout group with - padding
childWidth = Mathf.Min(childWidth, workingWidth);
// Apply spacing if not the first element in a row
if (_rowList.Count > 0)
{
currentRowWidth += Spacing;
}
// If adding this element would exceed the bounds of the row,
// go to a new line after processing the current row
if (currentRowWidth + childWidth > workingWidth)
{
// Undo spacing addition if we're moving to a new line (Spacing is not applied on edges)
currentRowWidth -= Spacing;
// Process current row elements positioning
if (!layoutInput)
{
var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis);
}
// Clear existing row
_rowList.Clear();
// Add the current row height to total height accumulator, and reset to 0 for the next row
yOffset += currentRowHeight;
yOffset += Spacing;
currentRowHeight = 0;
currentRowWidth = 0;
}
currentRowWidth += childWidth;
_rowList.Add(child);
// We need the largest element height to determine the starting position of the next line
if (childHeight > currentRowHeight)
{
currentRowHeight = childHeight;
}
}
if (!layoutInput)
{
var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
// Layout the final row
LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis);
}
_rowList.Clear();
// Add the last rows height to the height accumulator
yOffset += currentRowHeight;
yOffset += IsLowerAlign ? padding.top : padding.bottom;
if (layoutInput)
{
if (axis == 1)
{
SetLayoutInputForAxis(yOffset, yOffset, -1, axis);
}
}
return yOffset;
}
private float CalculateRowVerticalOffset(float groupHeight, float yOffset, float currentRowHeight)
{
float h;
if (IsLowerAlign)
{
h = groupHeight - yOffset - currentRowHeight;
}
else if (IsMiddleAlign)
{
h = groupHeight * 0.5f - _layoutHeight * 0.5f + yOffset;
}
else
{
h = yOffset;
}
return h;
}
protected void LayoutRow(IList<RectTransform> contents, float rowWidth, float rowHeight, float maxWidth,
float xOffset, float yOffset, int axis)
{
var xPos = xOffset;
if (!ChildForceExpandWidth && IsCenterAlign)
{
xPos += (maxWidth - rowWidth) * 0.5f;
}
else if (!ChildForceExpandWidth && IsRightAlign)
{
xPos += (maxWidth - rowWidth);
}
var extraWidth = 0f;
if (ChildForceExpandWidth)
{
var flexibleChildCount = 0;
for (var i = 0; i < _rowList.Count; i++)
{
if (LayoutUtility.GetFlexibleWidth(_rowList[i]) > 0f)
{
flexibleChildCount++;
}
}
if (flexibleChildCount > 0)
{
extraWidth = (maxWidth - rowWidth) / flexibleChildCount;
}
}
for (var j = 0; j < _rowList.Count; j++)
{
var index = IsLowerAlign ? _rowList.Count - 1 - j : j;
var rowChild = _rowList[index];
var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0);
if (LayoutUtility.GetFlexibleWidth(rowChild) > 0f)
{
rowChildWidth += extraWidth;
}
var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1);
if (ChildForceExpandHeight)
{
rowChildHeight = rowHeight;
}
rowChildWidth = Mathf.Min(rowChildWidth, maxWidth);
var yPos = yOffset;
if (IsMiddleAlign)
{
yPos += (rowHeight - rowChildHeight) * 0.5f;
}
else if (IsLowerAlign)
{
yPos += (rowHeight - rowChildHeight);
}
if (axis == 0)
{
#if UNITY_2019_1
SetChildAlongAxis(rowChild, 0, 1f, xPos, rowChildWidth);
#else
SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth);
#endif
}
else
{
#if UNITY_2019_1
SetChildAlongAxis(rowChild, 1, 1f, yPos, rowChildHeight);
#else
SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight);
#endif
}
xPos += rowChildWidth + Spacing;
}
}
public float GetGreatestMinimumChildWidth()
{
var max = 0f;
for (var i = 0; i < rectChildren.Count; i++)
{
var w = LayoutUtility.GetMinWidth(rectChildren[i]);
max = Mathf.Max(w, max);
}
return max;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f3a5149e46522d84cb8079537220a929
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

Some files were not shown because too many files have changed in this diff Show More