iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 6
0
Modern Web

再談 PixiJS,那些先前不一定有提到的部分與地雷系列 第 6

[Re:PixiJS - Day06] 顯示物件的奇妙行為與 Clone() 方法

接續昨天的討論,先討論幾個可視物件的行為:


繼承自 Container 的行為

Graphics 類別 繼承自 Container,因此可以使用 addChild (...children) 方法將 DisplayObject 放入其本身

Q. Graphics 類別畫在自己身上的東西,是否也會是 child?
情境:新建一個 graphic,畫了一個三角形並放入三個方塊,
那這個 graphic 的 children 陣列裡有幾個 child?

選項1:1
選項2:3
選項3:4

答案: 3
雖然看起來很像有 4 個可視物件,
可是 children 陣列裡的 child 數量是指使用 addChild(...children) 方法加進這個容器裡的 DisplayObject 數量
Graphics 類別裡的繪圖行為 不算在容器數量裡

[ Demo ]

const box1 = createBox(0xff0000, 100, 100, 'box1');
const box2 = createBox(0xff9900, 100, 100, 'box2');
const box3 = createBox(0xff0000, 100, 100, 'box3');

const boxGraphic = new PIXI.Graphics();
boxGraphic.beginFill(0xffffff);
boxGraphic.moveTo(0, 0);
boxGraphic.lineTo(300, 0);
boxGraphic.lineTo(150, 220);
boxGraphic.lineTo(0, 0);
boxGraphic.endFill();

boxGraphic.addChild(box1);
boxGraphic.addChild(box2);
boxGraphic.addChild(box3);

app.stage.addChild(boxGraphic);

console.log("boxGraphic.children.length: ", boxGraphic.children.length);

執行專案時,即使 Graphics 類別、Sprite 類別等都可當作容器,再放入可視物件
但我還是習慣使用 Container 類別放入各種可視物件,避免混亂


補充:Graphics 類別的 clone() 方法

Graphics#clone(),就結論來說與繼承較無直接關係
不是所有可視物件都有實作這個方法,
寫在這篇是因為跟這篇的範例比較接近

問題:Graphics 類別實作了 clone() 方法,
那剛剛一個三角形與三個方塊的 graphic,clone() 後會是?


右方 graphic 為左方 graphic 的 clone(),children 陣列裡的內容沒有拷貝
[ Demo]

const boxGraphicClone = boxGraphic.clone();
boxGraphicClone.name = "boxGraphicClone";
app.stage.addChild(boxGraphicClone);
boxGraphicClone.x = 450;
boxGraphicClone.y = 50;

想想這結果也挺合理的,如果 children 陣列裡的內容也會一起拷貝的話
clone() 方法就會由 Container 類別實作了


容易混淆的 pivot / anchor

anchor 與 pivot 作用類似,都是定義中心點
容易混淆的原因:官方範例裡兩種方法都有使用

[Demo] Sprite > Basic

Demo 裡使用 anchor 定義兔子的中心點

const bunny = PIXI.Sprite.from('examples/assets/bunny.png');
bunny.anchor.set(0.5);

[Demo] DEMOS-BASIC > Container


Demo 裡使用 anchor 定義兔子的中心點,使用 pivot 定義容器的中心點

for (let i = 0; i < 25; i++) {
    const bunny = new PIXI.Sprite(texture);
    bunny.anchor.set(0.5);
    bunny.x = (i % 5) * 40;
    bunny.y = Math.floor(i / 5) * 40;
    container.addChild(bunny);
}

container.pivot.x = container.width / 2;
container.pivot.y = container.height / 2;

可視物件的繼承關係裡,
所有可視物件與子類別都有 pivot (由 DisplayObject#pivot 實作)
但有 anchor 的類別與子類別並不多 ( 如 Sprite#anchor 與子類別等 )

Container 類別的實體有 pivot,沒有anchor; Sprite 類別的實體有 pivot,也有anchor;

來個試做:

左右各放一個兔子 (Sprite 類別),
左邊使用 anchor 設定中心點 ( anchor 相對於兔子材質的比例,設定為中心點 0.5)
右邊使用 pivot 設定 ( 單位為 pixel,取兔子素材實際尺寸的 0.5 倍)

加上黑色參考線用來協助判斷是否真的相同
[ Demo ],結果是相同

const bunnyLeft = PIXI.Sprite.from('assets/basics/bunny.png');
bunnyLeft.anchor.set(0.5);
bunnyLeft.x = app.screen.width / 2 - 100;
bunnyLeft.y = app.screen.height / 2;

const bunnyRight = PIXI.Sprite.from('assets/basics/bunny.png');
bunnyRight.pivot.set(26 * 0.5, 37 * 0.5); // 兔子寬 26, 高 37
bunnyRight.x = app.screen.width / 2 + 100;
bunnyRight.y = app.screen.height / 2;

可以這麼理解:anchor 影響的是 texture 的中心點,單位為向量(0~1)
pivot 為可視物件的 transform 中心點,單位為點
本質上還是有些差異

參考:Anchor vs Pivot - Pixi.js - HTML5 Game Devs Forum

xerver:The anchor is the attachment point for a texture (normalized to the size of the sprite), the pivot point is the point around which an object rotates (in pixel values).


差點忘了,昨天提到:

文字物件可以放東西,而且還能排序?

[ Demo ]

與上方 Demo 幾乎相同,僅將 Graphic 實體換成 Text 實體
children 陣列裡的 children 數量同樣為 3
也能使用 setChildIndex(child, index) 方法,將 box3 放在最底層

本篇提到的行為有點奇妙,但理解是因為繼承關係而來的特性時,也不那麼意外了。


上一篇
[Re:PixiJS - Day05] 可視物件的繼承關係
下一篇
[Re:PixiJS - Day07] 容器取得可視物件的 getChildAt()、getChildByName() 方法
系列文
再談 PixiJS,那些先前不一定有提到的部分與地雷45

尚未有邦友留言

立即登入留言