我是一个 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有关的射线,就最好了。