少年修仙传客户端代码仓库
lcy
2024-12-16 a39c35fc6449430cd02bccb681c4a0a880e46cd9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
using UnityEngine;
using System.Collections.Generic;
 
public class CollisionUtility
{
 
    /// <summary>
    /// 扫描碰撞检测
    /// </summary>
    /// <param name="_start_pos">扫描的起点</param>
    /// <param name="_end_pos">扫描的终点</param>
    /// <param name="_sweep_radius">扫描的半径</param>
    /// <param name="_position">被扫描对象的坐标</param>
    /// <param name="_height">被扫描对象的高度,碰撞体的高度已经包括了半径</param>
    /// <param name="_radius">被扫描对象的半径</param>
    /// <returns>返回是否扫描到</returns>
    public static bool ScanCollide(Vector3 _start_pos, Vector3 _end_pos, float _sweep_radius,
                                    Vector3 _position, float _height, float _radius)
    {
        // 转为判断2个向量的距离判断
        // 因为要扫的对象都是不会左右旋转的,是一个直立的胶囊提对象,所以取得最高点和最低点
        // 与扫的起点和终点为2个向量
        float low_x_1 = 0, height_x_1 = 0, low_y_1 = 0, height_y_1 = 0, low_z_1 = 0, height_z_1 = 0;
        // 计算2个向量的高点和低点
        if (_start_pos.y > _end_pos.y)
        {
            low_y_1 = _end_pos.y;
            height_y_1 = _start_pos.y;
        }
        else
        {
            low_y_1 = _start_pos.y;
            height_y_1 = _end_pos.y;
        }
 
        if (_start_pos.x > _end_pos.x)
        {
            low_x_1 = _end_pos.x;
            height_x_1 = _start_pos.x;
        }
        else
        {
            low_x_1 = _start_pos.x;
            height_x_1 = _end_pos.x;
        }
 
        if (_start_pos.z > _end_pos.z)
        {
            low_z_1 = _end_pos.z;
            height_z_1 = _start_pos.z;
        }
        else
        {
            low_z_1 = _start_pos.z;
            height_z_1 = _end_pos.z;
        }
 
        float low_y_2 = _position.y;
        float height_y_2 = _position.y + _height;
 
        // 如果其中一个的高点比另一个的低点-半径还要低,或者低点比另一个的高点+半径还要高,则肯定不会碰撞
        if (low_y_1 - _sweep_radius > height_y_2 || height_y_1 + _sweep_radius < low_y_2 ||
            low_x_1 - _sweep_radius > _position.x + _radius || height_x_1 + _sweep_radius < _position.x - _radius ||
            low_z_1 - _sweep_radius > _position.z + _radius || height_z_1 + _sweep_radius < _position.z - _radius)
            return false;
 
        // 再来就是比较2个向量的距离,如果距离小于2个半径,则会碰撞
        Vector3 vec1 = _end_pos - _start_pos;
        Vector3 vec2 = new Vector3(0, _height, 0);
 
        float d = float.MaxValue;
 
        // 这里要判断是否平行的情况
        // 只需要判断vec1的x和z是否为0,为0则与要判断向量平行
        if (vec1.x == 0 && vec1.z == 0)
        {
            d = Mathf.Sqrt((_start_pos.x - _position.x) * (_start_pos.x - _position.x) + (_start_pos.z - _position.z) * (_start_pos.z - _position.z));
        }
        else
        {
            // 扫描向量上任取一点A,被扫对象向量上任选一点B组成新的向量AB,
            // 求出扫描向量和被扫向量的法向量N
            // 则这2个向量的距离为 d = AB * N / N的模
            Vector3 N = Vector3.Cross(vec1, vec2);
            Vector3 AB = _start_pos - _position;
 
            d = Mathf.Abs(N.x * AB.x + N.y * AB.y + N.z * AB.z) / Mathf.Sqrt(N.x * N.x + N.y * N.y + N.z * N.z);
        }
 
        // CatDebugger.Log("distance : " + d + " , range : " + (_sweep_radius + _radius));
 
        return d < _sweep_radius + _radius;
    }
 
 
    public static bool Sweep(List<Vector3> points,
                             float radius,
                             Vector3 targetPosition,
                             float targetRadius)
    {
 
        bool _result = false;
 
        if (points.Count == 1)
        {
            return Vector3.SqrMagnitude(targetPosition - points[0]) < Mathf.Pow(radius + targetRadius, 2);
        }
 
        Vector3 _from;
        Vector3 _to;
 
        for (int i = 0; i < points.Count - 1; ++i)
        {
            _from = points[i];
            _to = points[i + 1];
            if (CircleCollied(_from, _to, radius, targetPosition, targetRadius))
            {
                _result = true;
                break;
            }
        }
 
        return _result;
    }
 
    /// <summary>
    /// 一段距离的线段的平面圆扫描检测
    /// </summary>
    /// <param name="f">线段起点</param>
    /// <param name="t">线段终点</param>
    /// <param name="radius">圆的半径</param>
    /// <param name="p">检测点</param>
    /// <param name="targetRadius">检测半径</param>
    /// <returns>返回距离是否小于2个半径的长度</returns>
    public static bool CircleCollied(Vector3 f,
                                     Vector3 t,
                                     float radius,
                                     Vector3 p,
                                     float targetRadius)
    {
 
        // 对y进行归零
        f.y = 0;
        t.y = 0;
        p.y = 0;
 
        // 得到真实的距离差
        float _radiusSum = radius + targetRadius;
 
        // 如果传入的起点,终点相同, 则只计算2点之间的距离是否小于半径
        if (f == t)
        {
            return Vector3.SqrMagnitude(p - f) < _radiusSum * _radiusSum;
        }
 
        // 如果点在两端之外,则一定不会碰撞
        // 起点x更大
        if (f.x > t.x)
        {
            if (p.x > f.x)
            {
                return Vector3.SqrMagnitude(p - f) < _radiusSum * _radiusSum;
            }
        }
        else
        {// 终点更大
            if (p.x > t.x)
            {
                return Vector3.SqrMagnitude(p - t) < _radiusSum * _radiusSum;
            }
        }
 
        // 起点z更大
        if (f.z > t.z)
        {
            if (p.z > f.z)
            {
                return Vector3.SqrMagnitude(p - f) < _radiusSum * _radiusSum;
            }
        }
        else
        {
            if (p.z > t.z)
            {
                return Vector3.SqrMagnitude(p - t) < _radiusSum * _radiusSum;
            }
        }
 
        float _distance = 0;
 
        if (f.x == t.x)
        {
            Debug.LogFormat("_distance: {0}", Mathf.Abs(p.x - f.x));
            // 只要保证
        }
 
        float cross = (t.x - f.x) * (p.x - f.x) + (t.z - f.z) * (p.z - f.z);
        if (cross <= 0)
        {
            _distance = Mathf.Sqrt((p.x - f.x) * (p.x - f.x) + (p.z - f.z) * (p.z - f.z));
            return _distance < _radiusSum;
        }
 
        float d2 = (t.x - f.x) * (t.x - f.x) + (t.z - f.z) * (t.z - f.z);
        if (cross >= d2)
        {
            _distance = Mathf.Sqrt((p.x - t.x) * (p.x - t.x) + (p.z - t.z) * (p.z - t.z));
            return _distance < _radiusSum;
        }
 
        float r = cross / d2;
        float px = f.x + (t.x - f.x) * r;
        float py = f.z + (t.z - f.z) * r;
 
        _distance = Mathf.Sqrt((p.x - px) * (p.x - px) + (py - p.z) * (py - p.z));
        return _distance < _radiusSum;
    }
 
    /// <summary>
    /// 检测点是否在给定的矩形中
    /// </summary>
    /// <param name="position">矩形位置</param>
    /// <param name="direction">矩形的朝向</param>
    /// <param name="width">矩形的宽度</param>
    /// <param name="distance">矩形的距离</param>
    /// <param name="checkPoint">检测点的坐标</param>
    /// <returns>是否在检测范围内</returns>
    public static bool IsPointInRectangle(Vector3 position,
                                          Vector3 direction,
                                          float width,
                                          float distance,
                                          Vector3 checkPoint)
    {
        Vector3 p1 = position + Quaternion.Euler(0, -90, 0) * direction * width * .5f;
        Vector3 p2 = p1 + direction * distance;
        Vector3 p3 = p2 + Quaternion.Euler(0, 90, 0) * direction * width;
        Vector3 p4 = position + Quaternion.Euler(0, 90, 0) * direction * width * .5f;
 
        Line2D _line1 = new Line2D
        {
            start = new Vector2(p1.x, p1.z),
            end = new Vector2(p2.x, p2.z)
        };
 
        Line2D _line2 = new Line2D
        {
            start = new Vector2(p2.x, p2.z),
            end = new Vector2(p3.x, p3.z)
        };
 
        Line2D _line3 = new Line2D
        {
            start = new Vector2(p3.x, p3.z),
            end = new Vector2(p4.x, p4.z)
        };
 
        Line2D _line4 = new Line2D
        {
            start = new Vector2(p4.x, p4.z),
            end = new Vector2(p1.x, p1.z)
        };
 
        bool result = Line2D.PointAtLineLeft(new Vector2(checkPoint.x, checkPoint.z), _line1)
                   || Line2D.PointAtLineLeft(new Vector2(checkPoint.x, checkPoint.z), _line2)
                   || Line2D.PointAtLineLeft(new Vector2(checkPoint.x, checkPoint.z), _line3)
                   || Line2D.PointAtLineLeft(new Vector2(checkPoint.x, checkPoint.z), _line4);
 
        return !result;
    }
 
    /// <summary>
    /// 检测给定的点是否在给定的扇形区域中
    /// </summary>
    /// <param name="position">扇形的圆心点</param>
    /// <param name="direction">扇形的朝向</param>
    /// <param name="radius">扇形的半径</param>
    /// <param name="angle">扇形的张角</param>
    /// <param name="checkPoint">检测点坐标</param>
    /// <returns></returns>
    public static bool IsPointInSector(Vector3 position,
                                       Vector3 direction,
                                       float radius,
                                       float angle,
                                       Vector3 checkPoint)
    {
        // 半径检测
        if (!IsPointsInDistance(position, checkPoint, radius))
        {
            return false;
        }
 
        // 扇形范围检测
        Vector3 _chkToSelf = (checkPoint - position).normalized;
        float _chkAngle = Mathf.Acos(Vector3.Dot(direction, _chkToSelf)) * Mathf.Rad2Deg;
        return _chkAngle <= angle * .5f;
    }
 
    public static bool IsPointInSector2(Vector3 position,
                                       Vector3 direction,
                                       float radius,
                                       float angle,
                                       Vector3 checkPoint)
    {
        return IsPointInSector2Sqrt(position, direction, radius * radius, angle, checkPoint);
    }
 
    public static bool IsPointInSector2Sqrt(Vector3 position,
                                   Vector3 direction,
                                   float radiusSqrt,
                                   float angle,
                                   Vector3 checkPoint)
    {
        float _chkDistSqrt = MathUtility.DistanceSqrtXZ(position, checkPoint);
 
        // 半径检测
        if (_chkDistSqrt > radiusSqrt)
        {
            return false;
        }
 
        Vector3 _targetDir = (checkPoint - position).normalized;
        float _chkAngle = Vector3.Angle(_targetDir, direction);
        bool _result = _chkAngle <= angle * .5f;
        return _result;
    }
 
    /// <summary>
    /// 判断2个点的距离是否小于给定距离
    /// </summary>
    /// <param name="position">检测点</param>
    /// <param name="checkPosition">检测点</param>
    /// <param name="distance">距离</param>
    /// <returns></returns>
    public static bool IsPointsInDistance(Vector3 position, Vector3 checkPosition, float distance)
    {
        return Vector3.SqrMagnitude(checkPosition - position) <= distance * distance;
    }
 
 
    public static bool TryGetGroundHeight(Vector3 _position, out float _height)
    {
        RaycastHit hit;
        var ray = new Ray(_position.SetY(150f), Vector3.down);
 
        if (Physics.Raycast(ray, out hit, 200f, LayerUtility.WalkbleMask))
        {
            _height = hit.point.y;
            return true;
        }
        else
        {
            _height = 0f;
            return false;
        }
    }
 
    public static bool NM_RayCast(Vector3 sourcePosition, Vector3 targetPosition, ref Vector3 result)
    {
        sourcePosition.y = 0;
        targetPosition.y = 0;
 
        UnityEngine.AI.NavMeshHit _hit;
 
        if (UnityEngine.AI.NavMesh.Raycast(sourcePosition, targetPosition, out _hit, UnityEngine.AI.NavMesh.AllAreas))
        {
            result = _hit.position;
            return true;
        }
 
        return false;
    }
}