问题描述
想象一个非常简单的场景:
- 800x640 的画布
- 中间的红色圆圈
- 9:00 位置的两条蓝线
private create(): void {
const circ = this.add.circle(
400,320,200,0xff0000
);
const l1 = this.add.line(
0,400,100,0x0000ff
).setorigin(0);
const l2 = this.add.line(
0,0x0000ff
).setorigin(0);
}
到目前为止一切顺利。
现在我想缩放这个简单的图形,相同的配置是当前大小的 1.5 倍:
private create(): void {
const circ = this.add.circle(
400,0x0000ff
).setorigin(0);
this.tweens.add({
targets: [circ,l1,l2],scale: 1.5,yoyo: false,duration: 2000,ease: 'Sine.easeInOut'
});
}
预期行为:
- 圆从中心扩大
- 线条也会扩展,最好是在它们相遇的地方
实际行为:
就目前的情况而言,只有 #1 符合我的期望。然而,这些线条不仅仅是缩放。并且翻译似乎受到传递给 tweens.add 的 scale 参数的影响。是什么赋予了?我在这里错过了什么?
考虑到 Phaser 3 中“原点”wrt 线的各种配置,我所期望的最糟糕的情况是这些线的发出/生长方式与圆(从中心/原点发出)不同。但我绝对希望线条保持静止/保持它们的交点在圆的中心。
你能解释一下 Phaser 到底在做什么吗,我该怎么做才能达到我想要的效果?
解决方法
Phaser 3 中的 Line GameObject 可能有很多不直观的地方,所有这些都导致了这种行为。让我们分解它们。
线条和起源
首先,区分线作为几何实体和线作为Phaser 3 Game Object。它们是相关的,但混淆源于微妙之处。
对于 Phaser 3 line Game Object,您需要记住三个有序对 p (x,y):
- P (X,Y),线的起点,相对于游戏世界(我们将在一段时间内定义该术语);在游戏世界中,(0,0) 位于左上角。
- P1 (X1,Y1),定义一条直线的第一个点,相对于 P
- P2 (X2,Y2),定义一条直线的第二个点,相对于 P
另一个重要的事情是游戏世界基本上是一个围绕x轴翻转的笛卡尔坐标系。因此,负 x 值仍然向左移动,但负 y 值上升,正 y 值下降。
现在让我们定义原点,我将从 official docs 中转述:
对象的原点是 [0,1] 范围内的标准化值。
对于 x 轴,0 表示游戏对象的左侧,1 表示右侧。
对于 y 轴,0 表示游戏对象的顶部,1 表示底部。
默认情况下,原点设置为 0.5,即对象的中心。
解释示例和补间
让我们以示例中的水平线 l2
为例,看看它是如何绘制的。
const l2 = this.add.line(
0,400,320,200,0x0000ff
).setOrigin(0);
- 原点在游戏对象的左侧。
- 就游戏世界而言,此原点位于 0、0 或左上角。
- 该线由相对于原点的两个点 ((400,320) 和 (200,320) 定义。
这里的重要观察是原点完全在定义的几何线之外。实际上,在您的原点(位于 (0,0))、游戏对象左侧和最右下角(位于 (400,320))之间的矩形区域中有相当大的不可见空间。
现在,当补间被调用时,它实际上缩放了游戏对象而不仅仅是几何线。而且由于大部分游戏对象是“不可见的”(几何线是唯一可见的部分),效果就像几何线在平移!
解决方案
要获得所需的效果,请将游戏对象限制在几何线所占据的区域。这样做的一种方法是:
- 由于我们希望线条以与圆相同的方式“辐射”,因此将 P 设置为 (400,320),即圆的中心。另外,将P1设置为(0,0)---记住这是相对于P的,所以在游戏世界中,我们只是让P = P1。
- 让我们将线条的原点保留为 0,但现在我们必须将它们的 P2 值分别重新定义为 (0,-100) 和 (0,-200)。
综合起来,
private create(): void {
const circ = this.add.circle(
400,0xff0000
);
const l1 = this.add.line(
400,-100,0x0000ff
).setOrigin(0);
const l2 = this.add.line(
400,-200,0x0000ff
).setOrigin(0);
this.tweens.add({
targets: [circ,l1,l2],scale: 1.5,yoyo: false,duration: 2000,ease: 'Sine.easeInOut'
});
}