From 35f52fc67f4ce37807bcc2edd9225a63ac294744 Mon Sep 17 00:00:00 2001 From: wbm1113 <46951987+wbm1113@users.noreply.github.com> Date: Mon, 7 Mar 2022 16:36:14 -0500 Subject: [PATCH 01/48] Triangle2D --- Assets/Scripts/2D/Geometry/Triangle2D.cs | 58 +++++++++++++++++++ Assets/Scripts/2D/Geometry/Triangle2D.cs.meta | 11 ++++ 2 files changed, 69 insertions(+) create mode 100644 Assets/Scripts/2D/Geometry/Triangle2D.cs create mode 100644 Assets/Scripts/2D/Geometry/Triangle2D.cs.meta diff --git a/Assets/Scripts/2D/Geometry/Triangle2D.cs b/Assets/Scripts/2D/Geometry/Triangle2D.cs new file mode 100644 index 0000000..9268d3a --- /dev/null +++ b/Assets/Scripts/2D/Geometry/Triangle2D.cs @@ -0,0 +1,58 @@ +using UnityEngine; +using UCL; + +// if you need to run collision checks within a triangular area, the easiest +// way to do that in Unity is to use a polygon collider. this is not very +// performant. this class allows you to run those collision checks without +// the performance overhead. + +public class Triangle2D +{ + Vector2[] vertices = new Vector2[3]; + + public Triangle2D(Vector2 v1, Vector2 v2, Vector2 v3) { + Update(v1, v2, v3); + } + + // update triangle by defining all its vertices + public void Update(Vector2 v1, Vector2 v2, Vector2 v3) { + vertices[0] = v1; + vertices[1] = v2; + vertices[2] = v3; + } + + // update triangle by redefining its origin (remaining points update relative to that) + public void Update(Vector2 v1) { + Vector2 delta = v1 - vertices[0]; + vertices[0] = v1; + vertices[1] += delta; + vertices[2] += delta; + } + + // update triangle with rotation and pivot point + public void Update(Vector2 v1, Vector2 v2, Vector2 v3, float rotation, Vector2 pivot) { + vertices[0] = v1.Rotate(rotation, pivot); + vertices[1] = v2.Rotate(rotation, pivot); + vertices[2] = v3.Rotate(rotation, pivot); + } + + float Sign(Vector2 p1, Vector2 p2, Vector2 p3) { + return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); + } + + public bool Contains(Vector2 pt, bool debug = false) { + float d1, d2, d3; + bool has_neg, has_pos; + + d1 = Sign(pt, vertices[0], vertices[1]); + d2 = Sign(pt, vertices[1], vertices[2]); + d3 = Sign(pt, vertices[2], vertices[0]); + + has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); + has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); + + bool contains = ! (has_neg && has_pos); + + return contains; + } +} \ No newline at end of file diff --git a/Assets/Scripts/2D/Geometry/Triangle2D.cs.meta b/Assets/Scripts/2D/Geometry/Triangle2D.cs.meta new file mode 100644 index 0000000..db09c09 --- /dev/null +++ b/Assets/Scripts/2D/Geometry/Triangle2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b3d23802c4b0df4db68d12d425fb251 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 0bfa89e430b39e5ff219d6e2ee4101039d063319 Mon Sep 17 00:00:00 2001 From: wbm1113 <46951987+wbm1113@users.noreply.github.com> Date: Mon, 7 Mar 2022 16:43:22 -0500 Subject: [PATCH 02/48] Vector2Extensions --- Assets/Scripts/2D/Geometry/Triangle2D.cs | 97 ++++++++++--------- .../Scripts/Extensions/Vector2Extensions.cs | 15 +++ .../Extensions/Vector2Extensions.cs.meta | 11 +++ 3 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 Assets/Scripts/Extensions/Vector2Extensions.cs create mode 100644 Assets/Scripts/Extensions/Vector2Extensions.cs.meta diff --git a/Assets/Scripts/2D/Geometry/Triangle2D.cs b/Assets/Scripts/2D/Geometry/Triangle2D.cs index 9268d3a..6d16785 100644 --- a/Assets/Scripts/2D/Geometry/Triangle2D.cs +++ b/Assets/Scripts/2D/Geometry/Triangle2D.cs @@ -1,58 +1,67 @@ using UnityEngine; -using UCL; -// if you need to run collision checks within a triangular area, the easiest -// way to do that in Unity is to use a polygon collider. this is not very -// performant. this class allows you to run those collision checks without -// the performance overhead. - -public class Triangle2D +namespace UnityLibrary { - Vector2[] vertices = new Vector2[3]; + // if you need to run collision checks within a triangular area, the easiest + // way to do that in Unity is to use a polygon collider. this is not very + // performant. this class allows you to run those collision checks without + // the performance overhead. - public Triangle2D(Vector2 v1, Vector2 v2, Vector2 v3) { - Update(v1, v2, v3); - } + public class Triangle2D + { + Vector2[] vertices = new Vector2[3]; - // update triangle by defining all its vertices - public void Update(Vector2 v1, Vector2 v2, Vector2 v3) { - vertices[0] = v1; - vertices[1] = v2; - vertices[2] = v3; - } + public Triangle2D(Vector2 v1, Vector2 v2, Vector2 v3) + { + Update(v1, v2, v3); + } - // update triangle by redefining its origin (remaining points update relative to that) - public void Update(Vector2 v1) { - Vector2 delta = v1 - vertices[0]; - vertices[0] = v1; - vertices[1] += delta; - vertices[2] += delta; - } + // update triangle by defining all its vertices + public void Update(Vector2 v1, Vector2 v2, Vector2 v3) + { + vertices[0] = v1; + vertices[1] = v2; + vertices[2] = v3; + } - // update triangle with rotation and pivot point - public void Update(Vector2 v1, Vector2 v2, Vector2 v3, float rotation, Vector2 pivot) { - vertices[0] = v1.Rotate(rotation, pivot); - vertices[1] = v2.Rotate(rotation, pivot); - vertices[2] = v3.Rotate(rotation, pivot); - } + // update triangle by redefining its origin (remaining points update relative to that) + public void Update(Vector2 v1) + { + Vector2 delta = v1 - vertices[0]; + vertices[0] = v1; + vertices[1] += delta; + vertices[2] += delta; + } - float Sign(Vector2 p1, Vector2 p2, Vector2 p3) { - return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); - } + // update triangle with rotation and pivot point + public void Update(Vector2 v1, Vector2 v2, Vector2 v3, float rotation, Vector2 pivot) + { + vertices[0] = v1.Rotate(rotation, pivot); + vertices[1] = v2.Rotate(rotation, pivot); + vertices[2] = v3.Rotate(rotation, pivot); + } - public bool Contains(Vector2 pt, bool debug = false) { - float d1, d2, d3; - bool has_neg, has_pos; + float Sign(Vector2 p1, Vector2 p2, Vector2 p3) + { + return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); + } - d1 = Sign(pt, vertices[0], vertices[1]); - d2 = Sign(pt, vertices[1], vertices[2]); - d3 = Sign(pt, vertices[2], vertices[0]); + public bool Contains(Vector2 pt, bool debug = false) + { + float d1, d2, d3; + bool has_neg, has_pos; - has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); - has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); + d1 = Sign(pt, vertices[0], vertices[1]); + d2 = Sign(pt, vertices[1], vertices[2]); + d3 = Sign(pt, vertices[2], vertices[0]); - bool contains = ! (has_neg && has_pos); + has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); + has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); - return contains; + bool contains = ! (has_neg && has_pos); + + return contains; + } } -} \ No newline at end of file +} + diff --git a/Assets/Scripts/Extensions/Vector2Extensions.cs b/Assets/Scripts/Extensions/Vector2Extensions.cs new file mode 100644 index 0000000..e85b0dd --- /dev/null +++ b/Assets/Scripts/Extensions/Vector2Extensions.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace UnityLibrary +{ + static class Vector2Extensions + { + public static Vector2 Round(this Vector2 vector, int to = 0) => new Vector2(vector.x.Round(to), vector.y.Round(to)); + + public static Vector2 Rotate(this Vector2 vector, float angle, Vector2 pivot = default(Vector2)) + { + Vector2 rotated = Quaternion.Euler(new Vector3(0f, 0f, angle)) * (vector - pivot); + return rotated + pivot; + } + } +} diff --git a/Assets/Scripts/Extensions/Vector2Extensions.cs.meta b/Assets/Scripts/Extensions/Vector2Extensions.cs.meta new file mode 100644 index 0000000..0fef0ef --- /dev/null +++ b/Assets/Scripts/Extensions/Vector2Extensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 058da80b535be1d469c9998e5629a60e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 4d4b3ee01093ec5bb62815c83b92d2530807d82e Mon Sep 17 00:00:00 2001 From: wbm1113 <46951987+wbm1113@users.noreply.github.com> Date: Wed, 9 Mar 2022 21:00:16 -0500 Subject: [PATCH 03/48] Create StringExtensions.cs --- Assets/Scripts/Extensions/StringExtensions.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Assets/Scripts/Extensions/StringExtensions.cs diff --git a/Assets/Scripts/Extensions/StringExtensions.cs b/Assets/Scripts/Extensions/StringExtensions.cs new file mode 100644 index 0000000..ca32336 --- /dev/null +++ b/Assets/Scripts/Extensions/StringExtensions.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using System.Globalization; + +namespace UnityLibrary +{ + public static class StringExtensions + { + public static Color ToColor(this string hex) { + hex = hex.Replace("0x", ""); + hex = hex.Replace("#", ""); + + byte a = 255; + byte r = byte.Parse(hex.Substring(0,2), NumberStyles.HexNumber); + byte g = byte.Parse(hex.Substring(2,2), NumberStyles.HexNumber); + byte b = byte.Parse(hex.Substring(4,2), NumberStyles.HexNumber); + + if (hex.Length == 8) + a = byte.Parse(hex.Substring(6,2), NumberStyles.HexNumber); + + return new Color32(r,g,b,a); + } + } +} \ No newline at end of file From a856fdcd55f34d20cf4e36dd527af4de2d3c4f2a Mon Sep 17 00:00:00 2001 From: wbm1113 <46951987+wbm1113@users.noreply.github.com> Date: Wed, 9 Mar 2022 21:06:50 -0500 Subject: [PATCH 04/48] Update StringExtensions.cs --- Assets/Scripts/Extensions/StringExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/Extensions/StringExtensions.cs b/Assets/Scripts/Extensions/StringExtensions.cs index ca32336..e5ecb6a 100644 --- a/Assets/Scripts/Extensions/StringExtensions.cs +++ b/Assets/Scripts/Extensions/StringExtensions.cs @@ -1,6 +1,8 @@ using UnityEngine; using System.Globalization; +// e.g. "#FFFFFF".ToColor() + namespace UnityLibrary { public static class StringExtensions @@ -20,4 +22,4 @@ public static Color ToColor(this string hex) { return new Color32(r,g,b,a); } } -} \ No newline at end of file +} From 73823b09b9254771a583a95854f5e92b51d866a5 Mon Sep 17 00:00:00 2001 From: mika Date: Tue, 19 Apr 2022 10:49:40 +0300 Subject: [PATCH 05/48] Create PostBuildCopyEmptyFolders.cs --- .../BuildProcess/PostBuildCopyEmptyFolders.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs diff --git a/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs b/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs new file mode 100644 index 0000000..da29025 --- /dev/null +++ b/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs @@ -0,0 +1,51 @@ +using System.IO; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; + +// copies empty StreamingAssets/ folders into build, as they are not automatically included + +namespace UnityLibrary +{ + public class PostBuildCopyEmptyFolders : MonoBehaviour + { + [PostProcessBuildAttribute(1)] + public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) + { + Debug.Log("### POSTBUILD : COPY EMPTY STREAMINGASSETS-FOLDERS ###"); + Debug.Log("Build done: " + pathToBuiltProject); + + // get output root + var root = Path.GetDirectoryName(pathToBuiltProject); + var appName = Path.GetFileNameWithoutExtension(pathToBuiltProject); + + // copy empty streaming asset folders to build + var sourcePath = Application.streamingAssetsPath; + var targetPath = Path.Combine(root, appName + "_Data", "StreamingAssets"); + //Debug.Log("sourcePath= "+ sourcePath); + //Debug.Log("targetPath= " + targetPath); + CopyFolderStructure(sourcePath, targetPath); + } + + // recursive folder copier + static public void CopyFolderStructure(string sourceFolder, string destFolder) + { + if (Directory.Exists(destFolder)) + { + + } + else + { + Directory.CreateDirectory(destFolder); + } + + string[] folders = Directory.GetDirectories(sourceFolder); + foreach (string folder in folders) + { + string name = Path.GetFileName(folder); + string dest = Path.Combine(destFolder, name); + CopyFolderStructure(folder, dest); + } + } + } +} From 2b455662d8a6cdd6a47955491b75e5a323d5ffa9 Mon Sep 17 00:00:00 2001 From: mika Date: Wed, 27 Apr 2022 12:20:01 +0300 Subject: [PATCH 06/48] OnPostprocessBuild copy for windows only (otherwise android build fails) --- .../Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs b/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs index da29025..186265b 100644 --- a/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs +++ b/Assets/Scripts/Editor/BuildProcess/PostBuildCopyEmptyFolders.cs @@ -12,6 +12,9 @@ public class PostBuildCopyEmptyFolders : MonoBehaviour [PostProcessBuildAttribute(1)] public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) { + // only for windows + if (target != BuildTarget.StandaloneWindows) return; + Debug.Log("### POSTBUILD : COPY EMPTY STREAMINGASSETS-FOLDERS ###"); Debug.Log("Build done: " + pathToBuiltProject); From 6fc5b5cfd89c8e531d6c1b7b3846692d2a391165 Mon Sep 17 00:00:00 2001 From: Bart Huylebroeck Date: Sun, 15 May 2022 09:37:27 +0200 Subject: [PATCH 07/48] fractional part should be calculated AFTER gray value has been added for continuous cycling effect --- Assets/Shaders/2D/Effects/ColorCycle.shader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Shaders/2D/Effects/ColorCycle.shader b/Assets/Shaders/2D/Effects/ColorCycle.shader index a41acc0..3d0c754 100644 --- a/Assets/Shaders/2D/Effects/ColorCycle.shader +++ b/Assets/Shaders/2D/Effects/ColorCycle.shader @@ -51,10 +51,10 @@ Shader "UnityLibrary/2D/Effects/ColorCycle" float gray = tex2D(_MainTex, i.uv).r; // get scrolling - float scroll = frac(_Time.x*_Speed); + float scroll = frac(gray + _Time.x*_Speed); // get gradient color from texture - fixed4 col = tex2D(_GradientTex,float2(gray+scroll,0.5)); + fixed4 col = tex2D(_GradientTex,float2(scroll,0.5)); return col; } From f1a9afac9d24b93bd8455b1e47ff409999b1eda8 Mon Sep 17 00:00:00 2001 From: mika Date: Thu, 2 Jun 2022 10:21:49 +0300 Subject: [PATCH 08/48] fix triangles error from point/line-topology meshes --- Assets/Scripts/Editor/Tools/GetSelectedMeshInfo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/Editor/Tools/GetSelectedMeshInfo.cs b/Assets/Scripts/Editor/Tools/GetSelectedMeshInfo.cs index e12f971..066da8d 100644 --- a/Assets/Scripts/Editor/Tools/GetSelectedMeshInfo.cs +++ b/Assets/Scripts/Editor/Tools/GetSelectedMeshInfo.cs @@ -59,7 +59,8 @@ void OnGUI() { int verts = meshes[i].sharedMesh.vertexCount; totalVertices += verts; - totalTris += meshes[i].sharedMesh.triangles.Length / 3; + // not for point/line meshes + if (meshes[i].sharedMesh.GetTopology(0) == MeshTopology.Triangles) totalTris += meshes[i].sharedMesh.triangles.Length / 3; totalMeshes++; topList.Add(i, verts); } From 8aaf2274a42d48c1023a8ea0572f094ddeaef633 Mon Sep 17 00:00:00 2001 From: mousedoc Date: Thu, 23 Jun 2022 12:28:46 +0900 Subject: [PATCH 09/48] Add legacy animation creator --- Assets/Scripts/Editor/Animation.meta | 8 ++++++ .../Animation/LegacyAnimationCreator.meta | 8 ++++++ .../LegacyAnimationCreator.cs | 28 +++++++++++++++++++ .../LegacyAnimationCreator.cs.meta | 11 ++++++++ 4 files changed, 55 insertions(+) create mode 100644 Assets/Scripts/Editor/Animation.meta create mode 100644 Assets/Scripts/Editor/Animation/LegacyAnimationCreator.meta create mode 100644 Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs create mode 100644 Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs.meta diff --git a/Assets/Scripts/Editor/Animation.meta b/Assets/Scripts/Editor/Animation.meta new file mode 100644 index 0000000..a9393f4 --- /dev/null +++ b/Assets/Scripts/Editor/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 344c9e72d34584041b61214522912d71 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/Animation/LegacyAnimationCreator.meta b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator.meta new file mode 100644 index 0000000..9fc6b69 --- /dev/null +++ b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e78d070eb9ba01749a33425b62b0fe5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs new file mode 100644 index 0000000..35f7ff2 --- /dev/null +++ b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs @@ -0,0 +1,28 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +public class LegacyAnimationCreator +{ + [MenuItem("Assets/Create/Legacy Animation", priority = 402)] + public static void CompressSelectedAnimationClips() + { + var clip = new AnimationClip(); + clip.legacy = true; + clip.name = "New Legacy Animation"; + + string path; + var selection = Selection.activeObject; + if (selection == null) + path = "Assets"; + else + path = AssetDatabase.GetAssetPath(selection.GetInstanceID()); + + path = Path.GetDirectoryName(path); + path += $"/{clip.name}.anim"; + + ProjectWindowUtil.CreateAsset(clip, path); + Selection.activeObject = clip; + EditorUtility.SetDirty(clip); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs.meta b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs.meta new file mode 100644 index 0000000..5bd716f --- /dev/null +++ b/Assets/Scripts/Editor/Animation/LegacyAnimationCreator/LegacyAnimationCreator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d536889e20faa9d47b7def4f46203b81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 70073f18dd40bc1b94da3ef53627c21ddb722d33 Mon Sep 17 00:00:00 2001 From: emir Date: Mon, 5 Sep 2022 01:09:28 +0300 Subject: [PATCH 10/48] =?UTF-8?q?Added=20SaveUtility=20static=20class=20wi?= =?UTF-8?q?th=20generic=20methods.=20->=20#=20For:=C2=A0Sav&Load=20any=20s?= =?UTF-8?q?erialized=20class=20#?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/Utilities/SaveUtility.cs | 70 ++++++++++++++++++++ Assets/Scripts/Utilities/SaveUtility.cs.meta | 11 +++ 2 files changed, 81 insertions(+) create mode 100644 Assets/Scripts/Utilities/SaveUtility.cs create mode 100644 Assets/Scripts/Utilities/SaveUtility.cs.meta diff --git a/Assets/Scripts/Utilities/SaveUtility.cs b/Assets/Scripts/Utilities/SaveUtility.cs new file mode 100644 index 0000000..96bb9b0 --- /dev/null +++ b/Assets/Scripts/Utilities/SaveUtility.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Utilities +{ + public static class SaveUtility + { + /* --- Usage ---- + + -- Lets say we have a serialized class called Save -- + + [System.Serializable] + public class Save + { + public int testInt; + public List TestStrings = new List(); + } + + -- For saving this class we would do the following -->> -- + + Save save = new Save(); + save.testInt = 5; + save.TestStrings.Add("Hello"); + + SaveUtility.Save(save, "testPath"); + + -- For loading this class we would do the following --> -- + + Save save = SaveUtility.Load("testPath"); + + Important : Since save operation uses PlayerPrefs and does not contain any encrypting. Dont save&load any confidential data using this class. + + --- End of Usage ---- */ + + + /// + /// Saves any serialized class on the specified savepath. + /// + public static void Save(this T save, string savePath) + where T : class + { + var data = JsonUtility.ToJson(save); + PlayerPrefs.SetString(savePath, data); + } + + /// + /// Loads and returns the saved class on the specified savepath. + /// If no save is found, it will return a new instance of the class. + /// + /// Loaded serialized save class + public static T Load(TSt path) + where T : class, new() + where TSt : IComparable, ICloneable, IConvertible, IComparable, IEnumerable, IEnumerable, IEquatable + { + var data = new T(); + + if (PlayerPrefs.HasKey(path as string) == false) + { + data.Save(path as string); + } + + { + data = JsonUtility.FromJson(PlayerPrefs.GetString(path as string)); + } + return data; + } + } +} diff --git a/Assets/Scripts/Utilities/SaveUtility.cs.meta b/Assets/Scripts/Utilities/SaveUtility.cs.meta new file mode 100644 index 0000000..390ab63 --- /dev/null +++ b/Assets/Scripts/Utilities/SaveUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d8aad24cf3d7485c9507bf763b79d42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From e12d3618ed22105e1a38038120a756e9d3345d53 Mon Sep 17 00:00:00 2001 From: mika Date: Sat, 3 Dec 2022 13:43:18 +0200 Subject: [PATCH 11/48] add LineRenderer_ClipStartEnd.shader --- .../LineRenderer_ClipStartEnd.shader | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Assets/Shaders/2D/LineRenderer/LineRenderer_ClipStartEnd.shader diff --git a/Assets/Shaders/2D/LineRenderer/LineRenderer_ClipStartEnd.shader b/Assets/Shaders/2D/LineRenderer/LineRenderer_ClipStartEnd.shader new file mode 100644 index 0000000..7971f3c --- /dev/null +++ b/Assets/Shaders/2D/LineRenderer/LineRenderer_ClipStartEnd.shader @@ -0,0 +1,62 @@ +Shader "UnityLibrary/LineRenderer/ClipStartEnd" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _Start ("Start", Range (0.0,1.0)) = 0.25 + _End ("End", Range (0.0,1.0)) = 0.75 + } + + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + float4 color : COLOR; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + float4 color : COLOR; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float _Start; + float _End; + + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + o.color = v.color; + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.uv)*i.color; + clip(-(i.uv.x <_Start || i.uv.x > _End)); + // return fixed4(i.uv.x,0,0,0); // view UV x + return col; + } + ENDCG + } + } +} \ No newline at end of file From 1a555e190570b4c86b8e35090bd4acada9cd904d Mon Sep 17 00:00:00 2001 From: mika Date: Sat, 3 Dec 2022 21:50:06 +0200 Subject: [PATCH 12/48] add NavMeshAgentExample.cs --- .../Docs/UnityEngine/NavMeshAgentExample.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Assets/Scripts/Docs/UnityEngine/NavMeshAgentExample.cs diff --git a/Assets/Scripts/Docs/UnityEngine/NavMeshAgentExample.cs b/Assets/Scripts/Docs/UnityEngine/NavMeshAgentExample.cs new file mode 100644 index 0000000..bae418b --- /dev/null +++ b/Assets/Scripts/Docs/UnityEngine/NavMeshAgentExample.cs @@ -0,0 +1,23 @@ +// made with chatGPT + +using UnityEngine; +using UnityEngine.AI; + +namespace UnityLibrary +{ + public class NavMeshAgentExample : MonoBehaviour + { + public Transform target; + + private NavMeshAgent agent; + + void Start() + { + // Get the NavMeshAgent component on this game object + agent = GetComponent(); + + // Set the destination of the NavMeshAgent to the target Transform + agent.destination = target.position; + } + } +} From a60e3cf7f40a816f3d06ed392e30080b6afb9c3c Mon Sep 17 00:00:00 2001 From: ForlornU <101473036+ForlornU@users.noreply.github.com> Date: Sat, 15 Apr 2023 06:42:02 +0200 Subject: [PATCH 13/48] Rewrite of cameraShake Lots of changes and improvements, the original purpose remains but in a better format Class that calls for the camera to shake passes along the values for intensity and duration to the camera which has "influence modifers" for how sensetive it is to shaking Based on a timed duration instead of a dickle decay value magical numbers, bools and such are gone --- Assets/Scripts/Camera/CameraShake.cs | 78 +++++++++++++++------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/Assets/Scripts/Camera/CameraShake.cs b/Assets/Scripts/Camera/CameraShake.cs index d8814bb..48a88e6 100644 --- a/Assets/Scripts/Camera/CameraShake.cs +++ b/Assets/Scripts/Camera/CameraShake.cs @@ -1,58 +1,66 @@ using UnityEngine; using System.Collections; -// usage: attach this script into camera, call Shake() method to start -// source: http://answers.unity3d.com/answers/992509/view.html +/* + * Usage: attach this script to a camera or any other object, call Shake() method to start shaking it +* To turn off, change influence to zero +* Attach the camera to an empty game object to keep its local position and rotation +*/ namespace UnityLibrary { public class CameraShake : MonoBehaviour { - public bool shakePosition; - public bool shakeRotation; - - public float shakeIntensityMin = 0.1f; - public float shakeIntensityMax = 0.5f; - public float shakeDecay = 0.02f; + [Range(0f, 1f)] + public float shakeInfluence = 0.5f; + [Range(0f, 10f)] + public float rotationInfluence = 0f; private Vector3 OriginalPos; private Quaternion OriginalRot; - private bool isShakeRunning = false; - // call this function to start shaking - public void Shake() +/// +/// Will shake the camera with a random value between minIntensity and maxIntensity for duration +/// +/// +/// +/// + public void Shake(float minIntensity, float maxIntensity, float duration) { + if (isShakeRunning) + return; + OriginalPos = transform.position; OriginalRot = transform.rotation; - StartCoroutine("ProcessShake"); + + float shake = Random.Range(minIntensity, maxIntensity) * shakeInfluence; + duration *= shakeInfluence; + + StartCoroutine(ProcessShake(shake, duration)); } - IEnumerator ProcessShake() + IEnumerator ProcessShake(float shake, float duration) { - if (!isShakeRunning) + isShakeRunning = true; + float countdown = duration; + float initialShake = shake; + + while (countdown > 0) { - isShakeRunning = true; - float currentShakeIntensity = Random.Range(shakeIntensityMin, shakeIntensityMax); - - while (currentShakeIntensity > 0) - { - if (shakePosition) - { - transform.position = OriginalPos + Random.insideUnitSphere * currentShakeIntensity; - } - if (shakeRotation) - { - transform.rotation = new Quaternion(OriginalRot.x + Random.Range(-currentShakeIntensity, currentShakeIntensity) * .2f, - OriginalRot.y + Random.Range(-currentShakeIntensity, currentShakeIntensity) * .2f, - OriginalRot.z + Random.Range(-currentShakeIntensity, currentShakeIntensity) * .2f, - OriginalRot.w + Random.Range(-currentShakeIntensity, currentShakeIntensity) * .2f); - } - currentShakeIntensity -= shakeDecay; - yield return null; - } - - isShakeRunning = false; + countdown -= Time.deltaTime; + + float lerpIntensity = countdown / duration; + shake = Mathf.Lerp(0f, initialShake, lerpIntensity); + + transform.position = OriginalPos + Random.insideUnitSphere * shake; + transform.rotation = Quaternion.Euler(OriginalRot.eulerAngles + Random.insideUnitSphere * shake * rotationInfluence); + + yield return null; } + + transform.position = OriginalPos; + transform.rotation = OriginalRot; + isShakeRunning = false; } } } \ No newline at end of file From d4eeaeb201b8bd99342656dfe17b7f23a373afc8 Mon Sep 17 00:00:00 2001 From: Falcon Date: Fri, 28 Apr 2023 18:59:17 +0900 Subject: [PATCH 14/48] Auto Resolution Script It's useful for overcoming very slight differences. It is difficult to apply a large changes in which the resolution is reversed. It can be used appropriately in situations where resolution is important in mobile-like environments. Attach this script to the camera and enter the desired resolution. --- Assets/Scripts/Camera/AutoResolution.cs | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Assets/Scripts/Camera/AutoResolution.cs diff --git a/Assets/Scripts/Camera/AutoResolution.cs b/Assets/Scripts/Camera/AutoResolution.cs new file mode 100644 index 0000000..87fd874 --- /dev/null +++ b/Assets/Scripts/Camera/AutoResolution.cs @@ -0,0 +1,58 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class AutoResolution : MonoBehaviour +{ + public int setWidth = 1440; + public int setHeight = 2560; + + private void Start() + { + // Get the main camera and its current dimensions + Camera camera = Camera.main; + Rect rect = camera.rect; + + // Calculate the scale height and width of the screen + float scaleHeight = ((float)Screen.width / Screen.height) / ((float)9 / 16); + float scaleWidth = 1f / scaleHeight; + + // Adjust the camera's dimensions based on the scale height and width + if (scaleHeight < 1) + { + rect.height = scaleHeight; + rect.y = (1f - scaleHeight) / 2f; + } + else + { + rect.width = scaleWidth; + rect.x = (1f - scaleWidth) / 2f; + } + + camera.rect = rect; + + SetResolution(); + } + + public void SetResolution() + { + // Get the current device's screen dimensions + int deviceWidth = Screen.width; + int deviceHeight = Screen.height; + + // Set the screen resolution to the desired dimensions, while maintaining aspect ratio + Screen.SetResolution(setWidth, (int)(((float)deviceHeight / deviceWidth) * setWidth), true); + + // Adjust the camera's dimensions based on the new resolution + if ((float)setWidth / setHeight < (float)deviceWidth / deviceHeight) + { + float newWidth = ((float)setWidth / setHeight) / ((float)deviceWidth / deviceHeight); + Camera.main.rect = new Rect((1f - newWidth) / 2f, 0f, newWidth, 1f); + } + else + { + float newHeight = ((float)deviceWidth / deviceHeight) / ((float)setWidth / setHeight); + Camera.main.rect = new Rect(0f, (1f - newHeight) / 2f, 1f, newHeight); // 새로운 Rect 적용 + } + } +} From 02ac2cde7f6b7c127461e09fa58f0a5fce0b6f7d Mon Sep 17 00:00:00 2001 From: Chase Duffman <74204097+xXxT0SHIIIxXx@users.noreply.github.com> Date: Sat, 6 May 2023 20:24:37 -0700 Subject: [PATCH 15/48] Update README.md Added custom Logo for Unity Library --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aca75b1..2facccc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# Unity Library -:tada: Welcome to Unity Library :tada: +# ![Unity Library](https://i.imgur.com/btbDvqv.png) + +:tada: Welcome to Unity Library :tada: Useful scripts, snippets and shaders here it is gathered for free. From c06129b3beaa7b0552cdf52026472a446515d2d2 Mon Sep 17 00:00:00 2001 From: Chase Duffman <74204097+xXxT0SHIIIxXx@users.noreply.github.com> Date: Sun, 7 May 2023 10:06:20 -0400 Subject: [PATCH 16/48] Adding Logos for Light and Dark Mode Added Logos for users using Dark Mode and Light Mode --- Logos/Unity_Library_Black.png | Bin 0 -> 33584 bytes Logos/Unity_Library_White.png | Bin 0 -> 35506 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Logos/Unity_Library_Black.png create mode 100644 Logos/Unity_Library_White.png diff --git a/Logos/Unity_Library_Black.png b/Logos/Unity_Library_Black.png new file mode 100644 index 0000000000000000000000000000000000000000..b5761a5ca1b6c229da5ca4c7c41e05a6239d70e2 GIT binary patch literal 33584 zcmdSA1z42bx<3qvf~cfOO9=>yzzkE83W(CJsN~QgEnNm(3P=h_hY|uJk_rqB0!oR5 zG!lYH$G09Z_kQ;|?>^uEIx%xGGtcv^b+0>qcdWo)NkRG;2|WoO9^SDlmnBv3@Ca7$ z@bJlr4}m)$j`OpDi(94=5=y36EFRwJ2M!O)WNVa;<2+X`NS$G_C%0)x`jo^%^6517 zY%;0k!JKoJvl1p|msL_elMygi_=-cB{pg{U=}CKVfS15+hdW zT2<3X^QC3np=L$?uCn!0lT%N5IUW^P3waO_PS-}gv$PXMGGvTzIH$_L_f>wM^Q|I1 z$Bx(X^V{xo!dY>T*w1$HmrO?oINo<%zG*AJCh1iB5dXeaWJ2~*+$W33s^d2nr;a+Q zDe``(&N|d>_lQ;atg!A_po`_nZyc}f^#nMJ6>p0nmD%ofTvj%CEKHiBa^#_=-O#nV zl4>6(d*`@_{MrW`T!R$Kft?6m1iQ=i1YwTI&0XQSmRhG`SN@|rS9`V@?^TONtlnH* zedo|@JnZiM`QpbaR*bxRVCB`GLm{k1$D&XUybgF*h2Cyja6U7TT54J`fPJyS*E&2^ z=^GMhrcrFymdH}cQ8h(M8mfDF-dAH6FQwafC~x9J0x-Z~>&u#Ucz8!Bp+Ef2j~-jV z99{NO*X&jF99gVwt&B`93|Z`*tqoZWolK4JNT5#=7U%^NfRP9yP-r9uiR1?_L5v^< zrU!nYp)2r0@$(D7_yzdk;J3iuouA(Vdf*P?*L@NsY`=kk{+|z!5JB*Qq5px<_x5lB za3A~@Fx+oPg8K0Q8X0;3jSgOz{V#qb294qu1Q*{q(u02g_CoU;Vfn$JB%n7C0Fq|^ z#*b@30i+<(2njI!B-X{VMX>(6!fQ{dDM`8qCdz?aA{!Ii!^jwjrpQ)_!H9trfhZ(bG{lH@Ptg9GURQ8-!<225@MIQc_`B=sGp19*7M z@BeZXCrfKQ67aD%2Iwb10>{FQP{1Zg0VEu$k3^sZVf>JGkwAAyL%0D9W@x0ZuWtl{ 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 nFG8?W-wdA;Qb-4=6 literal 0 HcmV?d00001 diff --git a/Logos/Unity_Library_White.png b/Logos/Unity_Library_White.png new file mode 100644 index 0000000000000000000000000000000000000000..f0d5651376829d2e549d105a38e30ac362637206 GIT binary patch literal 35506 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 MW!^}aN*eqBKjGKi`~Uy| literal 0 HcmV?d00001 From 9e876bc7e4ce9c0282b5e5da42caf0928057f39c Mon Sep 17 00:00:00 2001 From: Chase Duffman <74204097+xXxT0SHIIIxXx@users.noreply.github.com> Date: Sun, 7 May 2023 10:09:35 -0400 Subject: [PATCH 17/48] Update README.md Added Logos for light mode and dark mode --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2facccc..e7f51b0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# ![Unity Library](https://i.imgur.com/btbDvqv.png) - -:tada: Welcome to Unity Library :tada: +# ![Unity Library](https://raw.githubusercontent.com/xXxT0SHIIIxXx/UnityLibrary/master/Logos/Unity_Library_White.png#gh-dark-mode-only) +# ![Unity Library](https://raw.githubusercontent.com/xXxT0SHIIIxXx/UnityLibrary/master/Logos/Unity_Library_Black.png#gh-light-mode-only) +:tada: Welcome to Unity Library :tada: Useful scripts, snippets and shaders here it is gathered for free. From 3088d763e2446029ad68119f1eb516d943cd3625 Mon Sep 17 00:00:00 2001 From: Shubham Kumar <96144990+KatyaanShubham@users.noreply.github.com> Date: Sun, 16 Jul 2023 19:20:28 +0530 Subject: [PATCH 18/48] Update Glow.shader Explanation of changes: 1. Indentation: The entire code block inside Shader "Custom/Glow" is indented one level for better readability. 2. Spacing: Added proper spacing between the curly braces {} for clarity. --- Assets/Shaders/2D/Effects/Glow.shader | 94 ++------------------------- 1 file changed, 4 insertions(+), 90 deletions(-) diff --git a/Assets/Shaders/2D/Effects/Glow.shader b/Assets/Shaders/2D/Effects/Glow.shader index 775b7d2..97da796 100644 --- a/Assets/Shaders/2D/Effects/Glow.shader +++ b/Assets/Shaders/2D/Effects/Glow.shader @@ -1,117 +1,31 @@ -Shader "Custom/Glow" { - - - +@@ -1,117 +1,30 @@ +Shader "Custom/Glow" { Properties { - - - _Color ("Color", Color) = (1,1,1,1) - - - } - - SubShader { - - - Tags { "RenderType"="Transparent" } - - - LOD 200 - - - ZTest Always - - - Cull Off - - - - - - - - - - CGPROGRAM - - - #pragma surface surf Lambert decal:add - - - - - - float4 _Color; - - - - - - struct Input { - - - float3 viewDir; - - - float3 worldNormal; - - - }; - - - - - - void surf (Input IN, inout SurfaceOutput o) { - - - - o.Alpha = _Color.a * pow(abs(dot(normalize(IN.viewDir), - - - - normalize(IN.worldNormal))),4.0); - - - + o.Alpha = _Color.a * pow(abs(dot(normalize(IN.viewDir), normalize(IN.worldNormal))), 4.0); o.Emission = _Color.rgb * o.Alpha; - - - } - - - ENDCG - - - - } - - + } FallBack "Diffuse" - - - } From dda79f9892ef3668a5b2d19b3f416491f1e53c3e Mon Sep 17 00:00:00 2001 From: Shubham Kumar <96144990+KatyaanShubham@users.noreply.github.com> Date: Sun, 16 Jul 2023 19:25:50 +0530 Subject: [PATCH 19/48] Update AssetBundleLoader.cs Explanation of changes: 1. Added using UnityEngine.Networking; to import the required namespace. 2. Created a bundleName variable to specify the name of the asset bundle you are loading. Adjust it according to your asset bundle's name. 3. Added Caching.ClearOtherCachedVersions(bundleName, Hash128.Parse("0")); before starting the download. This line clears the cache for previous versions of the asset bundle with the specified name. --- .../Scripts/AssetBundles/AssetBundleLoader.cs | 76 +++++-------------- 1 file changed, 21 insertions(+), 55 deletions(-) diff --git a/Assets/Scripts/AssetBundles/AssetBundleLoader.cs b/Assets/Scripts/AssetBundles/AssetBundleLoader.cs index d31ae28..db53c54 100644 --- a/Assets/Scripts/AssetBundles/AssetBundleLoader.cs +++ b/Assets/Scripts/AssetBundles/AssetBundleLoader.cs @@ -2,47 +2,34 @@ using UnityEngine; using UnityEngine.Networking; -// AssetBundle cache checker & loader with caching -// worsk by loading .manifest file from server and parsing hash string from it - namespace UnityLibrary { public class AssetBundleLoader : MonoBehaviour { public string assetBundleURL = "http://localhost/bundle"; + private string bundleName = "bundle"; void Start() { - //StartCoroutine(DownloadAndCache(assetBundleURL)); + StartCoroutine(DownloadAndCache(assetBundleURL)); } - /// - /// load assetbundle manifest, check hash, load actual bundle with hash parameter to use caching - /// instantiate gameobject - /// - /// full url to assetbundle file - /// optional parameter to access specific asset from assetbundle - /// IEnumerator DownloadAndCache(string bundleURL, string assetName = "") { - // Wait for the Caching system to be ready while (!Caching.ready) { yield return null; } - // if you want to always load from server, can clear cache first - // Caching.CleanCache(); + // Clear cache for previous versions of the asset bundle + Caching.ClearOtherCachedVersions(bundleName, Hash128.Parse("0")); - // get current bundle hash from server, random value added to avoid caching UnityWebRequest www = UnityWebRequest.Get(bundleURL + ".manifest?r=" + (Random.value * 9999999)); - Debug.Log("Loading manifest:" + bundleURL + ".manifest"); + Debug.Log("Loading manifest: " + bundleURL + ".manifest"); - // wait for load to finish - yield return www.Send(); + yield return www.SendWebRequest(); - // if received error, exit - if (www.isNetworkError == true) + if (www.isNetworkError) { Debug.LogError("www error: " + www.error); www.Dispose(); @@ -50,43 +37,38 @@ IEnumerator DownloadAndCache(string bundleURL, string assetName = "") yield break; } - // create empty hash string - Hash128 hashString = (default(Hash128));// new Hash128(0, 0, 0, 0); + Hash128 hashString = default(Hash128); - // check if received data contains 'ManifestFileVersion' if (www.downloadHandler.text.Contains("ManifestFileVersion")) { - // extract hash string from the received data, TODO should add some error checking here var hashRow = www.downloadHandler.text.ToString().Split("\n".ToCharArray())[5]; hashString = Hash128.Parse(hashRow.Split(':')[1].Trim()); - if (hashString.isValid == true) + if (hashString.isValid) { - // we can check if there is cached version or not - if (Caching.IsVersionCached(bundleURL, hashString) == true) + if (Caching.IsVersionCached(bundleURL, hashString)) { Debug.Log("Bundle with this hash is already cached!"); - } else + } + else { - Debug.Log("No cached version founded for this hash.."); + Debug.Log("No cached version found for this hash.."); } - } else + } + else { - // invalid loaded hash, just try loading latest bundle - Debug.LogError("Invalid hash:" + hashString); + Debug.LogError("Invalid hash: " + hashString); yield break; } - - } else + } + else { Debug.LogError("Manifest doesn't contain string 'ManifestFileVersion': " + bundleURL + ".manifest"); yield break; } - // now download the actual bundle, with hashString parameter it uses cached version if available www = UnityWebRequestAssetBundle.GetAssetBundle(bundleURL + "?r=" + (Random.value * 9999999), hashString, 0); - // wait for load to finish yield return www.SendWebRequest(); if (www.error != null) @@ -97,42 +79,26 @@ IEnumerator DownloadAndCache(string bundleURL, string assetName = "") yield break; } - // get bundle from downloadhandler AssetBundle bundle = ((DownloadHandlerAssetBundle)www.downloadHandler).assetBundle; - GameObject bundlePrefab = null; - // if no asset name is given, take the first/main asset if (assetName == "") { bundlePrefab = (GameObject)bundle.LoadAsset(bundle.GetAllAssetNames()[0]); - } else - { // use asset name to access inside bundle + } + else + { bundlePrefab = (GameObject)bundle.LoadAsset(assetName); } - // if we got something out if (bundlePrefab != null) { - - // instantiate at 0,0,0 and without rotation Instantiate(bundlePrefab, Vector3.zero, Quaternion.identity); - - /* - // fix pink shaders, NOTE: not always needed.. - foreach (Renderer r in go.GetComponentsInChildren(includeInactive: true)) - { - // FIXME: creates multiple materials, not good - var material = Shader.Find(r.material.shader.name); - r.material.shader = null; - r.material.shader = material; - }*/ } www.Dispose(); www = null; - // try to cleanup memory Resources.UnloadUnusedAssets(); bundle.Unload(false); bundle = null; From d2ee8cfde0a18206086ca7917700fca25b163ca3 Mon Sep 17 00:00:00 2001 From: mika Date: Thu, 19 Oct 2023 09:14:56 +0300 Subject: [PATCH 20/48] Create Diffuse (2 Sided Light).shader --- .../2D/Sprites/Diffuse (2 Sided Light).shader | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Assets/Shaders/2D/Sprites/Diffuse (2 Sided Light).shader diff --git a/Assets/Shaders/2D/Sprites/Diffuse (2 Sided Light).shader b/Assets/Shaders/2D/Sprites/Diffuse (2 Sided Light).shader new file mode 100644 index 0000000..cf47668 --- /dev/null +++ b/Assets/Shaders/2D/Sprites/Diffuse (2 Sided Light).shader @@ -0,0 +1,79 @@ +// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) +// lights up sprites from both sides + +Shader "Sprites/Diffuse (2 Sided Light)" +{ + Properties + { + [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {} + _Color("Tint", Color) = (1,1,1,1) + [MaterialToggle] PixelSnap("Pixel snap", Float) = 0 + [HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1) + [HideInInspector] _Flip("Flip", Vector) = (1,1,1,1) + [PerRendererData] _AlphaTex("External Alpha", 2D) = "white" {} + [PerRendererData] _EnableExternalAlpha("Enable External Alpha", Float) = 0 + } + + SubShader + { + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + Cull Off + Lighting Off + ZWrite Off + Blend One OneMinusSrcAlpha + + CGPROGRAM + //#pragma surface surf Lambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing + #pragma surface surf TwoSidedLambert vertex:vert nofog nolightmap nodynlightmap keepalpha noinstancing + #pragma multi_compile_local _ PIXELSNAP_ON + #pragma multi_compile _ ETC1_EXTERNAL_ALPHA + #include "UnitySprites.cginc" + + struct Input + { + float2 uv_MainTex; + fixed4 color; + }; + + // added "abs" 2 sided lighting + half4 LightingTwoSidedLambert(SurfaceOutput s, half3 lightDir, half atten) { + half NdotL = abs(dot(s.Normal, lightDir)); + half4 c; + c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten); + c.a = s.Alpha; + return c; + } + + void vert(inout appdata_full v, out Input o) + { + v.vertex = UnityFlipSprite(v.vertex, _Flip); + + #if defined(PIXELSNAP_ON) + v.vertex = UnityPixelSnap(v.vertex); + #endif + + //v.normal.z *= -1; + + UNITY_INITIALIZE_OUTPUT(Input, o); + o.color = v.color * _Color * _RendererColor; + } + + void surf(Input IN, inout SurfaceOutput o) + { + fixed4 c = SampleSpriteTexture(IN.uv_MainTex) * IN.color; + o.Albedo = c.rgb * c.a; + o.Alpha = c.a; + } + ENDCG + } + + Fallback "Transparent/VertexLit" +} From 329f7d8f2bb8306b5df409f5ab03d1cd44595455 Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 17 May 2024 11:35:26 +0300 Subject: [PATCH 21/48] Add editor tool to replace string in selected gameobject names --- .../ReplaceCharacterInGameObjectNames.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Assets/Scripts/Editor/BatchTools/ReplaceCharacterInGameObjectNames.cs diff --git a/Assets/Scripts/Editor/BatchTools/ReplaceCharacterInGameObjectNames.cs b/Assets/Scripts/Editor/BatchTools/ReplaceCharacterInGameObjectNames.cs new file mode 100644 index 0000000..105bc74 --- /dev/null +++ b/Assets/Scripts/Editor/BatchTools/ReplaceCharacterInGameObjectNames.cs @@ -0,0 +1,69 @@ +// editor tool to replace string from selected GameObject names + +using UnityEngine; +using UnityEditor; +using UnityEditor.SceneManagement; + +namespace UnityLibrary.Tools +{ + public class ReplaceCharacterInGameObjectNames : EditorWindow + { + private string searchString = "|"; + private string replaceString = "@"; + + [MenuItem("Tools/Replace Characters in GameObject Names")] + public static void ShowWindow() + { + GetWindow("Replace Characters"); + } + + private void OnGUI() + { + GUILayout.Label("Replace Characters in Selected GameObject Names", EditorStyles.boldLabel); + + searchString = EditorGUILayout.TextField("Search String", searchString); + replaceString = EditorGUILayout.TextField("Replace String", replaceString); + + int selectedObjectCount = Selection.gameObjects.Length; + GUILayout.Label($"Selected GameObjects: {selectedObjectCount}", EditorStyles.label); + + if (GUILayout.Button("Replace")) + { + ReplaceCharacters(); + } + } + + private void ReplaceCharacters() + { + GameObject[] selectedObjects = Selection.gameObjects; + + if (selectedObjects.Length == 0) + { + Debug.LogWarning("No GameObjects selected."); + return; + } + + // Start a new undo group + Undo.IncrementCurrentGroup(); + Undo.SetCurrentGroupName("Replace Character in GameObject Names"); + int undoGroup = Undo.GetCurrentGroup(); + + foreach (GameObject obj in selectedObjects) + { + if (obj.name.Contains(searchString)) + { + Undo.RecordObject(obj, "Replace Character in GameObject Name"); + obj.name = obj.name.Replace(searchString, replaceString); + EditorUtility.SetDirty(obj); + } + } + + // End the undo group + Undo.CollapseUndoOperations(undoGroup); + + EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); + + Debug.Log($"Replaced '{searchString}' with '{replaceString}' in the names of selected GameObjects."); + } + } +} From 2296f02dabe31b8d5a1491308c82e9f13c761010 Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 17 May 2024 11:55:08 +0300 Subject: [PATCH 22/48] add editor tool to copy selected gameobject names to clipboard as a list --- .../Editor/BatchTools/CopyGameObjectNames.cs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs diff --git a/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs b/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs new file mode 100644 index 0000000..de28cd4 --- /dev/null +++ b/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs @@ -0,0 +1,55 @@ +// editor tool to copy names of selected GameObjects to clipboard as a list (so you can paste them in Excel or others..) + +using UnityEngine; +using UnityEditor; +using System.Text; +namespace UnityLibrary.Tools +{ + public class CopyGameObjectNames : EditorWindow + { + private string gameObjectNames = string.Empty; + + [MenuItem("Tools/Copy GameObject Names")] + public static void ShowWindow() + { + GetWindow("Copy GameObject Names"); + } + + private void OnGUI() + { + GUILayout.Label("Copy Names of Selected GameObjects", EditorStyles.boldLabel); + + if (GUILayout.Button("Fetch Names")) + { + FetchNames(); + } + + GUILayout.Label("GameObject Names:", EditorStyles.label); + gameObjectNames = EditorGUILayout.TextArea(gameObjectNames, GUILayout.Height(200)); + + if (GUILayout.Button("Copy to Clipboard")) + { + CopyToClipboard(); + } + } + + private void FetchNames() + { + StringBuilder sb = new StringBuilder(); + GameObject[] selectedObjects = Selection.gameObjects; + + foreach (GameObject obj in selectedObjects) + { + sb.AppendLine(obj.name); + } + + gameObjectNames = sb.ToString(); + } + + private void CopyToClipboard() + { + EditorGUIUtility.systemCopyBuffer = gameObjectNames; + Debug.Log("GameObject names copied to clipboard."); + } + } +} \ No newline at end of file From a39816f5b4a5a2a9d305ec13ac3aef017d49c9b9 Mon Sep 17 00:00:00 2001 From: mika Date: Fri, 17 May 2024 12:21:40 +0300 Subject: [PATCH 23/48] Fix CopyGameObjectNames.cs to copy in correct hierarchy order --- Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs b/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs index de28cd4..40bf0d0 100644 --- a/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs +++ b/Assets/Scripts/Editor/BatchTools/CopyGameObjectNames.cs @@ -3,6 +3,7 @@ using UnityEngine; using UnityEditor; using System.Text; +using System.Linq; namespace UnityLibrary.Tools { public class CopyGameObjectNames : EditorWindow @@ -38,7 +39,10 @@ private void FetchNames() StringBuilder sb = new StringBuilder(); GameObject[] selectedObjects = Selection.gameObjects; - foreach (GameObject obj in selectedObjects) + // Sort the selected objects by their sibling index + var sortedObjects = selectedObjects.OrderBy(go => go.transform.GetSiblingIndex()).ToArray(); + + foreach (GameObject obj in sortedObjects) { sb.AppendLine(obj.name); } @@ -52,4 +56,4 @@ private void CopyToClipboard() Debug.Log("GameObject names copied to clipboard."); } } -} \ No newline at end of file +} From f13f9beb250f96c99661b967b4fce3e92ccc8949 Mon Sep 17 00:00:00 2001 From: mika Date: Tue, 6 Aug 2024 13:17:11 +0300 Subject: [PATCH 24/48] Create RendererTypeCounter.cs --- .../Editor/Tools/RendererTypeCounter.cs | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Assets/Scripts/Editor/Tools/RendererTypeCounter.cs diff --git a/Assets/Scripts/Editor/Tools/RendererTypeCounter.cs b/Assets/Scripts/Editor/Tools/RendererTypeCounter.cs new file mode 100644 index 0000000..0cc0ce2 --- /dev/null +++ b/Assets/Scripts/Editor/Tools/RendererTypeCounter.cs @@ -0,0 +1,108 @@ +// shows renderer stats from selected objects in the editor + +using UnityEngine; +using UnityEditor; + +namespace UnityLibrary +{ + public class RendererTypeCounter : EditorWindow + { + private int activeMeshRendererCount; + private int inactiveMeshRendererCount; + private int activeSkinnedMeshRendererCount; + private int inactiveSkinnedMeshRendererCount; + private int activeSpriteRendererCount; + private int inactiveSpriteRendererCount; + private int totalGameObjectCount; + + [MenuItem("Tools/Renderer Type Counter")] + public static void ShowWindow() + { + GetWindow("Renderer Type Counter"); + } + + private void OnGUI() + { + if (GUILayout.Button("Count Renderers")) + { + CountRenderersInSelection(); + } + + GUILayout.Space(10); + + GUILayout.Label("Active Mesh Renderers: " + activeMeshRendererCount); + GUILayout.Label("Inactive Mesh Renderers: " + inactiveMeshRendererCount); + GUILayout.Label("Active Skinned Mesh Renderers: " + activeSkinnedMeshRendererCount); + GUILayout.Label("Inactive Skinned Mesh Renderers: " + inactiveSkinnedMeshRendererCount); + GUILayout.Label("Active Sprite Renderers: " + activeSpriteRendererCount); + GUILayout.Label("Inactive Sprite Renderers: " + inactiveSpriteRendererCount); + GUILayout.Label("Total GameObjects: " + totalGameObjectCount); + } + + private void CountRenderersInSelection() + { + activeMeshRendererCount = 0; + inactiveMeshRendererCount = 0; + activeSkinnedMeshRendererCount = 0; + inactiveSkinnedMeshRendererCount = 0; + activeSpriteRendererCount = 0; + inactiveSpriteRendererCount = 0; + totalGameObjectCount = 0; + + foreach (GameObject obj in Selection.gameObjects) + { + CountRenderersRecursively(obj); + } + + Repaint(); + } + + private void CountRenderersRecursively(GameObject obj) + { + totalGameObjectCount++; + + bool isActive = obj.activeInHierarchy; + + if (obj.GetComponent()) + { + if (isActive) + { + activeMeshRendererCount++; + } + else + { + inactiveMeshRendererCount++; + } + } + + if (obj.GetComponent()) + { + if (isActive) + { + activeSkinnedMeshRendererCount++; + } + else + { + inactiveSkinnedMeshRendererCount++; + } + } + + if (obj.GetComponent()) + { + if (isActive) + { + activeSpriteRendererCount++; + } + else + { + inactiveSpriteRendererCount++; + } + } + + foreach (Transform child in obj.transform) + { + CountRenderersRecursively(child.gameObject); + } + } + } +} From 4532dd6984ad76ed9b4ea0d1458be943307b6b7f Mon Sep 17 00:00:00 2001 From: Hasan Bayat Date: Fri, 4 Oct 2024 11:49:26 +0330 Subject: [PATCH 25/48] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7f51b0..f185093 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Feel free to [:postbox: Post your ideas/comments/improvements/recommendations](h ## Credits - [UnityCoder (mika)](https://github.com/unitycoder) (Owner) -- [EmpireWorld (Hasan Bayat)](https://github.com/EmpireWorld) (Owner) +- [hasanbayatme (Hasan Bayat)](https://github.com/hasanbayatme) (Owner) - [Lootheo (Manuel Otheo)](https://github.com/Lootheo) (Member) - [igorrafael (Igor Rafael de Sousa)](https://github.com/igorrafael) (Member) - [nrlnd](https://github.com/nrlnd) (Member) From 3e2d55b01d812be62b5239fc8f2d4c3b3edd2a2b Mon Sep 17 00:00:00 2001 From: mika Date: Tue, 22 Oct 2024 21:46:37 +0300 Subject: [PATCH 26/48] Create FindWhatButtonCallsMyMethod.cs --- .../Tools/FindWhatButtonCallsMyMethod.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Assets/Scripts/Editor/Tools/FindWhatButtonCallsMyMethod.cs diff --git a/Assets/Scripts/Editor/Tools/FindWhatButtonCallsMyMethod.cs b/Assets/Scripts/Editor/Tools/FindWhatButtonCallsMyMethod.cs new file mode 100644 index 0000000..e67f45b --- /dev/null +++ b/Assets/Scripts/Editor/Tools/FindWhatButtonCallsMyMethod.cs @@ -0,0 +1,69 @@ +// prints out which buttons in current scene are referencing your given method + +using UnityEngine; +using UnityEngine.UI; +using UnityEditor; +using UnityEngine.Events; +using System.Reflection; + +namespace UnityLibrary +{ + public class FindWhatButtonCallsMyMethod : EditorWindow + { + private string methodName = "MyMethodHere"; + + [MenuItem("Tools/Find Buttons with Method")] + public static void ShowWindow() + { + GetWindow("FindWhatButtonCallsMyMethod"); + } + + private void OnGUI() + { + GUILayout.Label("Find Buttons that call Method", EditorStyles.boldLabel); + methodName = EditorGUILayout.TextField("Method Name:", methodName); + + if (GUILayout.Button("Find Buttons")) + { + FindButtonsWithMethod(); + } + } + + private void FindButtonsWithMethod() + { + Button[] allButtons = FindObjectsOfType