2D-Platformer/Assets/Plugins/Light2D/Scripts/Util.cs
2022-02-12 12:53:50 +02:00

633 lines
No EOL
18 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
namespace Light2D
{
/// <summary>
/// Bunch of utility functions that could be userful sometimes.
/// </summary>
public static class Util
{
#if UNITY_METRO && !UNITY_EDITOR
static Windows.Devices.Input.TouchCapabilities touchCaps = new Windows.Devices.Input.TouchCapabilities();
#endif
public static bool isTouchscreen
{
get
{
return
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER
false;
#elif UNITY_METRO
touchCaps.TouchPresent != 0;
#else
true;
#endif
}
}
public static void SafeIterateBackward<T>(this IList<T> list, Action<T> action)
{
for (int i = list.Count - 1; i >= 0; i--)
{
action(list[i]);
}
}
public static void SafeIterateBackward<T>(this IList<T> list, Action<T, int> action)
{
for (int i = list.Count - 1; i >= 0; i--)
{
if (i >= list.Count) continue;
action(list[i], i);
}
}
public static void SafeIterateBackward<T>(this IEnumerable<T> enumerable, Action<T> action)
{
var list = enumerable.ToArray();
for (int i = list.Length - 1; i >= 0; i--)
{
action(list[i]);
}
}
public static void SafeIterateBackward<T>(this IEnumerable<T> enumerable, Action<T, int> action)
{
var list = enumerable.ToArray();
for (int i = list.Length - 1; i >= 0; i--)
{
action(list[i], i);
}
}
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var obj in enumerable)
{
action(obj);
yield return obj;
}
}
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
{
var i = 0;
foreach (var obj in enumerable)
{
action(obj, i);
yield return obj;
i++;
}
}
public static IEnumerable<T> GetComponentsInChildRecursive<T>(this GameObject root) where T : Component
{
return root.GetChildRecursive().SelectMany(go => go.GetComponents<T>());
}
public static IEnumerable<GameObject> GetChildRecursive(this GameObject root)
{
foreach (Transform child in root.transform)
{
var cgo = child.gameObject;
yield return cgo;
foreach (var gameObject in cgo.GetChildRecursive())
yield return gameObject;
}
}
public static Rigidbody2D GetRigidbodyUnderCursor()
{
var mousePos = GetMousePosInUnits();
var click = Physics2D.OverlapPoint(mousePos);
return click != null ? click.attachedRigidbody : null;
}
public static Vector2 GetMousePosInUnits()
{
var mouse = Input.mousePosition;
var camera = Camera.main;
var mouseWorld = camera.ScreenToWorldPoint(
new Vector3(mouse.x, mouse.y, -camera.transform.position.z));
return mouseWorld;
}
public static Vector2 ScreenToWorld(Vector2 screen)
{
var camera = Camera.main;
var mouseWorld = camera.ScreenToWorldPoint(
new Vector3(screen.x, screen.y, -camera.transform.position.z));
return mouseWorld;
}
public static Vector2 WorldToScreen(Vector2 screen)
{
var camera = Camera.main;
var mouseWorld = camera.WorldToScreenPoint(
new Vector3(screen.x, screen.y, -camera.transform.position.z));
return mouseWorld;
}
public static GameObject Instantiate(GameObject prefab)
{
return (GameObject) Object.Instantiate(prefab);
}
public static T Instantiate<T>(GameObject prefab) where T : Component
{
return (Instantiate(prefab)).GetComponent<T>();
}
public static T Instantiate<T>(GameObject prefab, Vector3 position, Quaternion rotation)
where T : Component
{
return ((GameObject) Object.Instantiate(prefab, position, rotation)).GetComponent<T>();
}
public static float ClampAngle(float angle)
{
angle = Mathf.Repeat(angle, 360);
if (angle > 180) angle -= 360;
return angle;
}
public static float AngleZ(this Vector2 angle)
{
if (angle == Vector2.zero) return 0;
return Vector2.Angle(Vector2.up, angle)*Mathf.Sign(-angle.x);
}
public static float AngleZ(this Vector3 angle)
{
if (angle == Vector3.zero) return 0;
return Vector2.Angle(Vector2.up, angle)*Mathf.Sign(-angle.x);
}
public static float Proj(Vector2 vector, Vector2 onNormal)
{
return Vector2.Dot(vector, onNormal)*onNormal.magnitude;
}
public static float Cross(Vector2 lhs, Vector2 rhs)
{
return lhs.x*rhs.y - lhs.y*rhs.x;
}
public static void Destroy(UnityEngine.Object obj)
{
if (obj == null) return;
if (obj is GameObject)
((GameObject) obj).transform.parent = null;
#if UNITY_EDITOR
if (!Application.isPlaying)
GameObject.DestroyImmediate(obj);
else GameObject.Destroy(obj);
#else
GameObject.Destroy(obj);
#endif
}
public static T RandomElement<T>(this IList<T> coll)
{
var index = Random.Range(0, coll.Count);
return coll[index];
}
public static T RandomElement<T>(this T[] coll)
{
var index = Random.Range(0, coll.Length);
return coll[index];
}
public static Vector2 RotateZ(this Vector2 v, float angle)
{
float sin = Mathf.Sin(angle*Mathf.Deg2Rad);
float cos = Mathf.Cos(angle*Mathf.Deg2Rad);
float tx = v.x;
float ty = v.y;
return new Vector2((cos*tx) - (sin*ty), (cos*ty) + (sin*tx));
}
public static Vector3 RotateZ(this Vector3 v, float angle)
{
float sin = Mathf.Sin(angle);
float cos = Mathf.Cos(angle);
float tx = v.x;
float ty = v.y;
return new Vector3((cos*tx) - (sin*ty), (cos*ty) + (sin*tx), v.z);
}
public static Vector2 Rotate90(this Vector2 v)
{
return new Vector2(-v.y, v.x);
}
public static void Log(params object[] vals)
{
var sb = new StringBuilder();
for (int i = 0; i < vals.Length; i++)
{
if (i != 0) sb.Append(", ");
sb.Append(vals[i]);
}
Debug.Log(sb.ToString());
}
public static void Log(UnityEngine.Object context, params object[] vals)
{
var sb = new StringBuilder();
for (int i = 0; i < vals.Length; i++)
{
if (i != 0) sb.Append(", ");
sb.Append(vals[i]);
}
Debug.Log(sb.ToString(), context);
}
public static void LogArray<T>(IEnumerable<T> enumerable)
{
var sb = new StringBuilder();
var vals = enumerable.ToArray();
for (int i = 0; i < vals.Length; i++)
{
sb.Append(i);
sb.Append(": ");
sb.Append(vals[i]);
sb.AppendLine(";");
}
Debug.Log(sb.ToString());
}
public static Color Set(this Color color, int channel, float value)
{
color[channel] = value;
return color;
}
public static Color WithAlpha(this Color color, float value)
{
color.a = value;
return color;
}
public static Vector3 WithX(this Vector3 vec, float value)
{
vec.x = value;
return vec;
}
public static Vector3 WithXY(this Vector3 vec, Vector2 xy)
{
vec.x = xy.x;
vec.y = xy.y;
return vec;
}
public static Vector3 WithXY(this Vector3 vec, float x, float y)
{
vec.x = x;
vec.y = y;
return vec;
}
public static Vector3 WithY(this Vector3 vec, float value)
{
vec.y = value;
return vec;
}
public static Vector3 WithZ(this Vector3 vec, float value)
{
vec.z = value;
return vec;
}
#if !UNITY_WINRT
public static void Serialize<T>(string path, T obj) where T : class
{
using (var stream = File.Create(path))
{
var serializer = new XmlSerializer(typeof (T));
var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
serializer.Serialize(xmlWriter, obj);
}
}
public static byte[] Serialize<T>(T obj)
{
using (var stream = new MemoryStream())
{
var serializer = new XmlSerializer(typeof (T));
var xmlWriter = new XmlTextWriter(stream, Encoding.UTF8);
serializer.Serialize(xmlWriter, obj);
return stream.ToArray();
}
}
public static T Deserialize<T>(string path) where T : class
{
using (var stream = File.OpenRead(path))
{
var serializer = new XmlSerializer(typeof (T));
var fromFile = serializer.Deserialize(stream) as T;
return fromFile;
}
}
public static T Deserialize<T>(byte[] data)
{
try
{
using (var stream = new MemoryStream(data))
{
var serializer = new XmlSerializer(typeof (T));
var fromFile = (T) serializer.Deserialize(stream);
return fromFile;
}
}
catch (Exception ex)
{
Debug.LogError(ex);
return default(T);
}
}
#endif
public static int IndexOfMin<T>(this List<T> list, Func<T, float> pred)
{
int minId = -1;
float minVal = float.MaxValue;
for (int i = 0; i < list.Count; i++)
{
var obj = list[i];
var val = pred(obj);
if (val < minVal)
{
minId = i;
minVal = val;
}
}
return minId;
}
public static T MinBy<T>(this IEnumerable<T> list, Func<T, float> pred)
{
T minObj = default(T);
float minVal = float.MaxValue;
bool isEmpty = true;
foreach (var obj in list)
{
var val = pred(obj);
if (val < minVal)
{
minObj = obj;
minVal = val;
}
isEmpty = false;
}
if (isEmpty) throw new ArgumentException();
return minObj;
}
public static T MinByOrDefault<T>(this IEnumerable<T> list, Func<T, float> pred)
{
T minObj = default(T);
float minVal = float.MaxValue;
bool isEmpty = true;
foreach (var obj in list)
{
var val = pred(obj);
if (val < minVal)
{
minObj = obj;
minVal = val;
}
isEmpty = false;
}
if (isEmpty) return default (T);
return minObj;
}
public static Vector2 NearestPointOnLine(this Vector2 c, Vector2 a, Vector2 b)
{
var v = (a - b).normalized;
return b + v*Vector2.Dot(v, c - b);
}
public static float DistToLine(this Vector2 c, Vector2 a, Vector2 b)
{
var n = new Vector2(b.y - a.y, a.x - b.x).normalized;
var v = c - a;
return Vector2.Dot(n, v);
}
public static bool GetTouchByFingerId(int fingerId, out Touch resultTouch)
{
if (fingerId == -1)
{
resultTouch = new Touch();
return false;
}
for (int i = 0; i < Input.touchCount; i++)
{
var touch = Input.GetTouch(i);
if (touch.fingerId == fingerId)
{
resultTouch = touch;
return true;
}
}
resultTouch = new Touch();
return false;
}
public static float ClampAngle(float angle, float min, float max)
{
angle = Mathf.Repeat(angle, 360);
min = Mathf.Repeat(min, 360);
max = Mathf.Repeat(max, 360);
if (min > max)
{
if (angle > min || angle < max) return angle;
return angle > (min + max)/2f ? min : max;
}
if (angle > min && angle < max) return angle;
return angle < min ? min : max;
}
public static int Hash<T>(T v1, T v2, T v3, T v4)
{
int hash = 23;
hash = hash*31 + v1.GetHashCode();
hash = hash*31 + v2.GetHashCode();
hash = hash*31 + v3.GetHashCode();
hash = hash*31 + v4.GetHashCode();
return hash;
}
public static int Hash<T>(T v1, T v2, T v3)
{
int hash = 23;
hash = hash*31 + v1.GetHashCode();
hash = hash*31 + v2.GetHashCode();
hash = hash*31 + v3.GetHashCode();
return hash;
}
public static int Hash<T>(T v1, T v2)
{
int hash = 23;
hash = hash*31 + v1.GetHashCode();
hash = hash*31 + v2.GetHashCode();
return hash;
}
public static int Hash<T>(params T[] els)
{
int hash = 23;
for (int i = 0; i < els.Length; i++)
hash = hash*31 + els[i].GetHashCode();
return hash;
}
public static Vector4 Div(this Vector4 vec, Vector4 div)
{
return new Vector4(vec.x/div.x, vec.y/div.y, vec.z/div.z, vec.w/div.w);
}
public static Vector3 Div(this Vector3 vec, Vector3 div)
{
return new Vector3(vec.x/div.x, vec.y/div.y, vec.z/div.z);
}
public static Vector2 Div(this Vector2 vec, Vector2 div)
{
return new Vector2(vec.x/div.x, vec.y/div.y);
}
public static Vector4 Mul(this Vector4 v1, Vector4 v2)
{
return Vector4.Scale(v1, v2);
}
public static Vector3 Mul(this Vector3 v1, Vector3 v2)
{
return Vector3.Scale(v1, v2);
}
public static Vector2 Mul(this Vector2 v1, Vector2 v2)
{
return Vector2.Scale(v1, v2);
}
public static float DecodeFloatRGBA(Vector3 enc)
{
enc = new Vector3((byte) (enc.x*254f), (byte) (enc.y*254f), (byte) (enc.z*254f))/255f;
var kDecodeDot = new Vector4(1f, 1/255f, 1/65025f);
var result = Vector3.Dot(enc, kDecodeDot);
return result;
}
public static Vector4 EncodeFloatRGBA(float v)
{
var kEncodeMul = new Vector3(1.0f, 255.0f, 65025.0f);
var enc = kEncodeMul*v;
enc = new Vector3(
enc.x - Mathf.Floor(enc.x), enc.y - Mathf.Floor(enc.y),
enc.z - Mathf.Floor(enc.z));
return enc;
}
#if UNITY_EDITOR
public static bool IsSceneViewFocused
{
get
{
return SceneView.currentDrawingSceneView != null &&
SceneView.currentDrawingSceneView == EditorWindow.focusedWindow;
}
}
#endif
public static bool FastEquals(this Matrix4x4 m1, Matrix4x4 m2)
{
return m1.m00 == m2.m00 && m1.m01 == m2.m01 && m1.m02 == m2.m02 && m1.m03 == m2.m03 &&
m1.m10 == m2.m10 && m1.m11 == m2.m11 && m1.m12 == m2.m12 && m1.m13 == m2.m13 &&
m1.m20 == m2.m20 && m1.m21 == m2.m21 && m1.m22 == m2.m22 && m1.m23 == m2.m23 &&
m1.m30 == m2.m30 && m1.m31 == m2.m31 && m1.m32 == m2.m32 && m1.m33 == m2.m33;
}
public static bool Equals(this Color32 col1, Color32 col2)
{
return col1.r == col2.r && col1.g == col2.g && col1.b == col2.b && col1.a == col2.a;
}
}
internal class GenericEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> distinct;
private Func<T, int> hash;
public GenericEqualityComparer(Func<T, T, bool> distinct, Func<T, int> hash)
{
this.distinct = distinct;
this.hash = hash;
}
public bool Equals(T x, T y)
{
if (System.Object.ReferenceEquals(x, y))
{
return true;
}
if (System.Object.ReferenceEquals(x, null) ||
System.Object.ReferenceEquals(y, null))
{
return false;
}
return distinct(x, y);
}
public int GetHashCode(T obj)
{
return hash(obj);
}
}
internal class GenericComparer<T> : IComparer<T>
{
private Func<T, T, int> comparer;
public GenericComparer(Func<T, T, int> comparer)
{
this.comparer = comparer;
}
public int Compare(T x, T y)
{
return comparer(x, y);
}
}
public class ReadOnlyAttribute : PropertyAttribute
{
}
}