iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 25
0
Modern Web

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

[Re:PixiJS - Day25] destroy(),連同快取一起摧毀物件

前幾篇提了 TextureBaseTexturePixiJS 的 Cache
這篇討論 可視物件destroy() 方法

在 PixiJS 的 Container子類別 裡,單純透過父物件 removeChild()
並不會移除物件本身,只是移出場景。
要完全移除可視物件時,可使用 destroy() 方法


Sprite.detroy(),不帶參數:

SPRITE - Basic 的例子舉例:

執行了 bunny.destroy(); 後:

  • 兔子從場景上移除了(app.stage.children 為空陣列)
  • 兔子的 TextureCache 快取:還在
  • 兔子的 BaseTextureCache 快取:還在
  • 兔子物件還在,標示為 _destroy:true


bunny.destroy();
console.log(PIXI.utils.BaseTextureCache);

_destroyed:


在各個 API 的說明裡,都有說在執行 destroy() 後,不要再使用該個物件


呼叫 Sprite.detroy() 時,帶入 texture:true 與 baseTexture:true

執行了 bunny.destroy({texture: true, baseTexture: true}); 後:

  • 兔子從場景上移除了(app.stage.children 為空陣列)
  • 兔子的 TextureCache 快取:已移除
  • 兔子的 BaseTextureCache 快取:已移除
  • 兔子物件還在,標示為 _destroy:true


bunny.destroy({
    texture:true, // 將 texture 移除
    baseTexture:true // 將 baseTexture 移除
});

destroy() 方法帶入的 children 屬性:

children 設定為 true 時,會將 destroy() 的其他屬性如 texture: truebaseTexture: true 再傳入子物件、孫物件

Container#destroy() 實作:

destroy(options) {
    super.destroy();
    this.sortDirty = false;
    const destroyChildren = typeof options === 'boolean' ? options : options && options.children;
    const oldChildren = this.removeChildren(0, this.children.length);
    if (destroyChildren) {
        for (let i = 0; i < oldChildren.length; ++i) {
            oldChildren[i].destroy(options);
        }
    }
}

destroy({children: true}) 的終點:

會到最底層 DisplayObjectdestroy() 實作

destroy(_options) {
    if (this.parent) {
        this.parent.removeChild(this);
    }
    this.removeAllListeners();
    this.transform = null;
    this.parent = null;
    this._bounds = null;
    this._mask = null;
    this.filters = null;
    this.filterArea = null;
    this.hitArea = null;
    this.interactive = false;
    this.interactiveChildren = false;
    this._destroyed = true;
}

Destroy 物件與釋放記憶體:

相關討論:difference-between-texture-and-basetexture

ivan.popelyshev:
Destroying PIXI.Texture does not free memory, it just makes texture not valid and removes it from image cache, so other sprites wont be able to use it. I really dont know cases when you have to call it :)

Destroying PIXI.BaseTexture frees WebGL objects that are bound to it. Call it for dynamic texture that you use or some statics that arent needed anymore.

大意:摧毀 PIXI.texture不會釋放記憶體,釋放記憶體時需摧毀 PIXI.BaseTexture,並且確定相對應的 PIXI.texture 不會再被使用

前半小節
好像都不是很難理解的參數,又好像理解了可視物件的層級關係
可喜可賀 (?)


以下一些交叉測試,參考用即可:

不同 Sprite 但 baseTexture 相同時的 destroy();

  • 準備兩個 Sprite,使用同一張圖片
const bunnyL = PIXI.Sprite.from('assets/basics/bunny.png');
app.stage.addChild(bunnyL);

const bunnyR = PIXI.Sprite.from('assets/basics/bunny.png');
app.stage.addChild(bunnyR);

先前文章 可知,使用 Sprite.from() 帶入相同網址,會得到同一個 texture

此時若將其一的 texture 刪除

兩個 Sprite 皆會刪除

但只有執行了 destroy({texture: true}) 的 bunnyL 本身Texture 被摧毀
bunnyR 沒有執行 destroy(),但是共用的 texture 已被移除,所以 bunnyR 從畫面上消失了

右邊的兔子除了 texture 不見外,其他狀態皆相同

  • 存在於場景上
  • alpha為 1
  • _destoryed 為 false


PIXI.Sprite 的 destroy()

讀入一隻兔子後,texture 與 baseTexture 狀態:

幾種交叉測試結果:

  • destroy() 不帶參數時:texture / baseTexture 皆保留

  • destroy({texture: true}) 設定 texture:true 時:texture 移除, baseTexture 保留

  • destroy({baseTexture: true}) 設定 baseTexture:true 時:texture 保留, baseTexture 保留,這是最特別的一個

  • destroy({texture: true, baseTexture: true}) 設定 texture: true、 baseTexture:true 時:texture 移除, baseTexture 移除

由於 Sprite 的 Texture、BaseTexture 有可能給不同的 Sprite 使用,destroy 的情形較為複雜


PIXI.Text 的 destroy()



結果:

  • 不用帶參數,textureCache、baseTextureCache 皆移除

用不到的 Text,就直接 destroy() 吧


PIXI.Graphics 的 destroy()


  • 畫出來的 Graphics實體 不會存在於 Texture / BaseTexture 裡,執行 destroy() 不影響結果。


  • 填入材質線段,快取為材質的快取,與 Graphics實體 無關。
  • 即使執行 destroy({children: true, texture: true, baseTexture: true});
    快取結果仍然相同

參考:不同可視物件的 destroy() 實作:

不同類別的可視物件繼承皆繼承自 PIXI.Container,但會覆寫其 destroy() 的方法

從原始檔看各個可視類別的實作:

後半心得:
每種類別的 destroy()方法 實作不同,需視情況執行 destroy()


上一篇
[Re:PixiJS - Day24] 用 Texture 實作把網頁弄壞 的 Demo
下一篇
[Re:PixiJS - Day26] Loader(1/2) / 讀取事件與解析讀取的檔案
系列文
再談 PixiJS,那些先前不一定有提到的部分與地雷45

尚未有邦友留言

立即登入留言