分享一个技围检测脚本,用来判定范围内是否有目标,或者是线性范围内是否可见目标。

简洁范围检测

测试代码

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckSkillRange : MonoBehaviour
{
public Vector3 offset = Vector3.one;
public float fieldOfViewAngle = 20;
public float viewDistance = 4;
public bool usePhysics2D = false;

public LayerMask ObjLayer = LayerMask.GetMask("Default");
public LayerMask IgnoreLayer = 1;


private void Update()
{
if (Input.GetMouseButtonUp(1))
{
var o = MovementUtility.WithinSight(transform, offset, fieldOfViewAngle, viewDistance, ObjLayer, Vector3.zero, IgnoreLayer);
if (o)
{
Debug.Log(string.Format("Attack obj {0}", o.name));
}
}

}


// Draw the line of sight representation within the scene window
public void OnDrawGizmos()
{
DrawLineOfSight(this.transform, offset, fieldOfViewAngle, viewDistance, usePhysics2D);
}
public static void DrawLineOfSight(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, bool usePhysics2D)
{
#if UNITY_EDITOR
var oldColor = UnityEditor.Handles.color;
var color = Color.yellow;
color.a = 0.1f;
UnityEditor.Handles.color = color;

var halfFOV = fieldOfViewAngle * 0.5f;
var beginDirection = Quaternion.AngleAxis(-halfFOV, (usePhysics2D ? Vector3.forward : Vector3.up)) * (usePhysics2D ? transform.up : transform.forward);
UnityEditor.Handles.DrawSolidArc(transform.TransformPoint(positionOffset), (usePhysics2D ? transform.forward : transform.up), beginDirection, fieldOfViewAngle, viewDistance);

UnityEditor.Handles.color = oldColor;
#endif
}
}

核心类,使用物理检测距离目标等,核心还是使用了碰撞检测

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
public class MovementUtility
{
//
// Static Fields
//
private static Dictionary<GameObject, AudioSource[]> transformAudioSourceMap;

//
// Static Methods
//
public static void DrawLineOfSight(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float angleOffset, float viewDistance, bool usePhysics2D)
{
}

private static AudioSource[] GetAudioSources(GameObject target)
{
bool flag = MovementUtility.transformAudioSourceMap == null;
if (flag)
{
MovementUtility.transformAudioSourceMap = new Dictionary<GameObject, AudioSource[]>();
}
AudioSource[] componentsInChildren;
bool flag2 = MovementUtility.transformAudioSourceMap.TryGetValue(target, out componentsInChildren);
AudioSource[] result;
if (flag2)
{
result = componentsInChildren;
}
else
{
componentsInChildren = target.GetComponentsInChildren<AudioSource>();
MovementUtility.transformAudioSourceMap.Add(target, componentsInChildren);
result = componentsInChildren;
}
return result;
}

public static GameObject LineOfSight(Transform transform, Vector3 positionOffset, GameObject targetObject, Vector3 targetOffset, bool usePhysics2D, int ignoreLayerMask)
{
GameObject result;
if (usePhysics2D)
{
RaycastHit2D raycastHit2D;
bool flag = raycastHit2D = Physics2D.Linecast(transform.TransformPoint(positionOffset), targetObject.transform.TransformPoint(targetOffset), ~ignoreLayerMask);
if (flag)
{
bool flag2 = raycastHit2D.transform.IsChildOf(targetObject.transform) || targetObject.transform.IsChildOf(raycastHit2D.transform);
if (flag2)
{
result = targetObject;
return result;
}
}
}
else
{
RaycastHit raycastHit;

bool flag3 = Physics.Linecast(transform.TransformPoint(positionOffset), targetObject.transform.TransformPoint(targetOffset), out raycastHit, ~ignoreLayerMask);
if (flag3)
{
bool flag4 = raycastHit.transform.IsChildOf(targetObject.transform) || targetObject.transform.IsChildOf(raycastHit.transform);
if (flag4)
{
result = targetObject;
return result;
}
}
}
result = null;
return result;
}


public static GameObject WithinHearingRange2D(Transform transform, Vector3 positionOffset, float audibilityThreshold, float hearingRadius, LayerMask objectLayerMask)
{
GameObject result = null;
Collider2D[] array = Physics2D.OverlapCircleAll(transform.TransformPoint(positionOffset), hearingRadius, objectLayerMask);
bool flag = array != null;
if (flag)
{
float num = 0f;
for (int i = 0; i < array.Length; i++)
{
float num2 = 0f;
GameObject gameObject;
bool flag2 = (gameObject = MovementUtility.WithinHearingRange(transform, positionOffset, audibilityThreshold, array[i].gameObject, ref num2)) != null;
if (flag2)
{
bool flag3 = num2 > num;
if (flag3)
{
num = num2;
result = gameObject;
}
}
}
}
return result;
}

public static GameObject WithinSight(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, LayerMask objectLayerMask, Vector3 targetOffset, LayerMask ignoreLayerMask)
{
GameObject result = null;
Collider[] array = Physics.OverlapSphere(transform.position, viewDistance, objectLayerMask);
bool flag = array != null;
if (flag)
{
float num = float.PositiveInfinity;
for (int i = 0; i < array.Length; i++)
{
float num2;
GameObject gameObject;
bool flag2 = (gameObject = MovementUtility.WithinSight(transform, positionOffset, fieldOfViewAngle, viewDistance, array[i].gameObject, targetOffset, false, 0f, out num2, ignoreLayerMask)) != null;
if (flag2)
{
bool flag3 = num2 < num;
if (flag3)
{
num = num2;
result = gameObject;
}
}
}
}
return result;
}

public static GameObject WithinSight(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, GameObject targetObject, Vector3 targetOffset, LayerMask ignoreLayerMask)
{
float num;
return MovementUtility.WithinSight(transform, positionOffset, fieldOfViewAngle, viewDistance, targetObject, targetOffset, false, 0f, out num, ignoreLayerMask);
}

private static GameObject WithinSight(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, GameObject targetObject, Vector3 targetOffset, bool usePhysics2D, float angleOffset2D, out float angle, int ignoreLayerMask)
{
Vector3 vector = targetObject.transform.position - transform.TransformPoint(positionOffset);
if (usePhysics2D)
{
angle = Vector3.Angle(vector, transform.up) + angleOffset2D;
vector.z = 0f;
}
else
{
angle = Vector3.Angle(vector, transform.forward);
vector.y = 0f;
}
bool flag = vector.magnitude < viewDistance && angle < fieldOfViewAngle * 0.5f;
GameObject result;
if (flag)
{
bool flag2 = MovementUtility.LineOfSight(transform, positionOffset, targetObject, targetOffset, usePhysics2D, ignoreLayerMask) != null;
if (flag2)
{
result = targetObject;
return result;
}
bool flag3 = targetObject.GetComponent<Collider>() == null && targetObject.GetComponent<Collider2D>() == null;
if (flag3)
{
bool activeSelf = targetObject.gameObject.activeSelf;
if (activeSelf)
{
result = targetObject;
return result;
}
}
}
result = null;
return result;
}

public static GameObject WithinSight2D(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, LayerMask objectLayerMask, Vector3 targetOffset, float angleOffset2D, LayerMask ignoreLayerMask)
{
GameObject result = null;
Collider2D[] array = Physics2D.OverlapCircleAll(transform.position, viewDistance, objectLayerMask);
bool flag = array != null;
if (flag)
{
float num = float.PositiveInfinity;
for (int i = 0; i < array.Length; i++)
{
float num2;
GameObject gameObject;
bool flag2 = (gameObject = MovementUtility.WithinSight(transform, positionOffset, fieldOfViewAngle, viewDistance, array[i].gameObject, targetOffset, true, angleOffset2D, out num2, ignoreLayerMask)) != null;
if (flag2)
{
bool flag3 = num2 < num;
if (flag3)
{
num = num2;
result = gameObject;
}
}
}
}
return result;
}

public static GameObject WithinSight2D(Transform transform, Vector3 positionOffset, float fieldOfViewAngle, float viewDistance, GameObject targetObject, Vector3 targetOffset, float angleOffset2D, LayerMask ignoreLayerMask)
{
float num;
return MovementUtility.WithinSight(transform, positionOffset, fieldOfViewAngle, viewDistance, targetObject, targetOffset, true, angleOffset2D, out num, ignoreLayerMask);
}
}