在射击游戏中,如何判定子弹是否击中敌人?

最简单的想法就是在枪口处实例化一个子弹并给它向前的速度,检测它与目标的碰撞。这个方法很容易实现,但是有一些问题。子弹的速度是很快的(假设要实现的是那种拟真的射击),那么在实践中,有可能出现子弹的速度过快造成碰撞检测的不准确,甚至有可能子弹穿过了目标而没有触发击中。

一种更好的方法是利用 Physics.Raycast 来进行检测。

在下面的演示中,我使用了

1
public static bool Raycast(Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance)
参数 含义
origin The starting point of the ray in world coordinates. 起始点的坐标
direction The direction of the ray. 射线方向
hitInfo If true is returned, hitInfo will contain more information about where the closest collider was hit. (See Also: RaycastHit). 被击中目标的信息
maxDistance The max distance the ray should check for collisions. 检测的最远距离

简而言之,这一函数会在起始点的位置向给定的方向发射一条射线,如果这条射线碰撞到了物体,那么它会返回 ture,否则返回 false。同时,被射线碰撞到的物体的一些信息会被记录在 RaycastHit 中,包括碰撞位置以及该物体的 Transform 等等。

在下面这个场景中,我创建了一个 Cube 和四个 Cylinder 分别来表示枪和目标。

接着将测试的脚本挂载在枪上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ShootTest : MonoBehaviour
{
void FixedUpdate()
{
RaycastHit hit;

if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity))
{
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.black);
Debug.Log("Did Hit " + hit.transform.gameObject.name);
}
else
{
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * 1000, Color.white);
Debug.Log("Did not Hit");
}
}
}
//该脚本来源于官方文档

值得注意的是,关于物理的代码应该要放置在 FixedUpdate 中而非 Update。

效果如下。