如何使用补间动画在 Phaser 3 中缩放线条?

问题描述

想象一个非常简单的场景:

  • 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'
        });
    }