diff --git a/Runtime/ABase/Extension/Extension/ArrayExtensions.cs b/Runtime/ABase/Extension/Extension/ArrayExtensions.cs new file mode 100644 index 0000000..7a02a4a --- /dev/null +++ b/Runtime/ABase/Extension/Extension/ArrayExtensions.cs @@ -0,0 +1,56 @@ +using UnityEngine; + +[UnityEngine.Scripting.Preserve] +public static class ArrayExtensions +{ + /// + /// 从数组中随机取一个元素。 + /// + public static T Random(this T[] items) + { + System.Random rnd = new System.Random(); + if (items.Length > 0) + { + return items[rnd.Next(0, items.Length)]; + } + + return default; + } + + /// + /// 获取与目标值最接近的元素索引。 + /// + public static int ClosestIndex(this int[] array, int value) + { + int closestIndex = 0; + int minDifference = Mathf.Abs(array[0] - value); + for (int i = 1; i < array.Length; i++) + { + int difference = Mathf.Abs(array[i] - value); + if (difference < minDifference) + { + minDifference = difference; + closestIndex = i; + } + } + + return closestIndex; + } +} + +namespace AlicizaX +{ + [UnityEngine.Scripting.Preserve] + public static class MinMaxExtensions + { + public static float Random(this MinMax minMax) + { + return UnityEngine.Random.Range(minMax.RealMin, minMax.RealMax); + } + + public static int Random(this MinMaxInt minMax) + { + return UnityEngine.Random.Range(minMax.RealMin, minMax.RealMax); + } + } +} diff --git a/Runtime/ABase/Helper/RandomHelper.cs.meta b/Runtime/ABase/Extension/Extension/ArrayExtensions.cs.meta similarity index 69% rename from Runtime/ABase/Helper/RandomHelper.cs.meta rename to Runtime/ABase/Extension/Extension/ArrayExtensions.cs.meta index 488ca5d..3d8ee3d 100644 --- a/Runtime/ABase/Helper/RandomHelper.cs.meta +++ b/Runtime/ABase/Extension/Extension/ArrayExtensions.cs.meta @@ -1,8 +1,7 @@ fileFormatVersion: 2 -guid: c7bd0b921d0715a4caa7a59d261e8803 -timeCreated: 1474942922 -licenseType: Pro +guid: ae1b3849ddfb58045a96ac9927218a73 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/Runtime/ABase/Extension/Extension/CollectionExtensions.cs b/Runtime/ABase/Extension/Extension/CollectionExtensions.cs index 1a48199..153c24e 100644 --- a/Runtime/ABase/Extension/Extension/CollectionExtensions.cs +++ b/Runtime/ABase/Extension/Extension/CollectionExtensions.cs @@ -145,4 +145,4 @@ namespace System.Collections.Generic } } } -} \ No newline at end of file +} diff --git a/Runtime/ABase/Helper/DistinctHelper.cs b/Runtime/ABase/Extension/Extension/EnumerableExtensions.cs similarity index 61% rename from Runtime/ABase/Helper/DistinctHelper.cs rename to Runtime/ABase/Extension/Extension/EnumerableExtensions.cs index 741c831..ab8b77f 100644 --- a/Runtime/ABase/Helper/DistinctHelper.cs +++ b/Runtime/ABase/Extension/Extension/EnumerableExtensions.cs @@ -1,27 +1,19 @@ using System; using System.Collections.Generic; +using System.Linq; namespace AlicizaX { - /// - /// 去重。帮助类 - /// [UnityEngine.Scripting.Preserve] - public static class DistinctHelper + public static class EnumerableExtensions { /// - /// 根据条件去重 + /// 根据指定键进行去重。 /// - /// - /// - /// - /// - /// [UnityEngine.Scripting.Preserve] public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { var identifiedKeys = new HashSet(); - foreach (var item in source) { if (identifiedKeys.Add(keySelector(item))) @@ -30,5 +22,13 @@ namespace AlicizaX } } } + + /// + /// 判断集合是否包含另一个集合中的所有元素。 + /// + public static bool ContainsAll(this IEnumerable source, IEnumerable values) + { + return !source.Except(values).Any(); + } } } diff --git a/Runtime/ABase/Extension/Extension/EnumerableExtensions.cs.meta b/Runtime/ABase/Extension/Extension/EnumerableExtensions.cs.meta new file mode 100644 index 0000000..40f725b --- /dev/null +++ b/Runtime/ABase/Extension/Extension/EnumerableExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6d80b4ea1444e5ab93a9ae1dbaa6946 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Extension/Extension/StringExtensions.cs b/Runtime/ABase/Extension/Extension/StringExtensions.cs index 3aefd4d..468f051 100644 --- a/Runtime/ABase/Extension/Extension/StringExtensions.cs +++ b/Runtime/ABase/Extension/Extension/StringExtensions.cs @@ -198,6 +198,30 @@ public static class StringExtension return string.Format(text, args); } + /// + /// 转换为标题格式。 + /// + public static string ToTitleCase(this string str) + { + return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower()); + } + + /// + /// 判断字符串是否为空。 + /// + public static bool IsEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + + /// + /// 返回当前字符串,若为空则返回备用值。 + /// + public static string Or(this string str, string otherwise) + { + return !string.IsNullOrEmpty(str) ? str : otherwise; + } + /// /// 将[\n、\t、\r、空格]替换为空,并返回 /// @@ -226,6 +250,87 @@ public static class StringExtension return self; } + /// + /// 替换起止字符之间的片段。 + /// + public static string ReplacePart(this string str, char start, char end, string replace) + { + int chStart = str.IndexOf(start); + int chEnd = str.IndexOf(end); + string old = str.Substring(chStart, chEnd - chStart + 1); + return str.Replace(old, replace); + } + + /// + /// 替换指定包裹标记中的内容。 + /// + public static string RegexReplaceTag(this string str, char start, char end, string tag, string replace) + { + Regex regex = new Regex($@"\{start}({tag})\{end}"); + if (regex.Match(str).Success) + { + return regex.Replace(str, replace); + } + + return str; + } + + /// + /// 读取起止字符之间的内容。 + /// + public static bool RegexGet(this string str, char start, char end, out string result) + { + string escapedStart = Regex.Escape(start.ToString()); + string escapedEnd = Regex.Escape(end.ToString()); + string pattern = $"{escapedStart}(.*?){escapedEnd}"; + + Match match = Regex.Match(str, pattern); + if (match.Success) + { + result = match.Groups[1].Value; + return true; + } + + result = string.Empty; + return false; + } + + /// + /// 读取所有起止字符之间的内容。 + /// + public static bool RegexGetMany(this string str, char start, char end, out string[] results) + { + string escapedStart = Regex.Escape(start.ToString()); + string escapedEnd = Regex.Escape(end.ToString()); + string pattern = $"{escapedStart}(.*?){escapedEnd}"; + + MatchCollection matches = Regex.Matches(str, pattern); + if (matches.Count > 0) + { + var matchList = new List(); + foreach (Match match in matches) + { + matchList.Add(match.Groups[1].Value); + } + + results = matchList.ToArray(); + return true; + } + + results = Array.Empty(); + return false; + } + + /// + /// 以单词为边界替换内容。 + /// + public static string RegexReplace(this string str, string word, string replace) + { + string escapedWord = Regex.Escape(word); + string pattern = $@"\b{escapedWord}\b"; + return Regex.Replace(str, pattern, replace); + } + public static int[] SplitToIntArray(this string str, char sep = '+') { if (string.IsNullOrEmpty(str)) @@ -328,4 +433,4 @@ public static class StringExtension return null; } -} \ No newline at end of file +} diff --git a/Runtime/ABase/Extension/UnityEngine.Common.meta b/Runtime/ABase/Extension/UnityEngine.Common.meta new file mode 100644 index 0000000..406bd64 --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a4c9cbd4e6d1ba84fb42b601118e51a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs new file mode 100644 index 0000000..9e841be --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs @@ -0,0 +1,148 @@ +using AlicizaX; +using UnityEngine.UI; + +namespace UnityEngine +{ + [UnityEngine.Scripting.Preserve] + public static class ColorExtensions + { + public static Color Alpha(this Color color, float alpha) + { + color.a = alpha; + return color; + } + + public static Color Lightness(this Color color, float lightness) + { + Color.RGBToHSV(color, out var hue, out var saturation, out var _); + return Color.HSVToRGB(hue, saturation, lightness); + } + } + + [UnityEngine.Scripting.Preserve] + public static class ImageExtensions + { + public static void Alpha(this Image image, float alpha) + { + Color color = image.color; + color.a = alpha; + image.color = color; + } + } + + [UnityEngine.Scripting.Preserve] + public static class AudioSourceExtensions + { + public static void SetSoundClip(this AudioSource audioSource, SoundClip soundClip, float volumeMul = 1f, bool play = false) + { + if (soundClip == null || soundClip.audioClip == null || audioSource == null) + { + return; + } + + if (audioSource.clip != soundClip.audioClip) + { + audioSource.clip = soundClip.audioClip; + } + + audioSource.volume = soundClip.volume * volumeMul; + if (play && !audioSource.isPlaying) + { + audioSource.Play(); + } + } + + public static void PlayOneShotSoundClip(this AudioSource audioSource, SoundClip soundClip, float volumeMul = 1f) + { + if (soundClip == null || soundClip.audioClip == null || audioSource == null) + { + return; + } + + audioSource.PlayOneShot(soundClip.audioClip, soundClip.volume * volumeMul); + } + } + + [UnityEngine.Scripting.Preserve] + public static class LayerMaskExtensions + { + public static bool CompareLayer(this LayerMask layerMask, int layer) + { + return layerMask == (layerMask | (1 << layer)); + } + } + + [UnityEngine.Scripting.Preserve] + public static class AnimatorExtensions + { + public static bool IsAnyPlaying(this Animator animator) + { + AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); + return (stateInfo.length + 0.1f > stateInfo.normalizedTime || animator.IsInTransition(0)) && !stateInfo.IsName("Default"); + } + } + + [UnityEngine.Scripting.Preserve] + public static class AngleExtensions + { + public static float FixAngle(this float angle, float min, float max) + { + if (angle < min) + { + angle += 360f; + } + + if (angle > max) + { + angle -= 360f; + } + + return angle; + } + + public static float FixAngle180(this float angle) + { + if (angle < -180f) + { + angle += 360f; + } + + if (angle > 180f) + { + angle -= 360f; + } + + return angle; + } + + public static float FixAngle(this float angle) + { + if (angle < -360f) + { + angle += 360f; + } + + if (angle > 360f) + { + angle -= 360f; + } + + return angle; + } + + public static float FixAngle360(this float angle) + { + if (angle < 0f) + { + angle += 360f; + } + + if (angle > 360f) + { + angle -= 360f; + } + + return angle; + } + } +} diff --git a/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs.meta b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs.meta new file mode 100644 index 0000000..47f1c99 --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Common/UnityEngine.CommonExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdcd89fb0474b6949b197c7da1cb81fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Extension/UnityEngage.GameObject.meta b/Runtime/ABase/Extension/UnityEngine.GameObject.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngage.GameObject.meta rename to Runtime/ABase/Extension/UnityEngine.GameObject.meta diff --git a/Runtime/ABase/Extension/UnityEngage.GameObject/ComponentExtensions.cs b/Runtime/ABase/Extension/UnityEngine.GameObject/ComponentExtensions.cs similarity index 100% rename from Runtime/ABase/Extension/UnityEngage.GameObject/ComponentExtensions.cs rename to Runtime/ABase/Extension/UnityEngine.GameObject/ComponentExtensions.cs diff --git a/Runtime/ABase/Extension/UnityEngage.GameObject/ComponentExtensions.cs.meta b/Runtime/ABase/Extension/UnityEngine.GameObject/ComponentExtensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngage.GameObject/ComponentExtensions.cs.meta rename to Runtime/ABase/Extension/UnityEngine.GameObject/ComponentExtensions.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngage.GameObject/UnityEngage.GameObjectExtension.cs b/Runtime/ABase/Extension/UnityEngine.GameObject/GameObjectExtensions.cs similarity index 76% rename from Runtime/ABase/Extension/UnityEngage.GameObject/UnityEngage.GameObjectExtension.cs rename to Runtime/ABase/Extension/UnityEngine.GameObject/GameObjectExtensions.cs index 1655000..597af4b 100644 --- a/Runtime/ABase/Extension/UnityEngage.GameObject/UnityEngage.GameObjectExtension.cs +++ b/Runtime/ABase/Extension/UnityEngine.GameObject/GameObjectExtensions.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace UnityEngine { - public static class UnityEngageGameObjectExtension + public static class GameObjectExtensions { public static void SafeDestroySelf( this Object obj) @@ -81,5 +81,31 @@ namespace UnityEngine return gameObject.scene.name != null; } + + /// + /// 设置对象下所有 MeshRenderer 的 rendering layer。 + /// + public static void SetRenderingLayer(this GameObject gameObject, uint layer, bool set = true) + { + if (layer > 31) + { + Debug.LogError("Invalid layer value. Must be between 0 and 31."); + return; + } + + uint layerMask = 1u << (int)layer; + foreach (MeshRenderer renderer in gameObject.GetComponentsInChildren()) + { + if (set) + { + renderer.renderingLayerMask |= layerMask; + } + else + { + renderer.renderingLayerMask &= ~layerMask; + } + } + } + } } diff --git a/Runtime/ABase/Extension/UnityEngage.GameObject/UnityEngage.GameObjectExtension.cs.meta b/Runtime/ABase/Extension/UnityEngine.GameObject/GameObjectExtensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngage.GameObject/UnityEngage.GameObjectExtension.cs.meta rename to Runtime/ABase/Extension/UnityEngine.GameObject/GameObjectExtensions.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngine.Transform/RectTransformExtensions.cs b/Runtime/ABase/Extension/UnityEngine.Transform/RectTransformExtensions.cs new file mode 100644 index 0000000..05d1440 --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Transform/RectTransformExtensions.cs @@ -0,0 +1,63 @@ +namespace UnityEngine +{ + [UnityEngine.Scripting.Preserve] + public static class RectTransformExtensions + { + //重置为全屏自适应UI + public static void ResetToFullScreen(this RectTransform self) + { + self.anchorMin = Vector2.zero; + self.anchorMax = Vector2.one; + self.anchoredPosition3D = Vector3.zero; + self.pivot = new Vector2(0.5f, 0.5f); + self.offsetMax = Vector2.zero; + self.offsetMin = Vector2.zero; + self.sizeDelta = Vector2.zero; + self.localEulerAngles = Vector3.zero; + self.localScale = Vector3.one; + } + + //重置位置与旋转 + public static void ResetLocalPosAndRot(this RectTransform self) + { + self.localPosition = Vector3.zero; + self.localRotation = Quaternion.identity; + } + + public static void SetWidth(this RectTransform rectTransform, float width) + { + Vector2 size = rectTransform.sizeDelta; + size.x = width; + rectTransform.sizeDelta = size; + } + + public static void SetHeight(this RectTransform rectTransform, float height) + { + Vector2 size = rectTransform.sizeDelta; + size.y = height; + rectTransform.sizeDelta = size; + } + + public static void SetAnchoredX(this RectTransform rectTransform, float x) + { + Vector2 position = rectTransform.anchoredPosition; + position.x = x; + rectTransform.anchoredPosition = position; + } + + public static void SetAnchoredY(this RectTransform rectTransform, float y) + { + Vector2 position = rectTransform.anchoredPosition; + position.y = y; + rectTransform.anchoredPosition = position; + } + + public static System.Collections.Generic.IEnumerable GetChildTransforms(this RectTransform rectTransform) + { + foreach (var item in rectTransform) + { + yield return item as RectTransform; + } + } + } +} diff --git a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.UIExtension.cs.meta b/Runtime/ABase/Extension/UnityEngine.Transform/RectTransformExtensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.UIExtension.cs.meta rename to Runtime/ABase/Extension/UnityEngine.Transform/RectTransformExtensions.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.TransformExtension.cs b/Runtime/ABase/Extension/UnityEngine.Transform/TransformExtensions.cs similarity index 99% rename from Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.TransformExtension.cs rename to Runtime/ABase/Extension/UnityEngine.Transform/TransformExtensions.cs index 34aea17..882cea7 100644 --- a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.TransformExtension.cs +++ b/Runtime/ABase/Extension/UnityEngine.Transform/TransformExtensions.cs @@ -3,7 +3,7 @@ using UnityEngine; namespace UnityEngine { [UnityEngine.Scripting.Preserve] - public static class UnityEngineTransformExtension + public static class TransformExtensions { /// /// 查找子节点的名称符合的 。 @@ -271,4 +271,4 @@ namespace UnityEngine } } } -} \ No newline at end of file +} diff --git a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.TransformExtension.cs.meta b/Runtime/ABase/Extension/UnityEngine.Transform/TransformExtensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.TransformExtension.cs.meta rename to Runtime/ABase/Extension/UnityEngine.Transform/TransformExtensions.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.UIExtension.cs b/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.UIExtension.cs deleted file mode 100644 index 19b12e1..0000000 --- a/Runtime/ABase/Extension/UnityEngine.Transform/UnityEngine.UIExtension.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace UnityEngine -{ - [UnityEngine.Scripting.Preserve] - public static class UnityEngine_UIExtension - { - //重置为全屏自适应UI - public static void ResetToFullScreen(this RectTransform self) - { - self.anchorMin = Vector2.zero; - self.anchorMax = Vector2.one; - self.anchoredPosition3D = Vector3.zero; - self.pivot = new Vector2(0.5f, 0.5f); - self.offsetMax = Vector2.zero; - self.offsetMin = Vector2.zero; - self.sizeDelta = Vector2.zero; - self.localEulerAngles = Vector3.zero; - self.localScale = Vector3.one; - } - - //重置位置与旋转 - public static void ResetLocalPosAndRot(this RectTransform self) - { - self.localPosition = Vector3.zero; - self.localRotation = Quaternion.identity; - } - } -} diff --git a/Runtime/ABase/Extension/UnityEngine.Vector2/UnityEngine.Vector2Extension.cs b/Runtime/ABase/Extension/UnityEngine.Vector2/UnityEngine.Vector2Extension.cs deleted file mode 100644 index 4d7548a..0000000 --- a/Runtime/ABase/Extension/UnityEngine.Vector2/UnityEngine.Vector2Extension.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace UnityEngine -{ - public static class UnityEngineVector2Extension - { - /// - /// 取 的 (x, y) 转换为 的 (x, 0, y)。 - /// - /// 要转换的 Vector2。 - /// 转换后的 Vector3。 - public static Vector3 ToVector3(this Vector2 vector2) - { - return new Vector3(vector2.x, 0f, vector2.y); - } - - /// - /// 取 的 (x, y) 和给定参数 y 转换为 的 (x, 参数 y, y)。 - /// - /// 要转换的 Vector2。 - /// Vector3 的 y 值。 - /// 转换后的 Vector3。 - public static Vector3 ToVector3(this Vector2 vector2, float y) - { - return new Vector3(vector2.x, y, vector2.y); - } - } -} \ No newline at end of file diff --git a/Runtime/ABase/Extension/UnityEngine.Vector2/Vector2Extensions.cs b/Runtime/ABase/Extension/UnityEngine.Vector2/Vector2Extensions.cs new file mode 100644 index 0000000..9f8da2c --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Vector2/Vector2Extensions.cs @@ -0,0 +1,55 @@ +namespace UnityEngine +{ + public static class Vector2Extensions + { + /// + /// 取 的 (x, y) 转换为 的 (x, 0, y)。 + /// + /// 要转换的 Vector2。 + /// 转换后的 Vector3。 + public static Vector3 ToVector3(this Vector2 vector2) + { + return new Vector3(vector2.x, 0f, vector2.y); + } + + /// + /// 取 的 (x, y) 和给定参数 y 转换为 的 (x, 参数 y, y)。 + /// + /// 要转换的 Vector2。 + /// Vector3 的 y 值。 + /// 转换后的 Vector3。 + public static Vector3 ToVector3(this Vector2 vector2, float y) + { + return new Vector3(vector2.x, y, vector2.y); + } + + /// + /// 判断值是否在向量区间内。 + /// + public static bool InRange(this Vector2 vector, float value, bool equal = false) + { + return equal ? value >= vector.x && value <= vector.y : value > vector.x && value < vector.y; + } + + /// + /// 判断角度是否在向量表示的角度区间内。 + /// + public static bool InDegrees(this Vector2 vector, float value, bool equal = false) + { + if (vector.x > vector.y) + { + return equal ? value >= (vector.x - 360f) && value <= vector.y : value > (vector.x - 360f) && value < vector.y; + } + + return equal ? value >= vector.x && value <= vector.y : value > vector.x && value < vector.y; + } + + /// + /// 从区间内取随机值。 + /// + public static float Random(this Vector2 vector) + { + return UnityEngine.Random.Range(vector.x, vector.y); + } + } +} diff --git a/Runtime/ABase/Extension/UnityEngine.Vector2/UnityEngine.Vector2Extension.cs.meta b/Runtime/ABase/Extension/UnityEngine.Vector2/Vector2Extensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngine.Vector2/UnityEngine.Vector2Extension.cs.meta rename to Runtime/ABase/Extension/UnityEngine.Vector2/Vector2Extensions.cs.meta diff --git a/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs b/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs new file mode 100644 index 0000000..3d1f05e --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs @@ -0,0 +1,86 @@ +using AlicizaX; + +namespace UnityEngine +{ + [UnityEngine.Scripting.Preserve] + public static class AxisExtensions + { + public static Vector3 Convert(this Axis axis) => axis switch + { + Axis.X => Vector3.right, + Axis.X_Negative => Vector3.left, + Axis.Y => Vector3.up, + Axis.Y_Negative => Vector3.down, + Axis.Z => Vector3.forward, + Axis.Z_Negative => Vector3.back, + _ => Vector3.up, + }; + + public static Vector3 Direction(this Transform transform, Axis axis) + { + return axis switch + { + Axis.X => transform.right, + Axis.X_Negative => -transform.right, + Axis.Y => transform.up, + Axis.Y_Negative => -transform.up, + Axis.Z => transform.forward, + Axis.Z_Negative => -transform.forward, + _ => transform.up, + }; + } + + public static float Component(this Vector3 vector, Axis axis) + { + return axis switch + { + Axis.X or Axis.X_Negative => vector.x, + Axis.Y or Axis.Y_Negative => vector.y, + Axis.Z or Axis.Z_Negative => vector.z, + _ => vector.y, + }; + } + + public static Vector3 SetComponent(this Vector3 vector, Axis axis, float value) + { + switch (axis) + { + case Axis.X: + case Axis.X_Negative: + vector.x = value; + break; + case Axis.Y: + case Axis.Y_Negative: + vector.y = value; + break; + case Axis.Z: + case Axis.Z_Negative: + vector.z = value; + break; + } + + return vector; + } + + public static Vector3 Clamp(this Vector3 vector, Axis axis, MinMax limits) + { + switch (axis) + { + case Axis.X: + case Axis.X_Negative: + vector.x = Mathf.Clamp(vector.x, limits.RealMin, limits.RealMax); + break; + case Axis.Y: + case Axis.Y_Negative: + vector.y = Mathf.Clamp(vector.y, limits.RealMin, limits.RealMax); + break; + case Axis.Z: + case Axis.Z_Negative: + vector.z = Mathf.Clamp(vector.z, limits.RealMin, limits.RealMax); + break; + } + + return vector; + } + } +} diff --git a/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs.meta b/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs.meta new file mode 100644 index 0000000..93aec24 --- /dev/null +++ b/Runtime/ABase/Extension/UnityEngine.Vector3/AxisExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b282fd247f4930142a14784638083a56 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Extension/UnityEngine.Vector3/UnityEngine.Vector3Extension.cs b/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs similarity index 78% rename from Runtime/ABase/Extension/UnityEngine.Vector3/UnityEngine.Vector3Extension.cs rename to Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs index d58d65f..02cebc0 100644 --- a/Runtime/ABase/Extension/UnityEngine.Vector3/UnityEngine.Vector3Extension.cs +++ b/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs @@ -3,7 +3,7 @@ /// /// 对 Unity 的扩展方法。 /// - public static class UnityEngineVector3Extension + public static class Vector3Extensions { /// /// 取 的 (x, y, z) 转换为 的 (x, z)。 @@ -25,5 +25,14 @@ { return new Vector3(vector3.x, vector3.y, vector3.z); } + + /// + /// 按分量相乘。 + /// + public static Vector3 Multiply(this Vector3 lhs, Vector3 rhs) + { + lhs.Scale(rhs); + return lhs; + } } -} \ No newline at end of file +} diff --git a/Runtime/ABase/Extension/UnityEngine.Vector3/UnityEngine.Vector3Extension.cs.meta b/Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs.meta similarity index 100% rename from Runtime/ABase/Extension/UnityEngine.Vector3/UnityEngine.Vector3Extension.cs.meta rename to Runtime/ABase/Extension/UnityEngine.Vector3/Vector3Extensions.cs.meta diff --git a/Runtime/ABase/Helper/ApplicationHelper.cs b/Runtime/ABase/Helper/ApplicationHelper.cs deleted file mode 100644 index 76612fc..0000000 --- a/Runtime/ABase/Helper/ApplicationHelper.cs +++ /dev/null @@ -1,128 +0,0 @@ -using UnityEngine; - -namespace AlicizaX -{ - /// - /// 应用帮助类 - /// - [UnityEngine.Scripting.Preserve] - public static class ApplicationHelper - { - /// - /// 是否是编辑器 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsEditor - { - get - { -#if UNITY_EDITOR - return true; -#else - return false; -#endif - } - } - - /// - /// 是否是安卓 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsAndroid - { - get - { -#if UNITY_ANDROID - return true; -#else - return false; -#endif - } - } - - /// - /// 是否是WebGL平台 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsWebGL - { - get { return Application.platform == RuntimePlatform.WebGLPlayer; } - } - - /// - /// 是否是Windows平台 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsWindows - { - get { return Application.platform == RuntimePlatform.WindowsPlayer; } - } - - /// - /// 是否是Linux平台 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsLinux - { - get { return Application.platform == RuntimePlatform.LinuxPlayer; } - } - - - /// - /// 是否是Mac平台 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsMacOsx - { - get { return Application.platform == RuntimePlatform.OSXPlayer; } - } - - /// - /// 是否是iOS 移动平台 - /// - [UnityEngine.Scripting.Preserve] - public static bool IsIOS - { - get - { -#if UNITY_IOS - return true; -#else - return false; -#endif - } - } - - /// - /// 退出 - /// - public static void Quit() - { -#if UNITY_EDITOR - UnityEditor.EditorApplication.isPlaying = false; - return; -#endif - Application.Quit(); - } -#if UNITY_IOS - [System.Runtime.InteropServices.DllImport("__Internal")] - private static extern void open_url(string url); -#endif - /// - /// 打开URL - /// - /// url地址 - public static void OpenURL(string url) - { -#if UNITY_EDITOR - Application.OpenURL(url); - return; -#endif -#if UNITY_IOS - open_url(url); -#else - Application.OpenURL(url); -#endif - } - } -} diff --git a/Runtime/ABase/Helper/ApplicationHelper.cs.meta b/Runtime/ABase/Helper/ApplicationHelper.cs.meta deleted file mode 100644 index be5aafc..0000000 --- a/Runtime/ABase/Helper/ApplicationHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 4bb21c08b2dd4b15af73858c5daf4a99 -timeCreated: 1676885563 \ No newline at end of file diff --git a/Runtime/ABase/Helper/DistinctHelper.cs.meta b/Runtime/ABase/Helper/DistinctHelper.cs.meta deleted file mode 100644 index 120b38d..0000000 --- a/Runtime/ABase/Helper/DistinctHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 777c1056a4804d90960109d21275c56e -timeCreated: 1670814641 \ No newline at end of file diff --git a/Runtime/ABase/Helper/FileHelper.cs b/Runtime/ABase/Helper/FileHelper.cs index 016e544..53b1bea 100644 --- a/Runtime/ABase/Helper/FileHelper.cs +++ b/Runtime/ABase/Helper/FileHelper.cs @@ -152,9 +152,9 @@ namespace AlicizaX { if (Application.platform == RuntimePlatform.Android) { - if (PathHelper.NormalizePath(path).Contains(PathHelper.AppResPath)) + if (Utility.Path.NormalizePath(path).Contains(Utility.Path.AppResPath)) { - readPath = path.Substring(PathHelper.AppResPath.Length); + readPath = path.Substring(Utility.Path.AppResPath.Length); return true; } } diff --git a/Runtime/ABase/Helper/NetworkHelper.cs b/Runtime/ABase/Helper/NetworkHelper.cs deleted file mode 100644 index 999ff0b..0000000 --- a/Runtime/ABase/Helper/NetworkHelper.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; -using System.Net; -using UnityEngine; - -namespace AlicizaX -{ - /// - /// 网络帮助类 - /// - public static class NetworkHelper - { - /// - /// 获取本地的IP列表 - /// - /// - public static string[] GetAddressIPs() - { - //获取本地的IP地址 - var list = Dns.GetHostEntry(Dns.GetHostName()).AddressList; - string[] addressIPs = new string[list.Length]; - for (var index = 0; index < list.Length; index++) - { - IPAddress address = list[index]; - addressIPs[index] = address.ToString(); - } - - return addressIPs; - } - - /// - /// 是否有网络 - /// - /// - public static bool IsReachable() - { - return Application.internetReachability != NetworkReachability.NotReachable; - } - - /// - /// 是否是WIFI - /// - /// - public static bool IsWifi() - { - return Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork; - } - - /// - /// 是否是移动网络 - /// - /// - public static bool IsViaCarrierData() - { - //当用户使用移动网络时 - return Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork; - } - } -} diff --git a/Runtime/ABase/Helper/NetworkHelper.cs.meta b/Runtime/ABase/Helper/NetworkHelper.cs.meta deleted file mode 100644 index 83204e2..0000000 --- a/Runtime/ABase/Helper/NetworkHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: debb4ec407ad464e9aa0cbee452683e1 -timeCreated: 1666448562 \ No newline at end of file diff --git a/Runtime/ABase/Helper/ObjectHelper.cs b/Runtime/ABase/Helper/ObjectHelper.cs deleted file mode 100644 index 610fe39..0000000 --- a/Runtime/ABase/Helper/ObjectHelper.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace AlicizaX -{ - [UnityEngine.Scripting.Preserve] - public static class ObjectHelper - { - [UnityEngine.Scripting.Preserve] - public static void Swap(ref T t1, ref T t2) - { - (t1, t2) = (t2, t1); - } - } -} diff --git a/Runtime/ABase/Helper/ObjectHelper.cs.meta b/Runtime/ABase/Helper/ObjectHelper.cs.meta deleted file mode 100644 index d826c1f..0000000 --- a/Runtime/ABase/Helper/ObjectHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 41b9276a283a4b6a9afcdde1b884ff70 -timeCreated: 1667393013 \ No newline at end of file diff --git a/Runtime/ABase/Helper/PathHelper.cs b/Runtime/ABase/Helper/PathHelper.cs deleted file mode 100644 index 07b6fd1..0000000 --- a/Runtime/ABase/Helper/PathHelper.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Text; -using UnityEngine; - -namespace AlicizaX -{ - public static class PathHelper - { - /// - ///应用程序外部资源路径存放路径(热更新资源路径) - /// - [UnityEngine.Scripting.Preserve] - public static string AppHotfixResPath - { - get - { - string game = Application.productName; - string path = $"{Application.persistentDataPath}/{game}/"; - return path; - } - } - - /// - /// 应用程序内部资源路径存放路径 - /// - public static string AppResPath - { - get { return NormalizePath(Application.streamingAssetsPath); } - } - - /// - /// 应用程序内部资源路径存放路径(www/webrequest专用) - /// - [UnityEngine.Scripting.Preserve] - public static string AppResPath4Web - { - get - { -#if UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR - return $"file://{Application.streamingAssetsPath}"; -#else - return NormalizePath(Application.streamingAssetsPath); -#endif - } - } - - /// - /// 获取平台名称 - /// - public static string GetPlatformName - { - get - { -#if UNITY_ANDROID - return $"Android"; -#elif UNITY_STANDALONE_OSX - return $"MacOs"; -#elif UNITY_IOS || UNITY_IPHONE - return $"iOS"; -#elif UNITY_WEBGL - return $"WebGL"; -#elif UNITY_STANDALONE_WIN - return $"Windows"; -#else - return string.Empty; -#endif - } - } - - /// - /// 规范化路径 - /// - /// - /// - public static string NormalizePath(string path) - { - return path.Replace('\\', '/').Replace("\\", "/"); - } - - static readonly StringBuilder CombineStringBuilder = new StringBuilder(); - - /// - /// 拼接路径 - /// - /// - /// - public static string Combine(params string[] paths) - { - CombineStringBuilder.Clear(); - const string separatorA = "/"; - const string separatorB = "\\"; - for (var index = 0; index < paths.Length - 1; index++) - { - var path = paths[index]; - CombineStringBuilder.Append(path); - if (path.EndsWithFast(separatorA) || path.EndsWithFast(separatorB)) - { - continue; - } - - if (path.StartsWithFast(separatorA) || path.StartsWithFast(separatorB)) - { - continue; - } - - CombineStringBuilder.Append(separatorA); - } - - CombineStringBuilder.Append(paths[paths.Length - 1]); - return CombineStringBuilder.ToString(); - } - } -} diff --git a/Runtime/ABase/Helper/PathHelper.cs.meta b/Runtime/ABase/Helper/PathHelper.cs.meta deleted file mode 100644 index 22bd71d..0000000 --- a/Runtime/ABase/Helper/PathHelper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: abf5957e17cb46339da8f67cd4074ffd -timeCreated: 1671505311 \ No newline at end of file diff --git a/Runtime/ABase/Helper/RandomHelper.cs b/Runtime/ABase/Helper/RandomHelper.cs deleted file mode 100644 index c471b06..0000000 --- a/Runtime/ABase/Helper/RandomHelper.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; - -namespace AlicizaX -{ - /// - /// 随机数帮助类 - /// - public static class RandomHelper - { - private static Random _random = new Random((int) DateTime.UtcNow.Ticks); - - /// - /// 设置随机种子 - /// - /// - public static void SetSeed(int seed) - { - _random = new Random(seed); - } - - /// - /// 获取UInt64范围内的随机数 - /// - /// - public static ulong NextUInt64() - { - var bytes = new byte[8]; - _random.NextBytes(bytes); - return BitConverter.ToUInt64(bytes, 0); - } - - /// - /// 获取Int64范围内的随机数 - /// - /// - public static long NextInt64() - { - var bytes = new byte[8]; - _random.NextBytes(bytes); - return BitConverter.ToInt64(bytes, 0); - } - - /// - /// 获取lower与Upper之间的随机数 - /// - /// - /// - /// - public static int Next(int lower, int upper) - { - return _random.Next(lower, upper); - } - - /// - /// 获取0与1之间的随机数 - /// - /// - public static float Next() - { - return _random.Next(0, 100_000) / 100_000f; - } - } -} diff --git a/Runtime/ABase/Structs/Pair.cs b/Runtime/ABase/Structs/Pair.cs new file mode 100644 index 0000000..e239f23 --- /dev/null +++ b/Runtime/ABase/Structs/Pair.cs @@ -0,0 +1,16 @@ +namespace AlicizaX +{ + public struct Pair + { + public T1 Key { get; set; } + public T2 Value { get; set; } + + public bool IsAssigned => Key != null && Value != null; + + public Pair(T1 key, T2 value) + { + Key = key; + Value = value; + } + } +} diff --git a/Runtime/ABase/Structs/Pair.cs.meta b/Runtime/ABase/Structs/Pair.cs.meta new file mode 100644 index 0000000..3175181 --- /dev/null +++ b/Runtime/ABase/Structs/Pair.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0278c1fdfc27bd4c9419d984d7d0ac1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Structs/UniqueID.cs b/Runtime/ABase/Structs/UniqueID.cs index 3c0a036..3a10314 100644 --- a/Runtime/ABase/Structs/UniqueID.cs +++ b/Runtime/ABase/Structs/UniqueID.cs @@ -32,7 +32,7 @@ namespace AlicizaX /// public void Generate() { - Id = GameHelper.GetGuid(); + Id = Utility.IdGenerator.GetGuid(); } public static implicit operator string(UniqueID uniqueID) diff --git a/Runtime/ABase/Utility/Utility.Gizmo.cs b/Runtime/ABase/Utility/Utility.Gizmo.cs new file mode 100644 index 0000000..477f9da --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Gizmo.cs @@ -0,0 +1,108 @@ +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// Gizmos 绘制辅助。 + /// + public static class Gizmo + { + public static void DrawArrow(Vector3 position, Vector3 direction, float arrowHeadLength = 0.25f, float arrowHeadAngle = 20f) + { + Gizmos.DrawRay(position, direction); + Vector3 right = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 + arrowHeadAngle, 0) * new Vector3(0, 0, 1); + Vector3 left = Quaternion.LookRotation(direction) * Quaternion.Euler(0, 180 - arrowHeadAngle, 0) * new Vector3(0, 0, 1); + Gizmos.DrawRay(position + direction, right * arrowHeadLength); + Gizmos.DrawRay(position + direction, left * arrowHeadLength); + } + + public static void DrawWireCapsule(Vector3 p1, Vector3 p2, float radius) + { +#if UNITY_EDITOR + if (p1 == p2) + { + Gizmos.DrawWireSphere(p1, radius); + return; + } + + using (new Handles.DrawingScope(Gizmos.color, Gizmos.matrix)) + { + Quaternion p1Rotation = Quaternion.LookRotation(p1 - p2); + Quaternion p2Rotation = Quaternion.LookRotation(p2 - p1); + float c = Vector3.Dot((p1 - p2).normalized, Vector3.up); + if (c == 1f || c == -1f) + { + p2Rotation = Quaternion.Euler(p2Rotation.eulerAngles.x, p2Rotation.eulerAngles.y + 180f, p2Rotation.eulerAngles.z); + } + + Handles.DrawWireArc(p1, p1Rotation * Vector3.left, p1Rotation * Vector3.down, 180f, radius); + Handles.DrawWireArc(p1, p1Rotation * Vector3.up, p1Rotation * Vector3.left, 180f, radius); + Handles.DrawWireDisc(p1, (p2 - p1).normalized, radius); + Handles.DrawWireArc(p2, p2Rotation * Vector3.left, p2Rotation * Vector3.down, 180f, radius); + Handles.DrawWireArc(p2, p2Rotation * Vector3.up, p2Rotation * Vector3.left, 180f, radius); + Handles.DrawWireDisc(p2, (p1 - p2).normalized, radius); + Handles.DrawLine(p1 + p1Rotation * Vector3.down * radius, p2 + p2Rotation * Vector3.down * radius); + Handles.DrawLine(p1 + p1Rotation * Vector3.left * radius, p2 + p2Rotation * Vector3.right * radius); + Handles.DrawLine(p1 + p1Rotation * Vector3.up * radius, p2 + p2Rotation * Vector3.up * radius); + Handles.DrawLine(p1 + p1Rotation * Vector3.right * radius, p2 + p2Rotation * Vector3.left * radius); + } +#endif + } + + public static void DrawWireCapsule(Vector3 position, Quaternion rotation, float radius, float height) + { +#if UNITY_EDITOR + Matrix4x4 angleMatrix = Matrix4x4.TRS(position, rotation, Handles.matrix.lossyScale); + using (new Handles.DrawingScope(angleMatrix)) + { + float pointOffset = (height - (radius * 2)) / 2; + Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.left, Vector3.back, -180, radius); + Handles.DrawLine(new Vector3(0, pointOffset, -radius), new Vector3(0, -pointOffset, -radius)); + Handles.DrawLine(new Vector3(0, pointOffset, radius), new Vector3(0, -pointOffset, radius)); + Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.left, Vector3.back, 180, radius); + Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.back, Vector3.left, 180, radius); + Handles.DrawLine(new Vector3(-radius, pointOffset, 0), new Vector3(-radius, -pointOffset, 0)); + Handles.DrawLine(new Vector3(radius, pointOffset, 0), new Vector3(radius, -pointOffset, 0)); + Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.back, Vector3.left, -180, radius); + Handles.DrawWireDisc(Vector3.up * pointOffset, Vector3.up, radius); + Handles.DrawWireDisc(Vector3.down * pointOffset, Vector3.up, radius); + } +#endif + } + + public static void DrawCenteredLabel(Vector3 position, string labelText, GUIStyle style = null) + { +#if UNITY_EDITOR + if (style == null) + { + style = new GUIStyle(GUI.skin.label); + } + + GUIContent content = new GUIContent(labelText); + Vector2 labelSize = style.CalcSize(content); + Vector3 screenPosition = HandleUtility.WorldToGUIPoint(position); + screenPosition.x -= labelSize.x / 2; + screenPosition.y -= labelSize.y / 2; + Vector3 worldPosition = HandleUtility.GUIPointToWorldRay(screenPosition).origin; + Handles.Label(worldPosition, labelText, style); +#endif + } + + public static void DrawDisc(Vector3 position, float radius, Color outerColor, Color innerColor) + { +#if UNITY_EDITOR + Handles.color = innerColor; + Handles.DrawSolidDisc(position, Vector3.up, radius); + Handles.color = outerColor; + Handles.DrawWireDisc(position, Vector3.up, radius); +#endif + } + } + } +} diff --git a/Runtime/ABase/Utility/Utility.Gizmo.cs.meta b/Runtime/ABase/Utility/Utility.Gizmo.cs.meta new file mode 100644 index 0000000..d16272e --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Gizmo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1795d7c750b9aaa4abd939fa483d3a66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Utility/Utility.IdGenerator.cs b/Runtime/ABase/Utility/Utility.IdGenerator.cs index 292af51..ff6dcec 100644 --- a/Runtime/ABase/Utility/Utility.IdGenerator.cs +++ b/Runtime/ABase/Utility/Utility.IdGenerator.cs @@ -31,6 +31,14 @@ namespace AlicizaX { return Interlocked.Increment(ref _intCounter); } + + /// + /// 生成新的 Guid 字符串。 + /// + public static string GetGuid() + { + return Guid.NewGuid().ToString("N"); + } } } } diff --git a/Runtime/ABase/Utility/Utility.Math.cs b/Runtime/ABase/Utility/Utility.Math.cs new file mode 100644 index 0000000..ae6b296 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Math.cs @@ -0,0 +1,183 @@ +using UnityEngine; + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// 数学和插值相关工具。 + /// + public static class Math + { + public static bool IsApproximate(float valueA, float valueB, float tolerance) + { + return Mathf.Abs(valueA - valueB) < tolerance; + } + + public static float PingPong(float min, float max, float speed = 1f) + { + return Mathf.PingPong(Time.time * speed, max - min) + min; + } + + public static int Wrap(int value, int min, int max) + { + int newValue = value % max; + if (newValue < min) + { + newValue = max - 1; + } + + return newValue; + } + + public static float InverseLerp3(float min, float mid, float max, float t) + { + if (t <= min) + { + return 0f; + } + + if (t >= max) + { + return 0f; + } + + return t <= mid ? Mathf.InverseLerp(min, mid, t) : 1f - Mathf.InverseLerp(mid, max, t); + } + + public static float Remap(float minA, float maxA, float minB, float maxB, float t) + { + return minB + (t - minA) * (maxB - minB) / (maxA - minA); + } + + public static float EaseOut(float start, float end, float t) + { + t = Mathf.Clamp01(t); + t = Mathf.Sin(t * Mathf.PI * 0.5f); + return Mathf.Lerp(start, end, t); + } + + public static float EaseIn(float start, float end, float t) + { + t = Mathf.Clamp01(t); + t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f); + return Mathf.Lerp(start, end, t); + } + + public static float SmootherStep(float start, float end, float t) + { + t = Mathf.Clamp01(t); + t = t * t * t * (t * (6f * t - 15f) + 10f); + return Mathf.Lerp(start, end, t); + } + + public static float InverseLerp(Vector3 a, Vector3 b, Vector3 value) + { + if (a != b) + { + Vector3 ab = b - a; + Vector3 av = value - a; + float t = Vector3.Dot(av, ab) / Vector3.Dot(ab, ab); + return Mathf.Clamp01(t); + } + + return 0f; + } + + public static Vector3 QuadraticBezier(Vector3 p1, Vector3 p2, Vector3 cp, float t) + { + t = Mathf.Clamp01(t); + Vector3 m1 = Vector3.LerpUnclamped(p1, cp, t); + Vector3 m2 = Vector3.LerpUnclamped(cp, p2, t); + return Vector3.LerpUnclamped(m1, m2, t); + } + + public static Vector3 BezierCurve(float t, params Vector3[] points) + { + if (points.Length < 1) + { + return Vector3.zero; + } + + if (points.Length == 1) + { + return points[0]; + } + + t = Mathf.Clamp01(t); + Vector3[] cp = points; + int n = points.Length - 1; + while (n > 1) + { + Vector3[] rp = new Vector3[n]; + for (int i = 0; i < rp.Length; i++) + { + rp[i] = Vector3.LerpUnclamped(cp[i], cp[i + 1], t); + } + + cp = rp; + n--; + } + + return Vector3.LerpUnclamped(cp[0], cp[1], t); + } + + public static Vector3 Lerp3(Vector3 a, Vector3 b, Vector3 c, float t) + { + t = Mathf.Clamp01(t); + if (t <= 0.5f) + { + return Vector3.LerpUnclamped(a, b, t * 2f); + } + + return Vector3.LerpUnclamped(b, c, (t * 2f) - 1f); + } + + public static Vector3 RangeLerp(float t, params Vector3[] points) + { + if (points.Length < 1) + { + return Vector3.zero; + } + + if (points.Length == 1) + { + return points[0]; + } + + t = Mathf.Clamp01(t); + int pointsCount = points.Length - 1; + float scale = 1f / pointsCount; + float remap = Remap(0f, 1f, 0f, pointsCount, t); + int index = Mathf.Clamp(Mathf.FloorToInt(remap), 0, pointsCount - 1); + float indexT = Mathf.InverseLerp(index * scale, (index + 1) * scale, t); + return Vector3.LerpUnclamped(points[index], points[index + 1], indexT); + } + + public static Vector3 Lerp(float t, Vector3[] points) + { + if (points.Length > 3) + { + return RangeLerp(t, points); + } + + if (points.Length == 3) + { + return Lerp3(points[0], points[1], points[2], t); + } + + if (points.Length == 2) + { + return Vector3.Lerp(points[0], points[1], t); + } + + if (points.Length == 1) + { + return points[0]; + } + + return Vector3.zero; + } + } + } +} diff --git a/Runtime/ABase/Utility/Utility.Math.cs.meta b/Runtime/ABase/Utility/Utility.Math.cs.meta new file mode 100644 index 0000000..6d14d94 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Math.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb2b3056e5c86d94697f60d958e1012e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Utility/Utility.Net.cs b/Runtime/ABase/Utility/Utility.Net.cs index 4ef9926..a7503b7 100644 --- a/Runtime/ABase/Utility/Utility.Net.cs +++ b/Runtime/ABase/Utility/Utility.Net.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +using UnityEngine; namespace AlicizaX { @@ -13,6 +14,45 @@ namespace AlicizaX /// public static class Net { + /// + /// 获取本地 IP 列表。 + /// + public static string[] GetAddressIPs() + { + var list = Dns.GetHostEntry(Dns.GetHostName()).AddressList; + string[] addressIPs = new string[list.Length]; + for (int index = 0; index < list.Length; index++) + { + IPAddress address = list[index]; + addressIPs[index] = address.ToString(); + } + + return addressIPs; + } + + /// + /// 是否有网络连接。 + /// + public static bool IsReachable() + { + return Application.internetReachability != NetworkReachability.NotReachable; + } + + /// + /// 是否为局域网或 WiFi 网络。 + /// + public static bool IsWifi() + { + return Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork; + } + + /// + /// 是否为移动网络。 + /// + public static bool IsViaCarrierData() + { + return Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork; + } /// /// 获取第一个可用的端口号 /// diff --git a/Runtime/ABase/Utility/Utility.Object.cs b/Runtime/ABase/Utility/Utility.Object.cs deleted file mode 100644 index 5f2d17c..0000000 --- a/Runtime/ABase/Utility/Utility.Object.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace AlicizaX -{ - public static partial class Utility - { - /// - /// Object 对象工具类 - /// - public static class Object - { - /// - /// 交换对象 - /// - /// - /// - /// - public static void Swap(ref T t1, ref T t2) - { - (t1, t2) = (t2, t1); - } - } - } -} diff --git a/Runtime/ABase/Utility/Utility.Object.cs.meta b/Runtime/ABase/Utility/Utility.Object.cs.meta deleted file mode 100644 index 9249cd1..0000000 --- a/Runtime/ABase/Utility/Utility.Object.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 0264830b4fe54557b5b0f6a6123ffbb1 -timeCreated: 1666234520 \ No newline at end of file diff --git a/Runtime/ABase/Utility/Utility.Path.cs b/Runtime/ABase/Utility/Utility.Path.cs index c1056a8..d4264af 100644 --- a/Runtime/ABase/Utility/Utility.Path.cs +++ b/Runtime/ABase/Utility/Utility.Path.cs @@ -1,5 +1,8 @@ using System.IO; +using System.Text; +using UnityEngine; + namespace AlicizaX { public static partial class Utility @@ -9,6 +12,62 @@ namespace AlicizaX /// public static class Path { + private static readonly StringBuilder CombineStringBuilder = new StringBuilder(); + + /// + /// 应用程序外部资源路径存放路径(热更新资源路径)。 + /// + public static string AppHotfixResPath + { + get + { + string game = Application.productName; + return $"{Application.persistentDataPath}/{game}/"; + } + } + + /// + /// 应用程序内部资源路径存放路径。 + /// + public static string AppResPath => GetRegularPath(Application.streamingAssetsPath); + + /// + /// 应用程序内部资源路径存放路径(www/webrequest专用)。 + /// + public static string AppResPath4Web + { + get + { +#if UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_EDITOR + return $"file://{Application.streamingAssetsPath}"; +#else + return GetRegularPath(Application.streamingAssetsPath); +#endif + } + } + + /// + /// 获取平台名称。 + /// + public static string PlatformName + { + get + { +#if UNITY_ANDROID + return "Android"; +#elif UNITY_STANDALONE_OSX + return "MacOs"; +#elif UNITY_IOS || UNITY_IPHONE + return "iOS"; +#elif UNITY_WEBGL + return "WebGL"; +#elif UNITY_STANDALONE_WIN + return "Windows"; +#else + return string.Empty; +#endif + } + } /// /// 获取规范的路径。 /// @@ -24,6 +83,16 @@ namespace AlicizaX return path.Replace('\\', '/'); } + /// + /// 获取规范的路径。 + /// + /// 要规范的路径。 + /// 规范的路径。 + public static string NormalizePath(string path) + { + return GetRegularPath(path); + } + /// /// 获取远程格式的路径(带有file:// 或 http:// 前缀)。 /// @@ -40,6 +109,37 @@ namespace AlicizaX return regularPath.Contains("://") ? regularPath : ("file:///" + regularPath).Replace("file:////", "file:///"); } + /// + /// 拼接路径。 + /// + public static string Combine(params string[] paths) + { + if (paths == null || paths.Length == 0) + { + return string.Empty; + } + + CombineStringBuilder.Clear(); + for (int index = 0; index < paths.Length - 1; index++) + { + string path = paths[index]; + if (string.IsNullOrEmpty(path)) + { + continue; + } + + CombineStringBuilder.Append(path); + char lastChar = path[path.Length - 1]; + if (lastChar != '/' && lastChar != '\\') + { + CombineStringBuilder.Append('/'); + } + } + + CombineStringBuilder.Append(paths[paths.Length - 1]); + return CombineStringBuilder.ToString(); + } + /// /// 移除空文件夹。 /// diff --git a/Runtime/ABase/Utility/Utility.Platform.cs b/Runtime/ABase/Utility/Utility.Platform.cs new file mode 100644 index 0000000..bba8649 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Platform.cs @@ -0,0 +1,111 @@ +using UnityEngine; + +namespace AlicizaX +{ + public static partial class Utility + { + /// + /// 应用和平台相关的实用函数。 + /// + public static class Platform + { + /// + /// 是否是编辑器。 + /// + public static bool IsEditor + { + get + { +#if UNITY_EDITOR + return true; +#else + return false; +#endif + } + } + + /// + /// 是否是安卓。 + /// + public static bool IsAndroid + { + get + { +#if UNITY_ANDROID + return true; +#else + return false; +#endif + } + } + + /// + /// 是否是 WebGL 平台。 + /// + public static bool IsWebGL => Application.platform == RuntimePlatform.WebGLPlayer; + + /// + /// 是否是 Windows 平台。 + /// + public static bool IsWindows => Application.platform == RuntimePlatform.WindowsPlayer; + + /// + /// 是否是 Linux 平台。 + /// + public static bool IsLinux => Application.platform == RuntimePlatform.LinuxPlayer; + + /// + /// 是否是 Mac 平台。 + /// + public static bool IsMacOsx => Application.platform == RuntimePlatform.OSXPlayer; + + /// + /// 是否是 iOS 平台。 + /// + public static bool IsIOS + { + get + { +#if UNITY_IOS + return true; +#else + return false; +#endif + } + } + + /// + /// 退出应用。 + /// + public static void Quit() + { +#if UNITY_EDITOR + UnityEditor.EditorApplication.isPlaying = false; + return; +#endif + Application.Quit(); + } + +#if UNITY_IOS + [System.Runtime.InteropServices.DllImport("__Internal")] + private static extern void open_url(string url); +#endif + + /// + /// 打开 URL。 + /// + public static void OpenURL(string url) + { +#if UNITY_EDITOR + Application.OpenURL(url); + return; +#endif +#if UNITY_IOS + open_url(url); +#else + Application.OpenURL(url); +#endif + } + } + } +} diff --git a/Runtime/ABase/Utility/Utility.Platform.cs.meta b/Runtime/ABase/Utility/Utility.Platform.cs.meta new file mode 100644 index 0000000..f4e8c79 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Platform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b2027d750c54878b78b6e304ed4ad7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ABase/Utility/Utility.Random.cs b/Runtime/ABase/Utility/Utility.Random.cs index 52cb02e..8b4c1ec 100644 --- a/Runtime/ABase/Utility/Utility.Random.cs +++ b/Runtime/ABase/Utility/Utility.Random.cs @@ -59,6 +59,35 @@ namespace AlicizaX return s_Random.NextDouble(); } + /// + /// 返回一个介于 0.0 和 1.0 之间的随机数。 + /// + /// 大于等于 0.0 并且小于 1.0 的单精度浮点数。 + public static float GetRandomSingle() + { + return (float)s_Random.NextDouble(); + } + + /// + /// 返回一个随机的 Int64。 + /// + public static long GetRandomInt64() + { + byte[] bytes = new byte[8]; + s_Random.NextBytes(bytes); + return BitConverter.ToInt64(bytes, 0); + } + + /// + /// 返回一个随机的 UInt64。 + /// + public static ulong GetRandomUInt64() + { + byte[] bytes = new byte[8]; + s_Random.NextBytes(bytes); + return BitConverter.ToUInt64(bytes, 0); + } + /// /// 用随机数填充指定字节数组的元素。 /// @@ -67,6 +96,87 @@ namespace AlicizaX { s_Random.NextBytes(buffer); } + + /// + /// 获取一个与上次值不同的随机数。 + /// + public static int RandomUnique(int min, int max, int last) + { + if (min + 1 >= max) + { + return min; + } + + int result = last; + while (result == last) + { + result = UnityEngine.Random.Range(min, max); + } + + return result; + } + + /// + /// 获取一个排除指定值集合的随机数。 + /// + public static int RandomExclude(int min, int max, int[] excludedValues, int maxIterations = 1000) + { + int result; + int iterations = 0; + do + { + if (iterations > maxIterations) + { + return -1; + } + + result = UnityEngine.Random.Range(min, max); + iterations++; + } + while (Contains(excludedValues, result)); + + return result; + } + + /// + /// 获取一个排除现有集合和已选集合的随机数。 + /// + public static int RandomExcludeUnique(int min, int max, int[] excludedValues, int[] currentValues, int maxIterations = 1000) + { + int result; + int iterations = 0; + do + { + if (iterations > maxIterations) + { + return -1; + } + + result = UnityEngine.Random.Range(min, max); + iterations++; + } + while (Contains(excludedValues, result) || Contains(currentValues, result)); + + return result; + } + + private static bool Contains(int[] values, int target) + { + if (values == null) + { + return false; + } + + for (int i = 0; i < values.Length; i++) + { + if (values[i] == target) + { + return true; + } + } + + return false; + } } } } diff --git a/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs new file mode 100644 index 0000000..0c7ae86 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs @@ -0,0 +1,106 @@ +using UnityEngine; + +namespace AlicizaX +{ + public static partial class Utility + { + public static partial class Unity + { + public static void ShowCursor(bool locked, bool visible) + { + Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None; + Cursor.visible = visible; + } + + public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int cullLayers, Layer interactLayer) + { + if (Physics.Raycast(ray, out RaycastHit hit, maxDistance, cullLayers)) + { + if (interactLayer.CompareLayer(hit.collider.gameObject)) + { + hitInfo = hit; + return true; + } + } + + hitInfo = default; + return false; + } + + public static AudioSource PlayOneShot2D(Vector3 position, AudioClip clip, float volume = 1f, string name = "OneShotAudio") + { + if (clip == null) + { + return null; + } + + GameObject gameObject = new GameObject(name); + gameObject.transform.position = position; + AudioSource source = gameObject.AddComponent(); + source.spatialBlend = 0f; + source.clip = clip; + source.volume = volume; + source.Play(); + Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + return source; + } + + public static AudioSource PlayOneShot2D(Vector3 position, SoundClip clip, string name = "OneShotAudio") + { + if (clip == null || clip.audioClip == null) + { + return null; + } + + return PlayOneShot2D(position, clip.audioClip, clip.volume, name); + } + + public static AudioSource PlayOneShot3D(Vector3 position, AudioClip clip, float volume = 1f, string name = "OneShotAudio") + { + if (clip == null) + { + return null; + } + + GameObject gameObject = new GameObject(name); + gameObject.transform.position = position; + AudioSource source = gameObject.AddComponent(); + source.spatialBlend = 1f; + source.clip = clip; + source.volume = volume; + source.Play(); + Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + return source; + } + + public static AudioSource PlayOneShot3D(Vector3 position, AudioClip clip, float maxDistance, float volume = 1f, string name = "OneShotAudio") + { + if (clip == null) + { + return null; + } + + GameObject gameObject = new GameObject(name); + gameObject.transform.position = position; + AudioSource source = gameObject.AddComponent(); + source.spatialBlend = 1f; + source.clip = clip; + source.volume = volume; + source.maxDistance = maxDistance; + source.Play(); + Object.Destroy(gameObject, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale)); + return source; + } + + public static AudioSource PlayOneShot3D(Vector3 position, SoundClip clip, string name = "OneShotAudio") + { + if (clip == null || clip.audioClip == null) + { + return null; + } + + return PlayOneShot3D(position, clip.audioClip, clip.volume, name); + } + } + } +} diff --git a/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs.meta b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs.meta new file mode 100644 index 0000000..5c4c476 --- /dev/null +++ b/Runtime/ABase/Utility/Utility.Unity.Gameplay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b214adecc8c0fab41b3fcd306d4ebb10 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: