---
# System prepended metadata

title: PixiJS 研究
tags: [PixiJS]

---

# PixiJS 研究
1. 官方Github: https://github.com/pixijs/pixijs
2. Demo參考: https://pixijs.io/examples/#/demos-basic/container.js
3. 官方教學文件：https://github.com/kittykatattack/learningPixi
   英文版使用 Pixi v5.3.10，中文版使用 Pixi v4.5.5
4. PixiJs Api: https://api.pixijs.io/index.html
5. TypeScript PixiJS: https://github.com/pixijs/pixi-typescript
    :::spoiler ~~現成 typescript+pixijs 的 github 專案 (測試中)~~
    https://github.com/GuillaumeDesforges/pixijs-typescript-starter
    下載後使用 vscode 開啟，在終端機輸入
    ```
    yarn install
    ```
    安裝相關的 package 後直接執行就能跑起來
    不過此專案的 package 版本並不是最新的，可以使用指令
    ```
    yarn upgrade --latest
    ```
    更新全部 package 的版本，但是目前測試升級後專案無法成功執行起來...
    :::
6. webpack設定+簡易範例: https://jameskiefer.com/posts/getting-started-with-pixi.js-and-webpack/
7. anchor預設為(0,0): https://api.pixijs.io/@pixi/sprite/PIXI/Sprite.html#anchor
8. 免費好用的spritesheet軟體 [Free Texture Packer](http://free-tex-packer.com)

---
### 載入SpriteSheet
:::success
```javascript=
const loader = new PIXI.Loader();
loader.add("相對路徑/檔名.json")
.load((loader: PIXI.Loader, resources: PIXI.utils.Dict<PIXI.LoaderResource>)=>{
    const sheet = loader.resources["相對路徑/檔名.json"].spritesheet;
    const img = new PIXI.Sprite(sheet.textures["sprite名稱.副檔名"])
});
```
:::

:::success
切九宮格 [文件](https://pixijs.download/dev/docs/PIXI.NineSlicePlane.html)
```javascript=
const img = new PIXI.NineSlicePlane(sheet.textures["sprite名稱.副檔名"], 30, 20, 30, 20);
```
:::

---
### 事件

:::success


使用 [PIXI.utils.EventEmitter](https://api.pixijs.io/@pixi/utils/PIXI/utils/EventEmitter.html), 基於 [EventEmitter3](https://github.com/primus/eventemitter3)

#### 簡易範例
:::spoiler
```javascript=
import * as PIXI from "pixi.js";

export enum CustomEvent {
    atlasLoaded = "atladLoaded"
}

export class EventDispatcher extends PIXI.utils.EventEmitter {
    static private inst: EventDispatcher;
    public static get instance(): EventDispatcher {
        return this.inst;
    }

    public static create() {
        if (this.inst == null) this.inst = new EventDispatcher();
    }

    public static destroy() {
        if (this.inst != null) this.inst.removeAllListeners();

        this.inst = null;
    }

    public static addListener(event: CustomEvent, callback: PIXI.utils.EventEmitter.ListenerFn, thisObj: any) {
        this.inst.on(event, callback, thisObj);
    }

    public static removeListener(event: CustomEvent, callback: PIXI.utils.EventEmitter.ListenerFn, thisObj: any) {
        this.inst.off(event, callback, thisObj);
    }

    public static dispatch(event: CustomEvent, data?: any) {
        if (data == null) this.inst.emit(event);
        else this.inst.emit(event, data);
    }
}
```
<br>

註冊和接收
```javascript=
import * as PIXI from "pixi.js";
import { EventDispatcher, CustomEvent } from "./EventDispatcher";

...略

EventDispatcher.addListener(CustomEvent.atlasLoaded, this.onAtlasLoaded, this);

...略

onAtlasLoaded(...args: Array<any>){
    console.log(`ATLAS LOADED: ${args[0]}`);    //ATLAS LOADED: hi
}
```
<br>

觸發事件
```javascript=
EventDispatcher.dispatch(CustomEvent.atlasLoaded, "hi");
```
:::

---
## Bitmap font 製作
:::success
推薦使用 [BMFont](https://www.angelcode.com/products/bmfont/)
<br>

:::spoiler
1. 開啟 Edit -> Open Image Manager
2. 開啟 (Image -> Import image)
3. 設定素材對應的字元ID
    以設定 **數字0** 為例, 滑鼠移到 **數字0** 的位置, **ID** 是圖片下方顯示的數字
    ![](https://i.imgur.com/PvG7ctS.png)
4. 開啟 Options -> Export Options
    * Bit depth 預設 8, 但必需選擇 **<font color=red>32</font>**, 才能保持色彩和透明度
    * Textures 預設 tga, 改選擇 **<font color=red>png</font>**
    * Font description 目前測試 **Text**, **XML** 都能在 pixi 正常讀取
    ![](https://i.imgur.com/GGhK1p5.png)
5. 輸出字型 Options -> Save bitmap font as...
6. 使用文字編輯器開啟剛剛輸出的 .fnt
7. 修改字型名稱 **<font color=red>info face="字型名稱"</font>**
    * 此欄位是在 pixi 使用的字型名稱
    * BMFont只能選系統已存在的字型, 預設選 Arial, 無法自定義名稱
    ![](https://i.imgur.com/AafOp8b.png)
8. pixi 使用方式
```javascript
const fnt = loader.resources["assets/test.fnt"].bitmapFont;
const txt = new PIXI.BitmapText("0123456789", {
    fontName: "字型名稱"
});
this.stage.addChild(txt);
```
![](https://i.imgur.com/3HDrHbG.png)

:::

---

## 碰撞偵測
:::success
矩形檢查 - [參考來源](https://hsiangfeng.github.io/javascript/20200518/1745009932/)
:::spoiler
```javascript=
boxesIntersect(a: PIXI物件類型, b: PIXI物件類型) {
    var ab = a.getBounds();
    var bb = b.getBounds();
    return ab.x + ab.width > bb.x && ab.x < bb.x + bb.width && ab.y + ab.height > bb.y && ab.y < bb.y + bb.height;
}
...
const isHitted = this.boxesIntersect(物件A, 物件B);
```
:::

---

### Graphics簡易顏色設定
:::success
Graphics圖形繪製時填入白色, 再設定 tint 來染色
:::spoiler
```javascript=
const shape = new PIXI.Graphics();
shape.beginFill(0xffffff, 0.5);
shape.drawCircle(0, 0, 50);
this.stage.addChild(shape);

shape.tint = 0xff0000;
```
:::

---
## 套用外部shader
:::success
:::spoiler
以載入fragment shader為例
```javascript=
const loader = new PIXI.Loader();
loader.add("相對路徑/檔名.frag").load((loader, resources) => {
    const frag = loader.resources["相對路徑/檔名.frag"].data;
    const filter = new PIXI.Filter(null, frag);
    某sprite.filters = [filter];
});
```
更新 shader uniform 變數
```glsl
uniform float u_time;
```
```javascript=
const data = {
    u_time: 0
}
const filter = new PIXI.Filter(null, frag, data);

...

//每個frame更新 data.u_time.value
filter.uniforms.u_time = performance.now() * 0.001;
```
[type 名稱參考來源](https://github.com/pixijs/pixijs/blob/364c2457c6693d6e3ab68786539c53d566503e7b/src/core/renderers/webgl/shaders/Shader.js#L232-L463)
<br>
:::warning
WebGL 2.0 還未普及, 也還不是各家瀏覽器預設啟用的功能
目前先以 WebGL 1.0 (OpenGL ES 2.0, GLSL 1.x) 為主

:::
---

## Render texture
:::success
擷取畫面+裁切特定範圍

:::spoiler
```typescript=
export class Main extends PIXI.Application {
...
    const param: PIXI.IBaseTextureOptions = {
        width: this.stage.width,
        height: this.stage.height
    };
...
    const screenTex = PIXI.RenderTexture.create(param);
    this.renderer.render(this.stage, { renderTexture: screenTex });

    const newTex = new PIXI.Texture(screenTex.baseTexture, new PIXI.Rectangle(100, 100, 300, 300));
    const sprite = new PIXI.Sprite(newTex);
    this.stage.addChild(sprite);
}

```
:::

---
## 骨骼動畫
### spine
:::success
安裝 [pixi-spine](https://github.com/pixijs/spine)

:::spoiler
```nodejs
npm install pixi-spine
```

```typescript=
import { Spine } from "pixi-spine"
...
test(){
    const loader = new PIXI.Loader();
    loader.add("res名稱", "res相對路徑.json")
    .load((loader, resources) => {
       const anim = new Spine(loader.res名稱.spineData); 
        
       this.stage.addChild(anim);
        
        if(anim.state.hasAnimation("動畫名稱")){
            anim.state.setAnimation(0, "動畫名稱", loop);
        }
    });
}

```
:::


### spine 疑難排解

:::danger
* 無法載入 .atlas 檔案

:::success

:::spoiler
主要發生在 IIS server, 參考 [IIS server設定](https://hackmd.io/oDM9hVv7TpGRPHGN6SLGng)
* 需要新增 MIME 類型
```
.atlas
text/plain
```
:::

:::danger
* Uncaught TypeError: Cannot read properties of undefined (reading 'substr') at detectSpineVersion (loader-uni.es.js:77)

:::success

:::spoiler
此問題主要是透過 dragonBones editor 匯出 spine 格式檔案, 缺少版號資訊
1. 使用文字編輯器開啟 spine 的 json
2. <font color=red>skeleton</font> 欄位底下新增 key 並且填上 spine 版號 
```json=
"spine":"3.3"
```

:::

---
## 待確認項目
1. 物件實體沒有 uid, 需要透過第三方套件來產生 ?
2. 如何透過 console 呼叫物件實體 ?

---
## 疑難排解
:::danger
透過 PIXI.Loader 下載資源出現錯誤
Cannot add resources while the loader is running
<br>
:::success

:::spoiler
每個 Loader 同時只能下載一個資源
需要清除 Loader cache 或額外建立新的 Loader 來下載
:::

:::danger
其他相依 pixi 的套件, 無法辨識 PIXI
:::success

:::spoiler
修改 webpack.config.js
```nodejs
const webpack = require("webpack");

const config = {
    plugin: [
        new webpack.ProvidePlugin({
            PIXI: "pixi.js"
        }),
    ]
}
```
:::
---
## performance
* [ParticleContainer](http://pixijs.download/dev/docs/PIXI.ParticleContainer.html)
* [Pixi Performance Tips](https://gist.github.com/GoodBoyDigital/5aea403f8528fb89c4f7639d6a51353f)
* [Inside PixiJS: The ultimate scene graph optimization](https://javascript.plainenglish.io/inside-pixijs-the-ultimate-scene-graph-optimization-35b62bb2153)

#### 延伸閱讀
* [GPU Accelerated Compositing in Chrome](https://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome)
* [Rendering Performance](https://developers.google.com/web/fundamentals/performance/rendering)
* [如何優化像素管道的 Paint 和 Composite](https://cythilya.github.io/2018/07/20/compositing-and-painting/)

---

###### tags: `PixiJS`