知识点
射线检测是什么?
射线检测是非常重要的功能,常常用来判断各种情况。其本质是对一条射线和另一个形状进行 相交性判断,如下图所示。
射线检测怎么使用?
构造射线
首先 引入 geometry 模块,
import { geometry } from 'cc';
然后 设置起点和方向,常见方法
一、通过 起点 + 方向,ray 的构造函数或静态接口 create
import { geometry } from 'cc';
const { ray } = geometry;
// 构造一条从(0,-1,0)出发,指向 Y 轴的射线
// 前三个参数是起点,后三个参数是方向
const outRay = new ray(0, -1, 0, 0, 1, 0);
// 或者通过静态方法 create
const outRay2 = ray.create(0, -1, 0, 0, 1, 0);
二、通过 起点 + 射线上的另一点,ray 的静态接口 fromPoints:
import { geometry, Vec3 } from 'cc';
// 构造一条从原点出发,指向 Z 轴的射线
const outRay = new geometry.ray();
geometry.ray.fromPoints(outRay, Vec3.ZERO, Vec3.UNIT_Z);
三、用相机构造一条从相机原点到屏幕某点发射出的射线:
import { geometry, Camera } from 'cc';
const { ray } = geometry;
// 此处假设已经有 cameraCom 的引用了
const cameraCom: Camera;
// 获得一条途径屏幕坐标(0,0)发射出的一条射线
const outRay = new ray();
cameraCom.screenPointToRay(0, 0, outRay);
注意:
- 首先需要获取一个相机组件或者相机实例的引用。
- 相机组件和相机实例两者暴露的接口参数顺序不一样。
接口介绍
Cocos Creator 提供了一套基于物理引擎的射线检测功能。但需要注意的是,检测的对象是物理碰撞器,在场景面板上与之对应的是碰撞器组件,例如 BoxCollider。
目前接口由 PhysicsSystem 提供,有以下两类:
- raycast : 检测所有的碰撞体,返回布尔值, 表示是否检测成功。
- raycastClosest :检测所有的碰撞体,同样返回布尔值。
参数说明:
- worldRay:世界空间下的射线
- mask:用于过滤的掩码,可以传入需要检测的分组
- maxDistance:最大检测距离,目前请勿传入 Infinity 或 Number.MAX_VALUE
- queryTrigger:是否检测触发器
获取结果
获取以上接口的检测结果,需分别通过以下方式:
- 获取 raycastAll 的检测结果:PhysicsSystem.instance.raycastResults
- 获取 raycastClosest 的检测结果:PhysicsSystem.instance.raycastClosestResult
**注意:**返回对象是只读并且复用的,每次调用检测接口后会更新相应结果。
结果存储的信息
信息由 PhysicsRayResult 进行存储,主要有以下信息:
- collider:击中的碰撞器
- distance:击中点与射线起点的距离
- hitPoint:击中点(世界坐标系中)
- hitNormal:击中点所处面的法线(世界坐标系中)
以上摘抄于 Cocos Creator 3.x 官方文档。
正文
效果
Cocos Creator 3D 可以基于物理碰撞器,来判断3D点击事件。
首先肯定要给物体添加碰撞器。
检测代码
import { _decorator, Component, Node, PhysicsSystem, SystemEventType, systemEvent, geometry, Camera, Touch, EventTouch } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('Typescript')
export class he extends Component {
@property({ type: Camera, tooltip: '主相机' })
public mainCamera: Camera | null = null;
@property({ type: Node, tooltip: '待触摸物体' })
public node_touch_1: Node | null = null;
private _ray: geometry.Ray = new geometry.Ray();
start() {
systemEvent.on(SystemEventType.TOUCH_START, this.onTouchStart, this);
}
onTouchStart(touch: Touch, event: EventTouch) {
// 基于摄像机 画射线
this.mainCamera?.screenPointToRay(event.getLocation().x, event.getLocation().y, this._ray);
// 基于物理碰撞器的射线检测
// 当点击 node_touch_1 时,控制台打印 “node_touch_1”
if (PhysicsSystem.instance.raycast(this._ray)) {
const r = PhysicsSystem.instance.raycastResults;
for (let index = 0; index < r.length; index++) {
const element = r[index];
console.log('当前点击: ' + element.collider.node.uuid);
if (element.collider.node.uuid == this.node_touch_1?.uuid) {
console.log('node_touch_1');
}
}
}
}
}
最后愉快的拉控件吧!!!
正文代码,基于Cocos Creator 3.1版本,其他版本自行修改部分接口!!!