Skip to content

網頁文字策略遊戲:技術棧選擇總結 ​

遊戲定位 ​

以文字為主的劇情遊戲,包含大量數據與策略模擬元素,在網頁上遊玩。開發模式為 vibe coding,以 Google Sheet 管理數據、Markdown 撰寫劇本腳本,搭配 AI 輔助生成程式碼。

技術棧選擇結論:React + TypeScript ​

為什麼不選專門的敘事引擎? ​

引擎適合場景不適合的原因
Twine純互動敘事(choose-your-own-adventure)缺乏複雜狀態管理能力,不適合策略模擬
ink (Inkle)分支劇本撰寫擅長敘事但非遊戲邏輯引擎,可作為混合方案的劇本層
Ren'Py有立繪的視覺小說Web 版體驗差(載入慢、體積大),不適合數據密集型遊戲

為什麼選 React + TypeScript? ​

  1. 狀態管理成熟:Zustand / Redux 等工具天生適合管理複雜的遊戲世界狀態(資源、屬性、關係、時間軸)
  2. 數據驅動設計:事件、角色、規則用 JSON/CSV 定義,程式碼只負責引擎邏輯,與內容分離
  3. UI 自由度高:策略遊戲需要的面板、儀表板、卡牌介面,前端框架處理最自然
  4. AI 生成品質最佳:Claude 等工具對 React + TypeScript 的程式碼生成品質是所有前端技術中最好的,最適合 vibe coding
  5. 與現有工作流相容:Google Sheet 匯出 CSV/JSON 直接餵入、Markdown 可用 remark/marked 解析

混合方案(可選) ​

如果劇情文本量很大,可將敘事部分交給 ink 處理(語法撰寫體驗好),遊戲邏輯由 TypeScript 負責。inkjs runtime 支援與遊戲引擎雙向溝通。

建議的系統架構 ​

遊戲引擎核心(純 TypeScript,不碰 UI)
├── 世界狀態 (World State)
├── 事件系統 (Event Engine) — 條件判斷、觸發、結果
├── 模擬引擎 (Simulation) — 每回合的數值運算
├── 劇情管理 (Narrative) — 可嵌入 ink 處理對話分支
└── 存檔系統 (Save/Load)

UI 層(React 元件)
├── 主畫面、地圖、角色面板
├── 對話介面
├── 事件卡牌 / 選擇介面
└── 數據儀表板

建議的資料架構 ​

project/
├── data/
│   ├── characters.csv      ← 從 Google Sheet 匯出
│   ├── items.csv
│   ├── events.csv           ← 事件條件、觸發規則、結果
│   └── balance.csv          ← 數值參數表
├── scripts/
│   ├── chapter-01.md        ← 劇情腳本
│   ├── chapter-02.md
│   └── ...
├── src/
│   ├── engine/              ← 遊戲邏輯(純 TypeScript,不碰 UI)
│   ├── components/          ← React UI 元件
│   └── editors/             ← 視覺化編輯器(後期開發)

核心原則:CSV 和 Markdown 是 single source of truth,日常內容迭代在 Google Sheet 和 .md 裡完成,不需要碰程式碼。

Markdown 劇本格式設計範例 ​

markdown
# 第一章:起點

你走進了村長的辦公室,桌上散落著文件。

> [條件: 智力 > 5] 你注意到文件裡藏著一張地圖。
> [條件: 魅力 > 7] 村長對你的到來顯得格外熱情。

## 選擇

- [查看文件] -> scene:examine_documents {好奇心 +1}
- [跟村長交談] -> scene:talk_to_chief {村長好感 +2}
- [直接離開] -> scene:leave {無變化}

人類讀寫直覺,同時可被解析器結構化處理。

視覺化編輯器開發優先順序 ​

不建議一開始就做編輯器。先用 Google Sheet + Markdown 手動跑通流程,確定數據結構穩定後,依痛點優先開發:

  1. 劇情流程圖 — 檢視分支結構與死路(推薦使用 React Flow)
  2. 數值模擬器 — 快速測試策略路線的數值平衡
  3. 事件條件編輯器 — 處理 Google Sheet 不擅長的複雜巢狀條件

後端方案:Supabase(BaaS) ​

為什麼需要後端? ​

Phase 1 為純前端(localStorage 存檔),但後續功能需要伺服器支援:

功能需求階段為什麼不能純前端
跨裝置存檔同步Phase 2-3localStorage 綁定瀏覽器,換裝置就丟失
源血基因碼交換Phase 5跨玩家資料必須存在共享伺服器
公共遺骸事件池Phase 5野外死亡遺物流入公共池,需全域資料庫
付費驗證Phase 5付費狀態需要可信的伺服器端記錄
反作弊Phase 5存檔驗證與源血品質校驗需後端參與

為什麼選 Supabase? ​

考量SupabaseFirebase自架(VPS + PostgreSQL)
資料庫PostgreSQL(成熟、可遷移)Firestore(NoSQL、廠商鎖定)PostgreSQL
認證內建 Auth(支援匿名、第三方)內建 Auth需自行整合
即時同步Realtime subscriptionsRealtime需自建 WebSocket
檔案儲存Storage(S3 相容)Cloud Storage需自行架設
邊緣函數Edge Functions(Deno)Cloud Functions需自行部署
免費額度500MB DB、1GB Storage、50K MAUSpark 方案有限制無,需自費
廠商鎖定風險低(標準 PostgreSQL,可隨時自架)高(Firestore 專有查詢語法)無
維運負擔幾乎零幾乎零需自行維運

結論:Supabase 提供完整的 BaaS 功能,底層為標準 PostgreSQL,廠商鎖定風險低。免費額度足以支撐早期開發與測試。若未來需要遷移,資料庫可直接匯出至自架 PostgreSQL。

Supabase 服務對應遊戲功能 ​

Supabase 服務遊戲功能
Auth玩家帳號(匿名登入→綁定社群帳號)、付費狀態驗證
PostgreSQL存檔同步、源血基因碼池、公共遺骸事件池、玩家設定檔
Storage存檔歷史版本(JSON 快照)、未來可能的 UGC 內容
Edge Functions付費回呼(ECPay/藍新金流)、源血品質驗證、反作弊校驗
Realtime暫不使用;未來若加入即時社群功能可啟用

資料庫 Schema 概念設計 ​

sql
-- 玩家基本資料
profiles (
  id UUID PRIMARY KEY REFERENCES auth.users,
  display_name TEXT,
  is_paid BOOLEAN DEFAULT FALSE,
  paid_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
)

-- 存檔(每玩家最多 3 欄位)
saves (
  id UUID PRIMARY KEY,
  user_id UUID REFERENCES profiles(id),
  slot INTEGER CHECK (slot BETWEEN 1 AND 3),
  save_data JSONB,        -- 完整 SaveData 結構
  version INTEGER,        -- 存檔版本號,用於遷移
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(user_id, slot)
)

-- 存檔歷史(自動備份)
save_history (
  id UUID PRIMARY KEY,
  save_id UUID REFERENCES saves(id),
  save_data JSONB,
  saved_at TIMESTAMPTZ DEFAULT NOW()
)

-- 源血基因碼池(跨玩家共享)
source_blood_pool (
  id UUID PRIMARY KEY,
  code TEXT UNIQUE,       -- WL-XXXX 短碼
  donor_user_id UUID REFERENCES profiles(id),
  gene_data JSONB,        -- 加密的基因碼資料
  quality INTEGER CHECK (quality BETWEEN 1 AND 5),
  is_consumed BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW()
)

-- 公共遺骸事件池(野外死亡遺物流轉)
public_remains (
  id UUID PRIMARY KEY,
  origin_user_id UUID REFERENCES profiles(id),
  region TEXT,            -- 死亡區域編碼 R##
  remain_data JSONB,      -- 遺物內容(技能、遺言片段、物資)
  quality_weight FLOAT,   -- 品質權重(影響被抽到的機率)
  created_at TIMESTAMPTZ DEFAULT NOW()
)

所有表啟用 Row Level Security(RLS),確保玩家只能讀寫自己的存檔,源血池和遺骸池為全域可讀但僅由 Edge Functions 寫入。

整合時程 ​

階段後端工作
Phase 1純前端,不碰 Supabase。localStorage 存檔
Phase 2-3引入 Supabase Auth(匿名登入)+ saves 表,實現跨裝置存檔同步。保留 localStorage 作為離線快取
Phase 5啟用 source_blood_pool、public_remains、Edge Functions。實裝付費驗證(ECPay/藍新)、源血交換、遺骸流轉

成本估算 ​

階段預估 MAUSupabase 方案月費
開發 + Alpha 測試< 100Free$0
Beta 公測100-1,000Free$0
正式營運初期1,000-5,000Free(接近上限)$0
正式營運成長5,000-50,000Pro~$25/月

Free 方案(500MB 資料庫、1GB 儲存、50K MAU)足以支撐到正式營運初期。SaveData 以 JSONB 存放,單筆存檔預估 10-50KB,500MB 可容納數萬份存檔。

風險與對策 ​

風險對策
RLS 設定錯誤導致資料洩漏上線前撰寫 RLS 測試腳本,模擬跨用戶存取
離線體驗降級Phase 2+ 採混合架構:localStorage 為主、Supabase 為同步層。無網路時降級為純本地
廠商鎖定Supabase 底層為標準 PostgreSQL + S3 Storage,可隨時匯出遷移至自架
Edge Functions 冷啟動延遲付費驗證回呼為非即時場景,冷啟動可接受

其他備選方案參考 ​

方案適用情境
Phaser.js需要較多視覺互動(地圖點擊、拖放、動畫),可搭配 React 做 UI 覆蓋層
Vue + TypeScript與 React 方案等價,依個人偏好選擇
純 ink + inkjs若策略模擬需求較輕,劇情為絕對核心