关于射线检测实现子弹射击效果
1. 什么是射线照相检测?
射线检测是指通过发射射线来检测射线所击中的碰撞物体。 当发生碰撞并且满足条件时,返回值为true。
这些包括:
1.Physics.Linecast线性投影:从起始位置到结束位置的射线投影
2.Physics.Raycast(比较常用):显示与碰撞体碰撞的射线。 射线的方向和长度可以设置。
3.Physics.RaycastAll:发射射线并返回所有碰撞。 返回的是 RaycastHit[] 结构。
4.Physics.OverlapSphere:球形射线检测,返回球形半径内所有collider[],可用于判断拾取物品、手榴弹爆炸等触发。
2、实现子弹射击效果 1、思路
子弹在 3D 游戏场景中发射。 为了避免子弹穿透的问题,可以考虑使用射线检测,从枪口发射射线,确定枪械射程内的碰撞。 碰撞证明物体被击中,并且在碰撞的位置产生射线。 弹孔效果。
2、具体实施
这里我以第一人称射击游戏(FPS)中实现的射击效果为例
代码如下(示例):
public class Player_OpenFire : MonoBehaviour
{
//屏幕中心点位置坐标
private Vector3 point;
//FPS人物相机
public Camera fpscam;
//枪的射程
private float GunRange = 20f;
void Start()
{
//第一人称相机在不停的转动,但是准星的位置始终是在屏幕的中心点,这里获取到屏幕的中心点位置坐标
point = new Vector3(Screen.width / 2, Screen.height / 2, 0);
}
void Update()
{
OpenFire();
}
void OpenFire()
{
RaycastHit hit;
//初始化一条从屏幕中心点发出的射线
Ray ray = fpscam.ScreenPointToRay(point);
//这里的5表示的是所在的层,因为我的项目中用了多个相机,所以需要分层处理。(读者可以根据自己的需要自行修改)
if (Physics.Raycast(ray, out hit, GunRange, 5))
{
//这里进行的判断是防止枪口朝向脚下时,射线碰撞到玩家,玩家身上产生弹孔,造成自己打自己的情况。
if (hit.collider.gameObject.tag=="Player")
{
return;
}
//这里我的弹孔特效是做成了预设体,放在Resources目录下进行动态加载,参数hit.point表示的是发生碰撞的坐标点是一个Vector3值
GameObject bullet = Instantiate(Resources.Load("Bullet/BulletMark1"), hit.point, Quaternion.identity);
//在Unity三维坐标中的一个点包括三个值(三角朝向、法线值、UV值),这里用到了碰撞点的法线值
bullet.transform.LookAt(hit.point - hit.normal);
//把子弹特效设为碰撞到的物体的子物体
bullet.transform.parent = hit.collider.transform;
//我的预设体方向做的时候有问题,所以这里加载后再次修改了方向(读者根据需要自行修改这行代码)
bullet.transform.Rotate(90, 0, 0);
//我们让子弹移动一点点位置,调整子弹的特效能够显示在碰撞的物体上,避免遮盖的现象
bullet.transform.Translate(Vector3.back * 0.01f);
//为了方便演示这里设置弹孔特效一秒后自动销毁(读者可以用子弹对象池进行修改)
Destroy(bullet, 1f);
}
}
3.扩展(FPS游戏进入游戏并开始游戏选择)(1)光线检测以及组件LineRenderer的使用
该脚本挂在枪的空物体上。 空对象必须包含LineRenderer和Outline组件Li,否则运行时会报错。
具体代码如下:
使用系统;
使用系统集合;
使用 System.Collections.Generic;
使用Unity引擎;
使用 UnityEngine.EventSystems;
使用UnityEngine.UI;
公共类 StartGame :MonoBehaviour
//获取LineRenderer组件
私有 LineRenderer 线;
//获取开始游戏按钮组件
公共按钮开始游戏;
//获取初始射线的终点坐标
Vector3端点;
// Start 在第一帧更新之前调用
无效开始()
行= this.GetComponent();
终点 = line.GetPosition(1);
//为按钮添加点击事件
startGame.onClick.AddListener(委托()
GameObject.Find("StartGame").SetActive(false);
});
无效更新()
//初始化一条射线unity 2d射线碰撞检测,从枪口位置向前方发射
Ray ray = new Ray(this.transform.position, this.transform.forward);
RaycastHit 命中;
//设置射线的碰撞距离为50米
if (Physics.Raycast(射线, out hit, 50))
//判断开始游戏按钮是否被触摸
if (hit.collider.tag == "StartGame")
//当触摸开始游戏按钮时,使按钮出现亮边框
startGame.GetComponent().enabled = true;
//绘制射线并将颜色设置为红色
Debug.DrawLine(transform.position, hit.point, Color.red);
//将世界坐标转换为本地坐标
line.SetPosition(1, line.transform.InverseTransformPoint(hit.point));
//点击鼠标左键会执行回调函数
if (Input.GetMouseButtonDown(0))
/*
* 这里我们用伪代码来简单描述一下具体可以实现的功能
* 1.可以实现上述的弹孔特效
* 2.可以跳转到游戏界面
* 3.也可以进入加载界面,通过异步加载的方式加载游戏(建议使用这种方式直接设计加载,如果游戏场景太大3D素材,会造成卡顿3D道具,而异步加载可以给用户带来一定的延迟)更好的游戏体验)
*/
ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
别的
//按钮在没有遇到碰撞体的情况下不能有亮边框
startGame.GetComponent().enabled = false;
//同时恢复射线原来的样子
line.SetPosition(1, 终点);
LineRenderer组件使用介绍:
LineRenderer组件可以显示光线
我这里没有使用世界空间坐标,是为了防止光线偏差造成的不切实际的效果。
LineRenderer中的坐标点可以编辑和添加,必须选择Loop才能使光线连续性更加真实。
射线线的宽度可以通过修改Width的值来实现。 默认值是1。我这里用0.01来达到线条而不是条的效果。
线条的颜色是可以改变的,但是要注意的是必须有材质才可以改变颜色,否则改变颜色是不行的。 多种材料中只有一种有效。
概述组件的使用
这里使用时默认不勾选,只有检测到射线时才会显示亮边框。
EffectColer根据场景色调和视觉效果来设置颜色并进行适当的匹配。
EffectDistance 设置宽度和高度。 不同的值显示不同的边框粗细。 值越大,厚度越大。
使用Graphic Alpha:使用Alpha值的图像具有更好的视觉效果unity 2d射线碰撞检测,并且占用更多的字节空间。
(2)优化策略
上面代码中之所以设置endPoint来存储初始光线位置,是为了节省光线,避免穿透。
line.SetPosition(1, line.transform.InverseTransformPoint(hit.point));
这段代码将射线的终点设置为碰撞点,这样射线在碰撞点之后就不会再出现,并且在离开碰撞对象后,射线可以通过endPoint点恢复到原来的形状,而不会造成碰撞固定长度。
这里提到的一些问题是出现的情况,读者可以自行尝试。
总结
这里特别说明一下:通过3D角色场景触发Canvas上的Button按钮,是光线检测与2D相结合。 这里的处理方法是给按钮添加一个BoxCollider碰撞体,实现碰撞和光线检测。
文章来源:https://blog.csdn.net/qq_37160769/article/details/109341055