一:圆形区域检测

Unity中实现攻击区域检测_方向向量

需要判断:
——发起检测的物体位置与目标位置的距离是否小于圆形半径

using UnityEngine;

public class Player : MonoBehaviour
{
public Transform targetTrans;//目标位置(敌人位置)

public float attackDist;//攻击距离

private void Awake()
{
DrawAttackArea(transform, attackDist);
}

void Update()
{
//移动
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
transform.Translate(new Vector3(h, 0, v) * Time.deltaTime * 30);
if (Input.GetKey(KeyCode.O))
{
transform.Rotate(Vector3.up * Time.deltaTime * -300);
}
if (Input.GetKey(KeyCode.P))
{
transform.Rotate(Vector3.up * Time.deltaTime * 300);
}

//判断
float dist = Vector3.Distance(transform.position, targetTrans.position);
if (dist <= attackDist)
{
Debug.Log("进入攻击区域");
}
else
{
Debug.Log("离开攻击区域");
}
}

/// <summary>
/// 绘制攻击区域
/// </summary>
public void DrawAttackArea(Transform t, float radius)
{
int segments = 100;
float deltaAngle = 360f / segments;
Vector3 forward = t.forward;

Vector3[] vertices = new Vector3[segments];
for (int i = 0; i < vertices.Length; i++)
{
Vector3 pos = Quaternion.Euler(0f, deltaAngle * i, 0f) * forward * radius + t.position;
vertices[i] = pos;
}
int trianglesAmount = segments - 2;
int[] triangles = new int[trianglesAmount * 3];
for (int i = 0; i < trianglesAmount; i++)
{
triangles[3 * i] = 0;
triangles[3 * i + 1] = i + 1;
triangles[3 * i + 2] = i + 2;
}
GameObject go = new GameObject("AttackArea");
go.transform.position = new Vector3(0, 0.1f, 0);
go.transform.SetParent(transform);
MeshFilter mf = go.AddComponent<MeshFilter>();
MeshRenderer mr = go.AddComponent<MeshRenderer>();
Mesh mesh = new Mesh();
mr.material.shader = Shader.Find("Unlit/Color");
mr.material.color = Color.red;
mesh.vertices = vertices;
mesh.triangles = triangles;
mf.mesh = mesh;
}
}

二:扇形区域检测

Unity中实现攻击区域检测_方向向量_02

需要判断:
——发起检测的物体位置与目标位置的距离是否小于扇形半径
——发起检测的物体与目标的夹角是否小于扇形角度的二分之一

using UnityEngine;

public class Player : MonoBehaviour
{
public Transform targetTrans;//目标位置(敌人位置)

public float attackDist;//攻击距离
public float attackAngle;//攻击角度

private void Awake()
{
DrawAttackArea(transform, attackAngle, attackDist);
}

void Update()
{
//移动
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
transform.Translate(new Vector3(h, 0, v) * Time.deltaTime * 30);
if (Input.GetKey(KeyCode.O))
{
transform.Rotate(Vector3.up * Time.deltaTime * -300);
}
if (Input.GetKey(KeyCode.P))
{
transform.Rotate(Vector3.up * Time.deltaTime * 300);
}

//判断
float dist = Vector3.Distance(transform.position, targetTrans.position);
float angle = Vector3.Angle(transform.forward, targetTrans.position - transform.position);
if (dist <= attackDist
&& angle <= attackAngle / 2)
{
Debug.Log("进入攻击区域");
}
else
{
Debug.Log("离开攻击区域");
}
}

/// <summary>
/// 绘制攻击区域
/// </summary>
public void DrawAttackArea(Transform t, float angle, float radius)
{
int segments = 100;
float deltaAngle = angle / segments;
Vector3 forward = t.forward;

Vector3[] vertices = new Vector3[segments + 2];
vertices[0] = t.position;
for (int i = 1; i < vertices.Length; i++)
{
Vector3 pos = Quaternion.Euler(0f, -angle / 2 + deltaAngle * (i - 1), 0f) * forward * radius + t.position;
vertices[i] = pos;
}
int trianglesAmount = segments;
int[] triangles = new int[segments * 3];
for (int i = 0; i < trianglesAmount; i++)
{
triangles[3 * i] = 0;
triangles[3 * i + 1] = i + 1;
triangles[3 * i + 2] = i + 2;
}

GameObject go = new GameObject("AttackArea");
go.transform.position = new Vector3(0, 0.1f, 0);
go.transform.SetParent(transform);
MeshFilter mf = go.AddComponent<MeshFilter>();
MeshRenderer mr = go.AddComponent<MeshRenderer>();
Mesh mesh = new Mesh();
mr.material.shader = Shader.Find("Unlit/Color");
mr.material.color = Color.red;
mesh.vertices = vertices;
mesh.triangles = triangles;
mf.mesh = mesh;
}
}


得到两个向量的夹角可以用另一种方法:

float _angle = Mathf.Acos(Vector3.Dot(transform.forward.normalized, (targetTrans.position - transform.position).normalized)) * Mathf.Rad2Deg;


三:矩形区域检测

Unity中实现攻击区域检测_方向向量_03

需要判断:
——发起检测的物体与目标是否小于等于90度
——发起检测的物体位置到目标位置的向量在发起检测物体前方向向量上的投影是否小于矩形的长度
——发起检测的物体位置到目标位置的向量在发起检测物体右方向向量上的投影是否小于矩形的一半宽度

using UnityEngine;

public class Test : MonoBehaviour
{
public Transform targetTrans;//目标位置(敌人位置)

public float attackDist;//攻击距离
public float attackWidth;//攻击宽度

private void Awake()
{
DrawAttackArea(transform, attackWidth, attackDist);
}

void Update()
{
//移动
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
transform.Translate(new Vector3(h, 0, v) * Time.deltaTime * 30);
if (Input.GetKey(KeyCode.O))
{
transform.Rotate(Vector3.up * Time.deltaTime * -300);
}
if (Input.GetKey(KeyCode.P))
{
transform.Rotate(Vector3.up * Time.deltaTime * 300);
}

//判断
float dot = Vector3.Dot(targetTrans.position - transform.position, transform.forward);
float projectionDist_forward = Vector3.Project(targetTrans.position - transform.position, transform.forward).magnitude;
float projectionDist_right = Vector3.Project(targetTrans.position - transform.position, transform.right).magnitude;
if (dot >= 0
&& projectionDist_forward <= attackDist
&& (projectionDist_right <= attackWidth / 2))
{
Debug.Log("进入攻击区域");
}
else
{
Debug.Log("离开攻击区域");
}
}

/// <summary>
/// 绘制攻击区域
/// </summary>
public void DrawAttackArea(Transform t, float width, float length)
{
Vector3[] vertices = new Vector3[4];
vertices[0] = t.position + t.right * width / 2;
vertices[1] = t.position + t.right * width / 2 + t.forward * length;
vertices[2] = t.position - t.right * width / 2 + t.forward * length;
vertices[3] = t.position - t.right * width / 2;
int trianglesAmount = 2;
int[] triangles = new int[trianglesAmount * 3];
for (int i = 0; i < trianglesAmount; i++)
{
triangles[3 * i] = 0;
triangles[3 * i + 1] = i + 2;
triangles[3 * i + 2] = i + 1;
}

GameObject go = new GameObject("AttackArea");
go.transform.position = new Vector3(0, 0.1f, 0);
go.transform.SetParent(transform);
MeshFilter mf = go.AddComponent<MeshFilter>();
MeshRenderer mr = go.AddComponent<MeshRenderer>();
Mesh mesh = new Mesh();
mr.material.shader = Shader.Find("Unlit/Color");
mr.material.color = Color.red;
mesh.vertices = vertices;
mesh.triangles = triangles;
mf.mesh = mesh;
}
}