OPENGAMES DEVELOPER CENTER

把遊戲做好,
直接在瀏覽器玩。

從匯出、封裝、測試、發布,到帳號存檔與多人連線,這裡是 OpenGames 遊戲的完整開發規格。

index.html · SDK v1
<script src="/opengames-sdk.js"></script>
<script>
  async function startGame() {
    const platform = await OpenGames.ready();
    console.log(platform.locale, platform.cloudSaves.enabled);
    // Initialize your game after the bridge is ready.
  }
  startGame();
</script>
01

從這裡開始

準備網頁建置,不是安裝檔

OpenGames 會在受限 iframe 中執行靜態 HTML、JavaScript、WebAssembly、媒體與字型。請從原始專案匯出 Web 版本,透過 HTTP 測試,再壓縮輸出資料夾裡面的檔案。

1

匯出

建立包含 index.html 的靜態瀏覽器版本。

2

測試

透過 HTTP 開啟,修正 Console 與 Network 的所有錯誤。

3

檢查並發布

先用本機轉換檢查,再壓縮根目錄內容並上傳。

必要 ZIP 結構
my-game.zip
├─ index.html
├─ game.js
├─ game.wasm
└─ assets/
   ├─ sprites.webp
   └─ music.ogg
02

WEB EXPORTS

從原始專案匯出

EXE、APK、IPA 或桌面安裝程式無法可靠轉換。請使用對應的原始專案與官方 Web 工具鏈。

UNITY WEBUnity C# → Web+

從 Unity 原始專案建立 Web 版本;Windows EXE 或 Android APK 不能取代原始專案。

  1. 在 Unity Hub 為專案使用的 Editor 版本安裝 Web Build Support。
  2. 建立並切換到 Web Build Profile,加入要發布的場景,關閉 Development Build。
  3. 移除原生 DLL、桌面檔案系統、原生 Socket,以及強制使用 SharedArrayBuffer 的套件。
  4. 輸出到新的空資料夾;ZIP 只包含輸出資料夾內的 index.html、Build 與資源。
Unity 官方 Web 文件 ↗
C / C++ / WASMC/C++ → Emscripten+

Emscripten 重新編譯原始碼;Windows API、桌面視窗與同步檔案流程通常需要改寫。

  1. 安裝並啟用 emsdk;Windows 使用 Emscripten Command Prompt。
  2. 使用 em++ 或 emcmake 建立 Release 網頁版本,輸出檔名設為 index.html。
  3. 把阻塞式 while 遊戲迴圈改為 Emscripten main loop,並以 --preload-file 封裝素材。
  4. 透過 emrun 或本機 HTTP 伺服器測試,不要直接雙擊 HTML。
Emscripten 官方教學 ↗
C# / .NET WASM獨立 Blazor WebAssembly+

只適用於能發布成靜態檔案的獨立 WebAssembly 專案;WinForms、WPF、MAUI 與需要 ASP.NET Server 的專案不能直接上傳。

  1. 確認是獨立 Blazor WebAssembly,而不是桌面 UI 或必須常駐伺服器的專案。
  2. 移除 Registry、本機任意檔案、原生 DLL 與伺服器端相依。
  3. 執行 dotnet publish -c Release。
  4. 從 publish/wwwroot 或 browser-wasm/publish 取出包含 index.html 與 _framework 的靜態輸出。
Microsoft 官方部署文件 ↗
GODOT WEBGodot → Web+

Godot 4 的 GDScript 專案可匯出;Godot 4 C# 目前不能匯出到 Web。

  1. 優先使用 Compatibility renderer,移除 Web 不支援的原生外掛。
  2. 安裝與 Editor 同版本的 Export Templates。
  3. 新增 Web preset,選好主場景與資源,輸出檔名設為 index.html。
  4. 採用單執行緒相容建置,透過 HTTP 測試後再封裝。
Godot 官方 Web 文件 ↗
本機 HTTP 測試
# Run this inside the exported build folder.
py -m http.server 8080

# Then open http://localhost:8080 and inspect Console + Network.
03

PACKAGE & PUBLISH

套件就是公開版本

ZIP 硬性限制

  • ZIP 根目錄必須直接看到 index.html。
  • 壓縮後 50 MiB、解壓後 250 MiB、最多 2,000 個檔案。
  • 不能加密、巢狀壓縮,也不能含絕對路徑、上層路徑或磁碟機路徑。
  • 發布後路徑區分大小寫;素材請使用相對網址。

禁止檔案

可執行檔、腳本、安裝程式、行動套件與巢狀壓縮檔會被拒絕:

exe bat cmd ps1 sh php py rb cgi jar msi scr com apk dmg pkg deb rpm zip rar 7z tar

DLL 只允許位於 .NET WebAssembly 的 _framework 目錄;Gzip 只允許用於平台可辨識的 Web 建置資源。

作品資料要求

  • 繁中與英文名稱皆必填,各 1–80 字元。
  • 繁中與英文介紹皆必填,各 1–1,600 字元。
  • 最多 8 個逗號分隔標籤;版本為 1–20 個英數字、點、底線或連字號。
  • 每位創作者每天最多發布 3 個版本。

權利設定彼此獨立

作品授權、選填的原始碼網址與 ZIP 下載權限要分開設定。發布到開源平台,不代表遊戲必須開源。

發布者必須擁有發布權利,並符合全年齡社群規範。

04

SANDBOX CONTRACT

先確認遊戲能存取什麼

可使用
  • HTML / CSS / JavaScript / WebAssembly
  • 同一版本內的檔案、data: 與 blob: 資源
  • 腳本、Web Worker、指標鎖定、自動播放、全螢幕與遊戲手把
  • 透過 OpenGames SDK 橋接語言、帳號存檔與多人連線
禁止
  • 外部 API、任意伺服器、原生 TCP/UDP 與 Socket
  • 彈窗、表單、頂層導覽、瀏覽器外掛與 object 嵌入
  • 相機、麥克風、定位、付款、USB、序列埠與剪貼簿
  • OpenGames Cookie、Email、存取權杖與直接帳號資料
05

OPENGAMES SDK v1

一個橋接,不暴露帳號憑證

從平台來源載入 /opengames-sdk.js,並等待 ready()。SDK 只會在遊戲由 OpenGames 嵌入時運作;站外測試請先檢查 window.OpenGames,並提供離線行為。

方法輸入回傳用途
OpenGames.ready()—Promise<Capabilities>遊戲啟動前讀取登入、語言、存檔與多人功能。
OpenGames.on(type, callback)event name, callbackunsubscribe()監聽多人訊息或 Presence 人數事件。
saves.load(slot)slot?: string{ save: Save | null }載入一個帳號存檔槽。
saves.write(data, options)JSON data, { slot, version }{ save: Save }建立存檔,或檢查版本後更新。
saves.remove(slot)slot?: string{ deleted: true }刪除一個存檔槽。
multiplayer.list()—{ rooms: RoomSummary[] }列出這款遊戲最多 50 個公開房。
multiplayer.create(options)visibility, password?, mode, teamCount?{ room: Room }建立玩家房或創作者房,並自動連線。
multiplayer.join(code, password)6-character code, password?{ room: Room }以邀請碼加入房間並自動連線。
multiplayer.joinGlobal(mode)allowed mode{ room: Room }加入此遊戲設定的單一永久世界。
multiplayer.send(payload)JSON-compatible payload{ sent: true }向房內其他成員廣播遊戲自訂訊息。
multiplayer.leave()—{ left: true }離開目前房間並停止續租。
multiplayer.close()—{ closed: true }關閉目前房間,僅房主可用。

ready() 回傳的能力

{ account: { signedIn }, locale, region, cloudSaves: { enabled, maxSlots: 10, maxBytes: 65536 }, multiplayer: { enabled, maxPlayers, modes, roomPolicy, managedUnlimited, canManageRooms, voice: false } }
語言與概略地區
const platform = await OpenGames.ready();
const locale = platform.locale; // "zh-Hant", "en", "ja"…
const region = platform.region; // "TW", "JP", "US" or "XX"

loadTranslations(locale);
showRegionalNotice(region);
06

ACCOUNT SAVES

每次寫入都要帶版本

10每位玩家、每款遊戲的槽位
64 KiB每格 JSON 上限
1–32槽位字元:英數字、_ 與 -

玩家必須登入,創作者也要先在控制台啟用帳號存檔。資料必須可轉為 JSON。保存每次回傳的 version,下一次寫入時再送回;version 0 用於建立新槽位。

載入、寫入與處理衝突
const loaded = await OpenGames.saves.load("campaign");
let version = loaded.save?.version ?? 0;
let state = loaded.save?.data ?? { level: 1, coins: 0 };

try {
  const written = await OpenGames.saves.write(state, {
    slot: "campaign",
    version
  });
  version = written.save.version;
} catch (error) {
  if (error.message === "VERSION_CONFLICT") {
    // Reload and let the player choose which progress to keep.
  }
}
07

REALTIME MULTIPLAYER

房間負責傳送,遊戲定義規則

玩家必須登入。創作者要先在控制台啟用多人連線,設定允許模式、人數上限與房間政策。create、join 或 joinGlobal 成功後,SDK 會自動連到私人 Realtime 頻道。

shared

所有玩家共享同一份狀態。

co-op

玩家合作完成共同目標。

versus

玩家競賽;計分與權威狀態由遊戲決定。

teams

2–4 隊;成員分配由遊戲決定。

player玩家建立臨時邀請碼房間。
creator只有已驗證創作者可建立永久房。
global單一全遊戲永久世界;使用 joinGlobal()。
hybrid同時提供玩家房與創作者房。
建立、列出與加入房間
// Public co-op room
const created = await OpenGames.multiplayer.create({
  visibility: "public",
  mode: "co-op"
});
showInviteCode(created.room.room_code);

// Password-protected team room
await OpenGames.multiplayer.create({
  visibility: "password",
  password: playerEnteredPassword,
  mode: "teams",
  teamCount: 2
});

const { rooms } = await OpenGames.multiplayer.list();
await OpenGames.multiplayer.join(inviteCode, passwordOrNull);
訊息與 Presence
const stopMessages = OpenGames.on("multiplayer.message", ({ payload }) => {
  applyRemoteMessage(payload);
});

const stopPresence = OpenGames.on("multiplayer.presence", ({ playerCount }) => {
  updateLobbyCount(playerCount);
});

await OpenGames.multiplayer.send({
  type: "input",
  frame: 1024,
  buttons: ["jump"]
});

// Call the returned functions when your game no longer needs the listeners.
stopMessages();
stopPresence();
創作者房與全遊戲世界
// Only the verified creator can create a persistent creator room.
await OpenGames.multiplayer.create({
  creatorManaged: true,
  persistent: true,
  visibility: "public",
  mode: "shared"
});

// Available only when the dashboard policy is "One game-wide world".
await OpenGames.multiplayer.joinGlobal("shared");

房間限制

  • 密碼房需要 4–32 字元;平台只保存不可逆雜湊。
  • 控制台的玩家上限為 2–8 人;分組模式需要 2–4 隊。
  • 同一帳號在單一建房流程最多保留 5 個開啟房間;公開清單最多回傳 50 房。
  • 臨時房無活動 10 分鐘後關閉;SDK 會自動續租在線成員。

訊息限制

  • 訊息必須可轉為 JSON,序列化後最多 8 KiB。
  • 每個遊戲頁每秒最多傳送 30 次。
  • 訊息不會回送給發送者;需要時請立即更新本機狀態。
  • 不提供語音、持久聊天紀錄或權威遊戲伺服器。
OpenGames

隔離憑證、驗證房間成員,並處理邀請碼、私人頻道、Presence、密碼雜湊與傳輸限制。

你的遊戲

實作大廳、訊息格式、權威規則、分隊、操作驗證、狀態重同步、重連與離線備援。

08

ERROR CONTRACT

處理穩定的橋接錯誤

SDK Promise 失敗時會拋出 Error。只有下列代碼可作為穩定分支依據。供應商、資料庫、瀏覽器與網路文字可能變動;未知訊息一律視為 REQUEST_FAILED,並提供重試或離線遊玩。

FEATURE_DISABLED

創作者尚未啟用這項服務。

AUTH_REQUIRED

玩家必須先登入 OpenGames 帳號。

VERSION_CONFLICT

存檔已在別處更新;重新載入並讓玩家選擇保留版本。

MODE_NOT_ALLOWED

控制台未啟用所選多人模式。

PLAYER_ROOMS_DISABLED

房間政策不允許玩家自行開房。

CREATOR_ROOM_NOT_ALLOWED

呼叫者不是已驗證創作者,或政策不允許創作者房。

GLOBAL_WORLD_DISABLED

遊戲未設定全遊戲共用世界。

NOT_IN_ROOM

傳送或關房前必須先建立或加入房間。

MESSAGE_TOO_LARGE

序列化後的訊息超過 8 KiB。

RATE_LIMITED

遊戲頁在一秒內傳送超過 30 則訊息。

HOST_ONLY

只有房主可以關閉房間。

MULTIPLAYER_UNAVAILABLE

目前環境無法使用 Realtime。

SEND_FAILED / ROOM_REQUEST_FAILED

供應商或連線拒絕操作;請顯示重試或離線介面。

09

RELEASE CHECKLIST

檢查完整玩家流程

  1. 用 HTTP 伺服器開啟匯出資料夾,不要只用 file:// 測試。
  2. 測試鍵盤、滑鼠、觸控、手把、音效、全螢幕、所有場景與手機視窗。
  3. 修正所有 Console 錯誤、Network 缺檔、MIME 問題與大小寫不符。
  4. 測試未登入、已登入、存檔衝突、重連、房滿、密碼錯誤、房主離開與離線備援。
  5. 確認 ZIP 與多人訊息都不含密鑰、權杖、私人網址、個資或開發用檔案。
  6. 執行本機轉換檢查,從輸出內容重新建立 ZIP,上傳後再實際玩一次正式版本。