3D新手关于组件点击事件碰到的一些坑

我是一个 java 服务器,之前因为某些原因,也对前端有点兴趣,写过了段时间 cocos creator 2.x 。

前段时间,女儿的数学手工作业让做两个圆,分别标上1到9的数字,然后旋转之后,把箭头指向的两个数丙乘,由于工具有限,于是给她用cocos creator 3.x 实现了,昨天,她玩了黑白棋之后,说让我给她做个黑白棋,研究之后碰到如下坑:

3D

3D的问题主要是我没有3D思维,也不能算坑,只能算我碰到的问题和怎么解决,毕竟还有摄像机,光线,甚至更多3D相关的概念需要我去理解

搞3D,我还是按2D的思维来搞,一开始就踩到了坑,改变圆柱体颜色始终不会,一开始准备在属性选择器修改,发现颜色在material中,且是锁定的,于是想到应该是要修改material,但默认的material是共用的,肯定不行,于是找论坛的帖子,又要自己new material,但是还是不知道修改哪个属性,最后想到应该是自己搞个material,于是新建材质,问题解决

点击事件

解决了3D颜色问题,就做了一面黑,一面白的棋子,然后做了个翻转的动画,女儿很喜欢这个动画,一直让我放,每次都刷新播放很麻烦,就想说做个按钮,点击一下就播放一下,结果女儿说为什么不直接点击棋子播放动画了,于是踩到了最大的坑:3D组件的点击事件。

一开始我按2D的思维,直接代码撸到底:

this.node.on(cc.NodeEventType.TOUCH_END, this.onClick, this);

于是报了错,只能继续去论坛搜,然后知道要用射线来解决,找了几个例子,代码大概都是大概这样(下面是官方文档代码):

 onTouchStart(event: EventTouch) {
        const touch = event.touch!;
        this.cameraCom.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
        if (PhysicsSystem.instance.raycast(this._ray)) {
            const raycastResults = PhysicsSystem.instance.raycastResults;
            for (let i = 0; i < raycastResults.length; i++) {
                const item = raycastResults[i];
                if (item.collider.node == this.targetNode) {
                    console.log('找到了!');
                    break;
                }
            }
        } else {
            console.log('没找到!');
        }
    }

然后一直打印 没找到 ,然后翻官方文档,也是一样。发现用到了 PhysicsSystem 于是想应该是 PhysicsSystem没有启用,增加

PhysicsSystem.enabled = true;

然后检测不到,又看到一篇文章,说要设置 raycast 的检测距离,于是看该当签名第3个参数是距离,虽然签名明确说了不要传number.max_value,但我也不知道传多大,就传个最大数试试,于是理所当然的依然没有检测到。

又想既然是物理系统,是不是没有加 刚体Collider 啊,于是加 刚体,加 Collider ,还乱设置一堆layer,依然不行!

实在没办法了,跑B站去搜视频,原来要用 raycastClosest,执行,终于打印 打到了

一些想法

点击3D节点,应该是很常用的操作吧,感觉可以底层做一下封装,代码层面只用在节点上通过类似下面代码来注册就行了:

this.node.on(Input.EventType.EventName, this.onClick, this);

或者加个组件 XXX

这样不管 raycastClosestResult 返回的是什么节点,直接:

let com = result.getComponent(XXX);
if (com != null) {
    com.emitXXX();
}

只是一些粗鄙的想法(毕竟我主要是一名服务端程序员),如果有不同意见的,轻喷!

我是准备自己实现一下这个XXX组件了,毕竟要是每个组件都执行一下射线,也没必要,毕竟点击屏幕,射线扫到最近的肯定就一个组件了。

刚逛论坛,又发现一个问题,就是如果有空气墙,那返回的就是空气墙,所以如果能有与物理系统无关,只与XXX有关的射线,就最好了。

不行哦,举个栗子如果不用射线那么如果有多个摄像机看一个物体那么画面上就可能渲染多次同个物体,那这时候如果只是点击事件的话你怎么知道点了那个要反馈,所以与摄像机相关的射线检测是必要的

我说的是不用物理射线,不是不用射线,如果有XXX组件,那么这个射线只检测XXX,