PixiJS 整合:特效、遊戲與編輯器
PixiJS 負責繪製:顯示物件、filter、blend mode 與 mesh 都留在 Pixi 這一側。ai*js 套件負責資料、狀態與生命週期,決定每一幀要畫什麼、物件何時建立與回收。只有 aispritejs/pixi 會匯入 Pixi,其他套件都不依賴 renderer。
每個套件都從三個角度說明:
- 遊戲中:遊戲執行期的邏輯與效能。
- 編輯器中:工具、存檔、除錯與測試。
- PixiJS 技法:搭配使用的 Pixi 顯示物件、filter 與 blend mode。
| 技法 | 效果 | 套件 |
|---|---|---|
| ColorMatrixFilter | 受擊閃白、暫停時降低飽和度 | aifsmjs、aieventjs |
| BlurFilter | 暫停畫面或景深 | aifsmjs |
| DisplacementFilter | 水面或熱浪扭曲,位移貼圖的 sprite 由 system 移動 | aiecsjs |
| ParticleContainer | 上千發子彈 | aipooljs、aiecsjs、aiquadtreejs |
| add / screen blend mode | 光暈、雷射 | aipooljs、aispritejs |
| MeshRope | 拖尾 | aiecsjs(SoA 歷史緩衝)、aipooljs |
RenderTexture / generateTexture |
縮圖、程序化產生的 frame | aibridgejs、aispritejs |
| BitmapText | 傷害數字、計數器 | aipooljs、aieventjs |
| mask | 戰爭迷霧 | aiquadtreejs、aiecsjs |
| TilingSprite | 視差捲動 | aiecsjs、aifsmjs |
| 事件與 hit testing | 拖曳、框選 | aibridgejs、aieventjs、aifsmjs、aiquadtreejs |
aiecsjs
Section titled “aiecsjs”Archetype ECS:component 存成 TypedArray SoA 欄位,system 每幀算完再寫進 Pixi。見 aiecsjs 指南。
遊戲中
- SoA 欄位直接寫進 ParticleContainer 裡 Particle 的座標,不需要逐一同步物件。
aiecsjs/loop提供固定步長迴圈,模擬結果不受螢幕更新率影響。- 用
ChildOf記錄砲塔屬於哪個車身,再由 system 依車身位置擺放砲塔。
編輯器中
- format 2 snapshot 當作存檔與 undo 檔:
toJSON輸出 JSON,serializeWorld輸出 binary,連續變更交給createDeltaSerializer。 - 以相同種類與欄位配置再次定義同一個 component
key會回傳既有的 component,適合重新載入指令碼;配置不同時丟出EcsError。 onAdd/onRemoveobserver 讓場景節點跟著 entity 建立與移除。
PixiJS 技法
- ParticleContainer:由 SoA 欄位驅動大量 Particle。
- DisplacementFilter:位移貼圖的 sprite 由 system 每幀移動。
- MeshRope:把最近幾幀的位置存成 SoA 歷史緩衝,再寫進 rope 的點。
aispritejs
Section titled “aispritejs”輸入驅動的 sprite 動畫狀態圖:遊戲邏輯只設定 input,由 graph 決定播放哪個 frame。見 aispritejs 指南。
遊戲中
- controller 把玩家操作轉成
number、boolean、trigger三種 input。 from: "*"搭配priority,讓受擊或死亡從任何狀態打斷目前的動畫。- 非循環的 clip 以
onEnd播完後回到 idle。
編輯器中
aispritejs/schema匯出 graph 的 JSON Schema,編輯器或 CI 都能用它驗證 graph JSON。parseAtlas把 PixiJS v8 格式的 atlas 加上 control block 轉成 graph,loadAtlas則直接建立 animator。- listener 採 run-to-completion:scrub 時間軸時,在最外層
update()回傳後讀activeState,讀數不會停在中間狀態。
PixiJS 技法
createPixiSpriteAnimator每次update()都會替換sprite.texture。- adapter 只接管 texture 與 anchor,同一個 sprite 仍可自由設定 tint 或 blend mode。
- 程序化繪製的 frame 可以先用
generateTexturebake 成 RenderTexture,再組成 frameKey → Texture map 交給 adapter。
aiaudiojs
Section titled “aiaudiojs”Howler.js 的薄包裝,管理音效的載入、播放、crossfade 與釋放。見 aiaudiojs 指南。
遊戲中
- 關卡 BGM 之間用
curve: "equal-power"的crossfade切換。 - 在 Pixi 第一個
pointeruphandler 裡呼叫unlock(),讓 AudioContext 在 user gesture 內恢復。 - 離開場景時以
AbortSignal取消進行中的 crossfade;abort 不會停止任何 voice,兩個 sound 之後由呼叫端處理。
編輯器中
- 切換專案時呼叫
disposeAll(),進行中的load()也會以AudioDisposedError拒絕。 - 時間軸預覽以
play()與stop()試聽。
PixiJS 技法
- fade 時間與 BlurFilter 或 ColorMatrixFilter 的 tween 對齊;
crossfade的duration以秒計,fade()以毫秒計。
aiaudiojs 不處理 audio sprite 與空間音效,需要時請直接使用 Howler。
aieventjs
Section titled “aieventjs”型別安全的事件 emitter,負責模組之間的通知。見 aieventjs 指南。
遊戲中
- 瞄準用的 pointer move 加上
throttleMs:leading edge 節流,區間內的事件直接丟棄。 - 過場觸發只需要一次,用
once。 captureErrors讓單一 listener 丟出錯誤時,不會中斷這一幀的 dispatch。
編輯器中
- 事件檢視器以
*訂閱全部事件,搭配sampleRate只取樣一部分。 - 切換工具時 abort 該工具的
signal,一次移除它的所有 listener。
PixiJS 技法
- 把 Pixi 的 FederatedPointerEvent 轉成自己的型別化事件再
emit,payload 只複製需要的欄位,因為 Pixi 會回收事件物件。 - BitmapText HUD 訂閱分數事件並更新文字。
aifsmjs
Section titled “aifsmjs”確定性 FSM:machine 定義是純資料,guard、action 與 effect 在 runtime 注入。見 aifsmjs 指南。
遊戲中
- 玩家與武器各自是一個 sub-machine。
- 無敵時間(i-frame)由
aifsmjs/timer的after()排程結束。 - 純函式
step()不執行 effect,同一串事件可以確定性重放;它只重現父 machine,不含 sub-machine 的狀態。
編輯器中
aifsmjs/inspect的recorder與persistmiddleware 供狀態面板使用。aifsmjs/replay依事件紀錄重現 bug report。- CI 以
aifsmjs/pbt執行 fast-check 屬性測試。
PixiJS 技法
- 進入
hit時套上 ColorMatrixFilter 閃白。 - 進入
paused時對遊戲層加上 BlurFilter。 - 場景 FSM 切換 TilingSprite 背景層。
aiquadtreejs
Section titled “aiquadtreejs”每幀重建的 2D quadtree,只做廣泛相(broadphase),精確判斷由呼叫端負責。見 aiquadtreejs 指南。
遊戲中
- 子彈的碰撞廣泛相每幀
clear()後重新insert()。 bounds與查詢範圍可以直接使用 PixigetBounds()的結果,兩者的 AABB 右緣與下緣都不含在內。- 以敵人的視野範圍呼叫
retrieve,取得可能看見的目標。
編輯器中
- 上千個節點的框選與 hover 選取:先用
retrieve取得候選,再做精確判斷。
PixiJS 技法
- 戰爭迷霧 mask:查詢可見區域內的物件。
- hit testing:先用 quadtree 縮小候選,再逐一精確判斷。
aipooljs
Section titled “aipooljs”固定大小的 object pool,acquire() 與 release() 都是 O(1)。見 aipooljs 指南。
遊戲中
- 子彈與粒子從池子取用,用完歸還。
onOverflow: 'null'在負載過高時讓acquire()回傳null,這次生成直接丟棄。borrow(fn, { signal })處理有範圍的特效:fn結束後自動歸還;abort 只歸還物件,不會停止fn內的工作。alive與available計數可以直接顯示在除錯面板。
編輯器中
- 預覽節點也放進池子重複使用。
- 歸還不屬於池子或已經歸還的物件會丟出
PoolError,能及早抓到工具的 bug。
PixiJS 技法
- Particle、BitmapText 傷害數字與 MeshRope 的片段都適合放進池子。
aibridgejs
Section titled “aibridgejs”Transport-agnostic 的跨 context bridge,host 之間的差異交給 adapter 處理。見 aibridgejs 指南。
遊戲中
- 遊戲嵌在 WebView 裡時,用
call請 host 存檔或處理購買,用emit回報進度。 timeoutMs讓沒有回應的 host 以BridgeTimeoutError失敗,不會一直等下去。
編輯器中
- 外殼頁面與畫布 iframe 之間使用 iframe adapter,
targetOrigin設為精確的 origin,Sprite Playground 就是這樣連接的。 - 測試改用
aibridgejs/mock的 mock adapter。 aibridgejs/detect依 host 環境自動選擇 adapter。
PixiJS 技法
- 用 RenderTexture 產生縮圖、轉成 PNG,再透過
call送給 host。 - host 調整尺寸時送出事件,遊戲端收到後呼叫
renderer.resize。
aipooljs + aiquadtreejs + aiecsjs + aieventjs。發射時從池子取出子彈並建立 entity,movement system 更新 SoA 位置欄位並寫進 ParticleContainer。每幀以這些欄位重建 quadtree,retrieve 取得候選後做精確判斷;命中時 emit 事件,BitmapText HUD 與音效各自訂閱。離場或命中的子彈歸還池子。
aispritejs + aifsmjs + aiaudiojs。玩家輸入送進 aifsmjs 的 machine,決定 idle、攻擊、受擊等行為狀態。每次轉移由 effect 把新狀態轉成 aispritejs 的 input,並透過 aiaudiojs 播放對應音效;aispritejs 再依 graph 決定播放的 frame。
aibridgejs + aifsmjs(aifsmjs/inspect)+ aiecsjs(aiecsjs/serialize)+ aispritejs(aispritejs/schema)。外殼頁面與 Pixi 畫布 iframe 透過 aibridgejs 溝通。aifsmjs 管理工具模式,aifsmjs/inspect 的 recorder 提供狀態面板與 bug report 所需的紀錄。場景資料放在 aiecsjs world,以 aiecsjs/serialize 存檔與 undo。匯入的動畫 graph 先以 aispritejs/schema 驗證。Sprite Playground 已實作其中外殼與 iframe 之間的 bridge。
以下五個套件指南都附有可互動的 PixiJS 範例: