我们先来看一个例子:
我们创建了一个Layer,并且在这个Layer种添加了两个带有PhysicsBody的Sprite
这是一个很正常的例子,不过,现在我们要做一些改动:
我们让这个layer做一个旋转动作
你会发现,这两个物体的运动被layer的运动影响了。
实际上不仅仅是旋转,哪怕是对layer进行setPosition动作都会对它内部的物理节点造成影响。
这就引发了一些问题,比如,如果我的游戏中要采用物理引擎,同时需要做地图卷动,镜头旋转缩放等功能,那么你在卷动地图或旋转镜头时一定是不能影响物体本身的运动的,所以,我们必须想办法解决这个问题。
我们来看一下物理引擎的一个关键方法:PhysicsWorld::step
step调用了update,
我折叠了update方法中一些无关的部分,我们只看箭头所指的两部分,可以发现物理引擎是通过物理节点的变换(Transform)来维护位置旋转等信息的。因为我们设置Node(Layer就是它的一个子类)的位置,旋转,缩放参数时,都会影响它的Transform,所以容器做出这样的变换,就会影响到子类节点的物理模拟了。所以,如果不想让容器的Transform影响到它子节点的物理模拟,我们就不能设置容器的位置,旋转,缩放等参数。
但是绘制游戏界面也需要getNodeToParentTransform()得到变换信息,如果不能设置容器的变换,那么也就无法制作地图卷动和镜头旋转这样的效果了。
这时,我们需要观察getNodeToParentTransform()这个方法是如何计算变换的。
我折叠了getNodeToParentTransform方法中一些无关的部分。我们可以发现一个叫_addtionalTransform的字段,它在getNodeToParentTransform的方法最后和_transform相乘了,两个矩阵变换相乘意味着变换叠加了,所以这个_addtionalTransform可以起到一个"额外加上去的"变换的效果。
那么,结合我们之前发现的问题:
1.物理引擎使用getNodeToParentTransform()变换来设置物体的位置信息
2.渲染引擎使用getNodeToParentTransform()变换来绘制节点
3._addtionalTransform在getNodeToParentTransform()的最后被叠加到Node的_transform上
可以设想,如果我们用"干净"的Transform去进行物理模拟,而用"旋转过的,移动过的"Transform去绘制节点,就可以解决问题了,
而解决的关键就在_addtionalTransform上。
来看下面的代码:
在这里我们新建了一个layerHandler节点,我们把layer的尺寸和锚点信息都给它,并且设置它在屏幕中心。
然后注意,我们没有对layer进行旋转,而是对layerHandler进行了旋转。
然后我们来看Scene的update部分(它负责每帧的更新,你需要调用scheduleUpdate()方法来开启它):
每一帧在进行物理模拟之前,我们把layer的addtionalTransform设为一个新的矩阵,这样它在进行物理模拟的过程中就不会影响子节点。
物理模拟之后,我们把layerHandler通过getNodeToParentTransform计算出的变换作为layer的addtionalTransform,这就意味着,这个layer将会使用它自身的变换和layerHandler的变换作为自己的getNodeToParentTransform结果去参与绘制,结果就是这样:
看,这时物理引擎的模拟没有受旋转的影响,我们可以把layerHandler当作一个摄像头来使用了。
(PS:这是Lanza第一次发这种日志,如有写得不好的地方请大家多提意见~)
附上示例项目归档:
链接: https://pan.baidu.com/s/1jLDKzV3bAlp6PIQihxikyA 密码: mhmz
支持Lanza!!!!
@virmint:谢谢!!!