com.wallstop-studios.unity-helpers 2.0.0-rc76.4 → 2.0.0-rc76.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Editor/CustomDrawers/WShowIfPropertyDrawer.cs +1 -0
- package/Editor/CustomEditors/PersistentDirectoryGUI.cs +4 -1
- package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs +40 -0
- package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs.meta +3 -0
- package/Editor/CustomEditors/SourceFolderEntryDrawer.cs +43 -31
- package/{Runtime/Core/Extension → Editor/Extensions}/SerializedPropertyExtensions.cs +1 -1
- package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs +9 -1
- package/Editor/Sprites/SpriteSheetAnimationCreator.cs +1218 -0
- package/Editor/Sprites/SpriteSheetAnimationCreator.cs.meta +3 -0
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +29 -19
- package/Runtime/Core/Extension/DictionaryExtensions.cs +30 -10
- package/Runtime/Core/Extension/IEnumerableExtensions.cs +12 -10
- package/Runtime/Core/Extension/IListExtensions.cs +6 -0
- package/Runtime/Core/Extension/UnityExtensions.cs +68 -0
- package/Runtime/Core/Helper/Helpers.cs +12 -0
- package/Runtime/Core/Helper/LineHelper.cs +194 -0
- package/Runtime/Core/Helper/LineHelper.cs.meta +3 -0
- package/Runtime/Tags/CollisionSenses.cs +91 -0
- package/Runtime/Tags/CollisionSenses.cs.meta +3 -0
- package/Runtime/Utils/ChildSpawner.cs +100 -0
- package/Runtime/Utils/ChildSpawner.cs.meta +3 -0
- package/Runtime/Utils/CollisionProxy.cs +48 -0
- package/Runtime/Utils/CollisionProxy.cs.meta +3 -0
- package/Runtime/Utils/PolygonCollider2DOptimizer.cs +83 -0
- package/Runtime/Utils/PolygonCollider2DOptimizer.cs.meta +3 -0
- package/Runtime/Utils/SerializedStringComparer.cs +107 -0
- package/Runtime/Utils/SerializedStringComparer.cs.meta +3 -0
- package/Runtime/Utils/UnityObjectNameComparer.cs +46 -1
- package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +2 -2
- package/package.json +3 -1
- /package/{Runtime/Core/Extension → Editor/Extensions}/SerializedPropertyExtensions.cs.meta +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
using System;
|
|
4
4
|
using System.Collections;
|
|
5
5
|
using System.Collections.Generic;
|
|
6
|
-
using System.Linq;
|
|
7
6
|
using Extension;
|
|
8
7
|
using Helper;
|
|
9
8
|
|
|
@@ -53,7 +52,6 @@
|
|
|
53
52
|
public int Count { get; private set; }
|
|
54
53
|
|
|
55
54
|
private readonly List<T> _buffer;
|
|
56
|
-
private readonly List<T> _cache;
|
|
57
55
|
private int _position;
|
|
58
56
|
|
|
59
57
|
public T this[int index]
|
|
@@ -81,7 +79,6 @@
|
|
|
81
79
|
_position = 0;
|
|
82
80
|
Count = 0;
|
|
83
81
|
_buffer = new List<T>();
|
|
84
|
-
_cache = new List<T>();
|
|
85
82
|
if (initialContents != null)
|
|
86
83
|
{
|
|
87
84
|
foreach (T item in initialContents)
|
|
@@ -131,17 +128,26 @@
|
|
|
131
128
|
|
|
132
129
|
public bool Remove(T element, IEqualityComparer<T> comparer = null)
|
|
133
130
|
{
|
|
131
|
+
if (Count == 0)
|
|
132
|
+
{
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
int write = 0;
|
|
134
137
|
bool removed = false;
|
|
135
|
-
_cache.Clear();
|
|
136
138
|
comparer ??= EqualityComparer<T>.Default;
|
|
137
|
-
|
|
139
|
+
for (int i = 0; i < Count; ++i)
|
|
138
140
|
{
|
|
141
|
+
int readIdx = AdjustedIndexFor(i);
|
|
142
|
+
T item = _buffer[readIdx];
|
|
143
|
+
|
|
139
144
|
if (!removed && comparer.Equals(item, element))
|
|
140
145
|
{
|
|
141
146
|
removed = true;
|
|
142
147
|
continue;
|
|
143
148
|
}
|
|
144
|
-
|
|
149
|
+
|
|
150
|
+
_buffer[write++] = item;
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
if (!removed)
|
|
@@ -149,27 +155,34 @@
|
|
|
149
155
|
return false;
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
|
|
153
|
-
foreach (T item in _cache)
|
|
154
|
-
{
|
|
155
|
-
Add(item);
|
|
156
|
-
}
|
|
158
|
+
_buffer.RemoveRange(write, _buffer.Count - write);
|
|
157
159
|
|
|
160
|
+
Count--;
|
|
161
|
+
_position = Count < Capacity ? Count : 0;
|
|
158
162
|
return true;
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
public int RemoveAll(Func<T, bool> predicate)
|
|
162
166
|
{
|
|
167
|
+
if (Count == 0)
|
|
168
|
+
{
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
int write = 0;
|
|
163
173
|
int removedCount = 0;
|
|
164
|
-
|
|
174
|
+
|
|
175
|
+
for (int i = 0; i < Count; ++i)
|
|
165
176
|
{
|
|
177
|
+
int readIdx = AdjustedIndexFor(i);
|
|
178
|
+
T item = _buffer[readIdx];
|
|
166
179
|
if (predicate(item))
|
|
167
180
|
{
|
|
168
181
|
removedCount++;
|
|
169
182
|
}
|
|
170
183
|
else
|
|
171
184
|
{
|
|
172
|
-
|
|
185
|
+
_buffer[write++] = item;
|
|
173
186
|
}
|
|
174
187
|
}
|
|
175
188
|
|
|
@@ -178,12 +191,9 @@
|
|
|
178
191
|
return 0;
|
|
179
192
|
}
|
|
180
193
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Add(item);
|
|
185
|
-
}
|
|
186
|
-
|
|
194
|
+
_buffer.RemoveRange(write, _buffer.Count - write);
|
|
195
|
+
Count -= removedCount;
|
|
196
|
+
_position = Count < Capacity ? Count : 0;
|
|
187
197
|
return removedCount;
|
|
188
198
|
}
|
|
189
199
|
|
|
@@ -144,10 +144,11 @@
|
|
|
144
144
|
|
|
145
145
|
public static Dictionary<K, V> Merge<K, V>(
|
|
146
146
|
this IReadOnlyDictionary<K, V> lhs,
|
|
147
|
-
IReadOnlyDictionary<K, V> rhs
|
|
147
|
+
IReadOnlyDictionary<K, V> rhs,
|
|
148
|
+
Func<Dictionary<K, V>> creator = null
|
|
148
149
|
)
|
|
149
150
|
{
|
|
150
|
-
Dictionary<K, V> result = new();
|
|
151
|
+
Dictionary<K, V> result = creator?.Invoke() ?? new Dictionary<K, V>();
|
|
151
152
|
if (0 < lhs.Count)
|
|
152
153
|
{
|
|
153
154
|
foreach (KeyValuePair<K, V> kvp in lhs)
|
|
@@ -176,10 +177,11 @@
|
|
|
176
177
|
/// <returns>All elements of rhs that either don't exist in or are different from lhs</returns>
|
|
177
178
|
public static Dictionary<K, V> Difference<K, V>(
|
|
178
179
|
this IReadOnlyDictionary<K, V> lhs,
|
|
179
|
-
IReadOnlyDictionary<K, V> rhs
|
|
180
|
+
IReadOnlyDictionary<K, V> rhs,
|
|
181
|
+
Func<Dictionary<K, V>> creator = null
|
|
180
182
|
)
|
|
181
183
|
{
|
|
182
|
-
Dictionary<K, V> result = new(rhs.Count);
|
|
184
|
+
Dictionary<K, V> result = creator?.Invoke() ?? new Dictionary<K, V>(rhs.Count);
|
|
183
185
|
foreach (KeyValuePair<K, V> kvp in rhs)
|
|
184
186
|
{
|
|
185
187
|
K key = kvp.Key;
|
|
@@ -194,9 +196,12 @@
|
|
|
194
196
|
return result;
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
public static Dictionary<V, K> Reverse<K, V>(
|
|
199
|
+
public static Dictionary<V, K> Reverse<K, V>(
|
|
200
|
+
this IReadOnlyDictionary<K, V> dictionary,
|
|
201
|
+
Func<Dictionary<V, K>> creator = null
|
|
202
|
+
)
|
|
198
203
|
{
|
|
199
|
-
Dictionary<V, K> output = new(dictionary.Count);
|
|
204
|
+
Dictionary<V, K> output = creator?.Invoke() ?? new Dictionary<V, K>(dictionary.Count);
|
|
200
205
|
foreach (KeyValuePair<K, V> entry in dictionary)
|
|
201
206
|
{
|
|
202
207
|
output[entry.Value] = entry.Key;
|
|
@@ -264,10 +269,25 @@
|
|
|
264
269
|
return false;
|
|
265
270
|
}
|
|
266
271
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
272
|
+
if (dictionary.Count != other.Count)
|
|
273
|
+
{
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (dictionary.Count == 0)
|
|
278
|
+
{
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
foreach (KeyValuePair<K, V> entry in dictionary)
|
|
283
|
+
{
|
|
284
|
+
if (!other.TryGetValue(entry.Key, out V value) || !entry.Value.Equals(value))
|
|
285
|
+
{
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return true;
|
|
271
291
|
}
|
|
272
292
|
|
|
273
293
|
public static void Deconstruct<K, V>(this KeyValuePair<K, V> kvp, out K key, out V value)
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
FuncBasedComparer<T> comparerObject =
|
|
34
34
|
(FuncBasedComparer<T>)
|
|
35
35
|
ComparerCache.GetOrAdd(comparer, () => new FuncBasedComparer<T>(comparer));
|
|
36
|
-
return enumeration.OrderBy(
|
|
36
|
+
return enumeration.OrderBy(x => x, comparerObject);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
public static IEnumerable<T> Ordered<T>(this IEnumerable<T> enumerable)
|
|
40
40
|
where T : IComparable
|
|
41
41
|
{
|
|
42
|
-
return enumerable.OrderBy(
|
|
42
|
+
return enumerable.OrderBy(x => x);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
public static IEnumerable<T> Shuffled<T>(
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
IRandom random = null
|
|
48
48
|
)
|
|
49
49
|
{
|
|
50
|
-
random
|
|
50
|
+
random ??= ThreadLocalRandom<PcgRandom>.Instance;
|
|
51
51
|
return enumerable.OrderBy(_ => random.Next());
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -81,6 +81,13 @@
|
|
|
81
81
|
using IEnumerator<T> enumerator = items.GetEnumerator();
|
|
82
82
|
bool hasNext = enumerator.MoveNext();
|
|
83
83
|
|
|
84
|
+
while (hasNext)
|
|
85
|
+
{
|
|
86
|
+
yield return NextPartitionOf().ToList();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
yield break;
|
|
90
|
+
|
|
84
91
|
IEnumerable<T> NextPartitionOf()
|
|
85
92
|
{
|
|
86
93
|
int remainingCountForPartition = size;
|
|
@@ -90,11 +97,6 @@
|
|
|
90
97
|
hasNext = enumerator.MoveNext();
|
|
91
98
|
}
|
|
92
99
|
}
|
|
93
|
-
|
|
94
|
-
while (hasNext)
|
|
95
|
-
{
|
|
96
|
-
yield return NextPartitionOf().ToList();
|
|
97
|
-
}
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
public static List<T> ToList<T>(this IEnumerable<T> enumerable, int count)
|
|
@@ -113,9 +115,9 @@
|
|
|
113
115
|
_comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
public int Compare(T
|
|
118
|
+
public int Compare(T x, T y)
|
|
117
119
|
{
|
|
118
|
-
return _comparer(
|
|
120
|
+
return _comparer(x, y);
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
}
|
|
@@ -110,14 +110,20 @@
|
|
|
110
110
|
switch (inputList)
|
|
111
111
|
{
|
|
112
112
|
case T[] array:
|
|
113
|
+
{
|
|
113
114
|
Array.Sort(array, UnityObjectNameComparer<T>.Instance);
|
|
114
115
|
return;
|
|
116
|
+
}
|
|
115
117
|
case List<T> list:
|
|
118
|
+
{
|
|
116
119
|
list.Sort(UnityObjectNameComparer<T>.Instance);
|
|
117
120
|
return;
|
|
121
|
+
}
|
|
118
122
|
default:
|
|
123
|
+
{
|
|
119
124
|
inputList.InsertionSort(UnityObjectNameComparer<T>.Instance);
|
|
120
125
|
break;
|
|
126
|
+
}
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
|
|
@@ -1603,5 +1603,73 @@
|
|
|
1603
1603
|
}
|
|
1604
1604
|
}
|
|
1605
1605
|
#endif
|
|
1606
|
+
|
|
1607
|
+
public static bool IsDontDestroyOnLoad(this GameObject gameObjectToCheck)
|
|
1608
|
+
{
|
|
1609
|
+
if (gameObjectToCheck == null)
|
|
1610
|
+
{
|
|
1611
|
+
return false;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
return string.Equals(
|
|
1615
|
+
gameObjectToCheck.scene.name,
|
|
1616
|
+
"DontDestroyOnLoad",
|
|
1617
|
+
StringComparison.Ordinal
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
public static bool IsCircleFullyContained(
|
|
1622
|
+
this Collider2D targetCollider,
|
|
1623
|
+
Vector2 center,
|
|
1624
|
+
float radius,
|
|
1625
|
+
int sampleCount = 16
|
|
1626
|
+
)
|
|
1627
|
+
{
|
|
1628
|
+
for (int i = 0; i < sampleCount; ++i)
|
|
1629
|
+
{
|
|
1630
|
+
float angle = 2 * Mathf.PI / sampleCount * i;
|
|
1631
|
+
Vector2 pointOnCircle =
|
|
1632
|
+
center + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
|
|
1633
|
+
|
|
1634
|
+
if (!targetCollider.OverlapPoint(pointOnCircle))
|
|
1635
|
+
{
|
|
1636
|
+
return false;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
return true;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
public static void Invert(this PolygonCollider2D col, Rect outerRect)
|
|
1643
|
+
{
|
|
1644
|
+
int originalCount = col.pathCount;
|
|
1645
|
+
if (originalCount == 0)
|
|
1646
|
+
{
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
Vector2[][] originals = new Vector2[originalCount][];
|
|
1651
|
+
for (int i = 0; i < originalCount; i++)
|
|
1652
|
+
{
|
|
1653
|
+
originals[i] = col.GetPath(i).ToArray();
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
Vector2[] outerPath =
|
|
1657
|
+
{
|
|
1658
|
+
new Vector2(outerRect.xMin, outerRect.yMin),
|
|
1659
|
+
new Vector2(outerRect.xMin, outerRect.yMax),
|
|
1660
|
+
new Vector2(outerRect.xMax, outerRect.yMax),
|
|
1661
|
+
new Vector2(outerRect.xMax, outerRect.yMin),
|
|
1662
|
+
};
|
|
1663
|
+
|
|
1664
|
+
col.pathCount = originalCount + 1;
|
|
1665
|
+
col.SetPath(0, outerPath);
|
|
1666
|
+
|
|
1667
|
+
for (int i = 0; i < originalCount; ++i)
|
|
1668
|
+
{
|
|
1669
|
+
Vector2[] hole = originals[i];
|
|
1670
|
+
Array.Reverse(hole);
|
|
1671
|
+
col.SetPath(i + 1, hole);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1606
1674
|
}
|
|
1607
1675
|
}
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
using Object = UnityEngine.Object;
|
|
14
14
|
#if UNITY_EDITOR
|
|
15
15
|
using UnityEditor;
|
|
16
|
+
using UnityEditorInternal;
|
|
17
|
+
#else
|
|
18
|
+
using System;
|
|
16
19
|
#endif
|
|
17
20
|
|
|
18
21
|
public static partial class Helpers
|
|
@@ -24,6 +27,15 @@
|
|
|
24
27
|
StringComparer.Ordinal
|
|
25
28
|
);
|
|
26
29
|
|
|
30
|
+
public static string[] GetAllLayerNames()
|
|
31
|
+
{
|
|
32
|
+
#if UNITY_EDITOR
|
|
33
|
+
return InternalEditorUtility.layers;
|
|
34
|
+
#else
|
|
35
|
+
return Array.Empty<string>();
|
|
36
|
+
#endif
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
// https://gamedevelopment.tutsplus.com/tutorials/unity-solution-for-hitting-moving-targets--cms-29633
|
|
28
40
|
public static Vector2 PredictCurrentTarget(
|
|
29
41
|
this GameObject currentTarget,
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Core.Helper
|
|
2
|
+
{
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
5
|
+
using UnityEngine;
|
|
6
|
+
|
|
7
|
+
public static class LineHelper
|
|
8
|
+
{
|
|
9
|
+
private static float PerpendicularDistance(
|
|
10
|
+
Vector2 point,
|
|
11
|
+
Vector2 lineStart,
|
|
12
|
+
Vector2 lineEnd
|
|
13
|
+
)
|
|
14
|
+
{
|
|
15
|
+
float xDistance = lineEnd.x - lineStart.x;
|
|
16
|
+
float yDistance = lineEnd.y - lineStart.y;
|
|
17
|
+
|
|
18
|
+
if (Mathf.Approximately(xDistance, 0) && Mathf.Approximately(yDistance, 0))
|
|
19
|
+
{
|
|
20
|
+
return Vector2.Distance(point, lineStart);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
float t =
|
|
24
|
+
((point.x - lineStart.x) * xDistance + (point.y - lineStart.y) * yDistance)
|
|
25
|
+
/ (xDistance * xDistance + yDistance * yDistance);
|
|
26
|
+
|
|
27
|
+
Vector2 closestPoint = t switch
|
|
28
|
+
{
|
|
29
|
+
< 0 => lineStart,
|
|
30
|
+
> 1 => lineEnd,
|
|
31
|
+
_ => new Vector2(lineStart.x + t * xDistance, lineStart.y + t * yDistance),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return Vector2.Distance(point, closestPoint);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// c# implementation of the Ramer-Douglas-Peucker-Algorithm by Craig Selbert slightly adapted for Unity Vector Types
|
|
38
|
+
//http://www.codeproject.com/Articles/18936/A-Csharp-Implementation-of-Douglas-Peucker-Line-Ap
|
|
39
|
+
public static List<Vector2> SimplifyPrecise(List<Vector2> points, double tolerance)
|
|
40
|
+
{
|
|
41
|
+
if (points == null || points.Count < 3)
|
|
42
|
+
{
|
|
43
|
+
return points;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
int firstPoint = 0;
|
|
47
|
+
int lastPoint = points.Count - 1;
|
|
48
|
+
|
|
49
|
+
//Add the first and last index to the keepers
|
|
50
|
+
List<int> pointIndexsToKeep = new() { firstPoint, lastPoint };
|
|
51
|
+
|
|
52
|
+
//The first and the last point cannot be the same
|
|
53
|
+
while (points[firstPoint] == points[lastPoint])
|
|
54
|
+
{
|
|
55
|
+
lastPoint--;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
DouglasPeuckerReductionRecursive(
|
|
59
|
+
points,
|
|
60
|
+
firstPoint,
|
|
61
|
+
lastPoint,
|
|
62
|
+
tolerance,
|
|
63
|
+
ref pointIndexsToKeep
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
List<Vector2> returnPoints = new();
|
|
67
|
+
pointIndexsToKeep.Sort();
|
|
68
|
+
foreach (int index in pointIndexsToKeep)
|
|
69
|
+
{
|
|
70
|
+
returnPoints.Add(points[index]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return returnPoints;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private static void DouglasPeuckerReductionRecursive(
|
|
77
|
+
List<Vector2> points,
|
|
78
|
+
int firstPoint,
|
|
79
|
+
int lastPoint,
|
|
80
|
+
double tolerance,
|
|
81
|
+
ref List<int> pointIndexesToKeep
|
|
82
|
+
)
|
|
83
|
+
{
|
|
84
|
+
while (true)
|
|
85
|
+
{
|
|
86
|
+
double maxDistance = 0;
|
|
87
|
+
int indexFarthest = 0;
|
|
88
|
+
|
|
89
|
+
for (int index = firstPoint; index < lastPoint; index++)
|
|
90
|
+
{
|
|
91
|
+
double distance = InternalPerpendicularDistance(
|
|
92
|
+
points[firstPoint],
|
|
93
|
+
points[lastPoint],
|
|
94
|
+
points[index]
|
|
95
|
+
);
|
|
96
|
+
if (distance > maxDistance)
|
|
97
|
+
{
|
|
98
|
+
maxDistance = distance;
|
|
99
|
+
indexFarthest = index;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (maxDistance > tolerance && indexFarthest != 0)
|
|
104
|
+
{
|
|
105
|
+
//Add the largest point that exceeds the tolerance
|
|
106
|
+
pointIndexesToKeep.Add(indexFarthest);
|
|
107
|
+
|
|
108
|
+
DouglasPeuckerReductionRecursive(
|
|
109
|
+
points,
|
|
110
|
+
firstPoint,
|
|
111
|
+
indexFarthest,
|
|
112
|
+
tolerance,
|
|
113
|
+
ref pointIndexesToKeep
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
firstPoint = indexFarthest;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return;
|
|
124
|
+
|
|
125
|
+
static double InternalPerpendicularDistance(
|
|
126
|
+
Vector2 point1,
|
|
127
|
+
Vector2 point2,
|
|
128
|
+
Vector2 point
|
|
129
|
+
)
|
|
130
|
+
{
|
|
131
|
+
double area = System.Math.Abs(
|
|
132
|
+
.5f
|
|
133
|
+
* (
|
|
134
|
+
point1.x * point2.y
|
|
135
|
+
+ point2.x * point.y
|
|
136
|
+
+ point.x * point1.y
|
|
137
|
+
- point2.x * point1.y
|
|
138
|
+
- point.x * point2.y
|
|
139
|
+
- point1.x * point.y
|
|
140
|
+
)
|
|
141
|
+
);
|
|
142
|
+
double bottom = System.Math.Sqrt(
|
|
143
|
+
System.Math.Pow(point1.x - point2.x, 2.0)
|
|
144
|
+
+ System.Math.Pow(point1.y - point2.y, 2.0)
|
|
145
|
+
);
|
|
146
|
+
double height = area / bottom * 2.0;
|
|
147
|
+
return height;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
public static List<Vector2> Simplify(List<Vector2> points, float epsilon)
|
|
152
|
+
{
|
|
153
|
+
if (points == null || points.Count < 3 || epsilon <= 0)
|
|
154
|
+
{
|
|
155
|
+
return new List<Vector2>(points ?? Enumerable.Empty<Vector2>());
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
float maxDistance = 0;
|
|
159
|
+
int index = 0;
|
|
160
|
+
int end = points.Count - 1;
|
|
161
|
+
|
|
162
|
+
for (int i = 1; i < end; ++i)
|
|
163
|
+
{
|
|
164
|
+
float distance = PerpendicularDistance(points[i], points[0], points[end]);
|
|
165
|
+
if (distance > maxDistance)
|
|
166
|
+
{
|
|
167
|
+
index = i;
|
|
168
|
+
maxDistance = distance;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
List<Vector2> result = new();
|
|
173
|
+
|
|
174
|
+
if (maxDistance > epsilon)
|
|
175
|
+
{
|
|
176
|
+
List<Vector2> recResults1 = Simplify(points.GetRange(0, index + 1), epsilon);
|
|
177
|
+
List<Vector2> recResults2 = Simplify(
|
|
178
|
+
points.GetRange(index, points.Count - index),
|
|
179
|
+
epsilon
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
result.AddRange(recResults1.Take(recResults1.Count - 1));
|
|
183
|
+
result.AddRange(recResults2);
|
|
184
|
+
}
|
|
185
|
+
else
|
|
186
|
+
{
|
|
187
|
+
result.Add(points[0]);
|
|
188
|
+
result.Add(points[end]);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tags
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using Core.Attributes;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
|
|
8
|
+
[DisallowMultipleComponent]
|
|
9
|
+
[RequireComponent(typeof(TagHandler))]
|
|
10
|
+
public sealed class CollisionSenses : MonoBehaviour
|
|
11
|
+
{
|
|
12
|
+
public const string CollisionDisabledTag = nameof(CollisionDisabledTag);
|
|
13
|
+
|
|
14
|
+
[SiblingComponent]
|
|
15
|
+
private TagHandler _tagHandler;
|
|
16
|
+
|
|
17
|
+
private readonly List<Collider2D> _managedColliders = new();
|
|
18
|
+
|
|
19
|
+
private void Awake()
|
|
20
|
+
{
|
|
21
|
+
this.AssignRelationalComponents();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private void OnEnable()
|
|
25
|
+
{
|
|
26
|
+
if (_tagHandler.HasTag(CollisionDisabledTag))
|
|
27
|
+
{
|
|
28
|
+
StartManagingColliders();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_tagHandler.OnTagAdded += CheckForTagAddition;
|
|
32
|
+
_tagHandler.OnTagRemoved += CheckForTagRemoval;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private void OnDisable()
|
|
36
|
+
{
|
|
37
|
+
_tagHandler.OnTagAdded -= CheckForTagAddition;
|
|
38
|
+
_tagHandler.OnTagRemoved -= CheckForTagRemoval;
|
|
39
|
+
StopManagingColliders();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private void CheckForTagAddition(string addedTag)
|
|
43
|
+
{
|
|
44
|
+
if (!isActiveAndEnabled)
|
|
45
|
+
{
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (string.Equals(addedTag, CollisionDisabledTag, StringComparison.Ordinal))
|
|
50
|
+
{
|
|
51
|
+
StartManagingColliders();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private void CheckForTagRemoval(string removedTag)
|
|
56
|
+
{
|
|
57
|
+
if (!isActiveAndEnabled)
|
|
58
|
+
{
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (string.Equals(removedTag, CollisionDisabledTag, StringComparison.Ordinal))
|
|
63
|
+
{
|
|
64
|
+
StopManagingColliders();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private void StopManagingColliders()
|
|
69
|
+
{
|
|
70
|
+
foreach (Collider2D managedCollider in _managedColliders)
|
|
71
|
+
{
|
|
72
|
+
if (managedCollider != null)
|
|
73
|
+
{
|
|
74
|
+
managedCollider.enabled = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_managedColliders.Clear();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private void StartManagingColliders()
|
|
82
|
+
{
|
|
83
|
+
GetComponentsInChildren(_managedColliders);
|
|
84
|
+
_managedColliders.RemoveAll(managed => !managed.enabled);
|
|
85
|
+
foreach (Collider2D managedCollider in _managedColliders)
|
|
86
|
+
{
|
|
87
|
+
managedCollider.enabled = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|