跳到內容

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

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 / onRemove observer 讓場景節點跟著 entity 建立與移除。

PixiJS 技法

  • ParticleContainer:由 SoA 欄位驅動大量 Particle。
  • DisplacementFilter:位移貼圖的 sprite 由 system 每幀移動。
  • MeshRope:把最近幾幀的位置存成 SoA 歷史緩衝,再寫進 rope 的點。

輸入驅動的 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 可以先用 generateTexture bake 成 RenderTexture,再組成 frameKey → Texture map 交給 adapter。

Howler.js 的薄包裝,管理音效的載入、播放、crossfade 與釋放。見 aiaudiojs 指南。

遊戲中

  • 關卡 BGM 之間用 curve: "equal-power" 的 crossfade 切換。
  • 在 Pixi 第一個 pointerup handler 裡呼叫 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。

型別安全的事件 emitter,負責模組之間的通知。見 aieventjs 指南。

遊戲中

  • 瞄準用的 pointer move 加上 throttleMs:leading edge 節流,區間內的事件直接丟棄。
  • 過場觸發只需要一次,用 once。
  • captureErrors 讓單一 listener 丟出錯誤時,不會中斷這一幀的 dispatch。

編輯器中

  • 事件檢視器以 * 訂閱全部事件,搭配 sampleRate 只取樣一部分。
  • 切換工具時 abort 該工具的 signal,一次移除它的所有 listener。

PixiJS 技法

  • 把 Pixi 的 FederatedPointerEvent 轉成自己的型別化事件再 emit,payload 只複製需要的欄位,因為 Pixi 會回收事件物件。
  • BitmapText HUD 訂閱分數事件並更新文字。

確定性 FSM:machine 定義是純資料,guard、action 與 effect 在 runtime 注入。見 aifsmjs 指南。

遊戲中

  • 玩家與武器各自是一個 sub-machine。
  • 無敵時間(i-frame)由 aifsmjs/timer 的 after() 排程結束。
  • 純函式 step() 不執行 effect,同一串事件可以確定性重放;它只重現父 machine,不含 sub-machine 的狀態。

編輯器中

  • aifsmjs/inspect 的 recorder 與 persist middleware 供狀態面板使用。
  • aifsmjs/replay 依事件紀錄重現 bug report。
  • CI 以 aifsmjs/pbt 執行 fast-check 屬性測試。

PixiJS 技法

  • 進入 hit 時套上 ColorMatrixFilter 閃白。
  • 進入 paused 時對遊戲層加上 BlurFilter。
  • 場景 FSM 切換 TilingSprite 背景層。

每幀重建的 2D quadtree,只做廣泛相(broadphase),精確判斷由呼叫端負責。見 aiquadtreejs 指南。

遊戲中

  • 子彈的碰撞廣泛相每幀 clear() 後重新 insert()。
  • bounds 與查詢範圍可以直接使用 Pixi getBounds() 的結果,兩者的 AABB 右緣與下緣都不含在內。
  • 以敵人的視野範圍呼叫 retrieve,取得可能看見的目標。

編輯器中

  • 上千個節點的框選與 hover 選取:先用 retrieve 取得候選,再做精確判斷。

PixiJS 技法

  • 戰爭迷霧 mask:查詢可見區域內的物件。
  • hit testing:先用 quadtree 縮小候選,再逐一精確判斷。

固定大小的 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 的片段都適合放進池子。

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 範例: