iT邦幫忙

2026 iThome 鐵人賽

DAY 24
0
Modern Web

《九重燼》Vue3 + PixiJS + Ink.js 視覺小說遊戲開發全紀錄系列 第 24

Day24 多平台展望:Web 之外還能怎麼走?

  • 分享至 

  • xImage
  •  

前幾天整理的,都是已經落地的系統:存檔、選項、音訊、Pixi 場景和資源預載。到了 Day24,我原本想直接談「Web 之外還能怎麼走」,但回頭對照 repo 後,發現更值得先說清楚的是:現在到底做到哪裡,哪些還停在規劃階段。

《九重燼》現在的主軸仍然是 Web。Vercel 是實際部署平台,npm run build 是正式建置流程,PWA 已經接上 vite-plugin-pwa,但目前只快取一小部分 app shell 資源,沒有把整包美術與音訊做成離線遊戲。Electron、Steam、Tauri 目前也沒有專案骨架。

目前的正式部署路線:Vercel

先看 vercel.json

{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "cleanUrls": true,
  "trailingSlash": false
}

也就是說,正式部署時 Vercel 會跑 npm run build,然後把 dist 當靜態輸出目錄。

package.json 裡的 build 指令不是只有 vite build

"build": "npm run check:ink && npm run generate:manifest && npm run generate:sections && vite build"

這裡有三個前置步驟:

  • check:ink:編譯 Ink 劇本,並輸出 src/narrative/compiled/main.json
  • generate:manifest:產生圖片與音訊預載 manifest,包括 Day23 提到的 preload-manifest.json
  • generate:sections:產生 src/data/chapter-sections.json 章節分段資料。

最後才交給 Vite 打包。這代表部署不是「把前端丟上去」這麼簡單;每次 build 都會重新編譯劇本,並重產資源清單與章節資料。對互動敘事遊戲來說,這些步驟尤其重要,因為劇情資料一錯,畫面再漂亮也沒用。

路由:多入口靜態站,不是單一 Vue Router 應用

vercel.json 還有幾條 rewrite:

{ "source": "/play", "destination": "/play.html" },
{ "source": "/ranking", "destination": "/ranking.html" }

入口頁、遊戲頁、排行頁各自有 HTML。vite.config.ts 也把它們列成三個 input:

input: {
  portal: resolve(__dirname, 'index.html'),
  play: resolve(__dirname, 'play.html'),
  ranking: resolve(__dirname, 'ranking.html'),
}

所以這不是傳統 Vue Router 的單頁站,而是 Vite 多入口靜態站。/play 只是被 Vercel 導到 play.html/ranking 導到 ranking.html。除了 assets/story/manifests/api/ 與三個入口 HTML 之外的路徑,才會回到 index.html

這個做法很適合現在的專案:Portal、遊戲本體、排行榜彼此獨立,又可以共用同一組 Vite build。

快取標頭:素材可以長效快取,劇本不能

Vercel 設定裡也把快取分開:

{
  "source": "/assets/(.*)",
  "headers": [
    { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
  ]
}

/assets/ 主要放圖片和音訊,可以使用長效快取。檔案名稱穩定時,瀏覽器不用每次重新下載。

/story//manifests/ 是另一回事:

"public, max-age=0, must-revalidate"

劇本和 manifest 不能像圖片一樣快取一年。故事修一句台詞、章節資料更新、結局條件調整,如果玩家一直拿到舊 JSON,存檔和劇情狀態就可能對不上。這也是 Day12 存檔版本化會遇到的同一個問題:遊戲資料會變,不能假裝每個版本都永遠相容。

PWA

PWA 支援已經接上,但範圍刻意壓得很小。

vite.config.ts 已經引入:

import { VitePWA } from 'vite-plugin-pwa'

設定也已經存在:

VitePWA({
  registerType: 'autoUpdate',
  workbox: {
    globPatterns: ['**/*.{js,css}'],
    navigateFallback: null,
  },
  manifest: {
    name: '九重燼 Embers of the Ninefold Court',
    short_name: '九重燼',
    start_url: '/play.html',
    display: 'standalone',
    orientation: 'any',
  },
})

這代表 build 後會有 PWA manifest 和 service worker。public/pwa/ 也有 icon:

  • icon-192.png
  • icon-512.png
  • icon-maskable-512.png

但這裡最重要的是快取範圍。workbox.globPatterns 只把 js/css 放進 precache;PWA icon 和少數 favicon 仍會被快取,但遊戲中的 webpmp3json 不會整批放進去。

所以現在的 PWA 可以安裝到桌面/主畫面,並以 standalone 方式開啟。

為什麼不直接做完整離線版

文字冒險看起來很適合離線,但《九重燼》不是只有文字。

Day23 講過,素材載入已經有 PreloadManager 和 chapter bundle。那是為了降低切場景卡頓,不是為了永久離線。圖片、CG、音訊加起來的體積不小;如果 service worker 一口氣快取全部資產,會遇到幾個問題。

第一,第一次安裝成本太高。玩家只是想試玩,結果瀏覽器開始抓兩百 MB 素材,體感會很差。

第二,更新會變麻煩。劇本、manifest、素材、存檔版本要一起考慮。

所以現在只做 app shell 快取。

Web 優先,不是 Web 限定

比較務實的路線應該是這樣:

先把 Web 版穩住。Vercel 建置、路由 rewrite、快取標頭、API,以及有限度的 PWA app shell 快取,這些基礎設施已經足以支撐公開 Demo。

接著把 PWA 做完整一點。不是馬上離線整包遊戲,而是先確認安裝體驗、圖示、啟動畫面與更新提示。尤其真機測試很重要,Chrome 桌面、Android、iOS Safari 對 PWA 的支援細節不完全一樣。

最後才考慮桌面封裝。等內容量、玩家需求、離線需求都明確之後,再評估 Electron、Tauri 或 Steam。那時候才知道要包的是一個試玩 Demo,還是一個值得安裝和更新的正式版。


上一篇
Day23 效能最佳化:PixiJS Renderer、資源預載與快取策略
下一篇
Day25 遊戲資源管理:Assets、章節與動態載入設計
系列文
《九重燼》Vue3 + PixiJS + Ink.js 視覺小說遊戲開發全紀錄25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言