|
@@ -0,0 +1,183 @@
|
|
|
|
|
+# Game SDK
|
|
|
|
|
+
|
|
|
|
|
+平台在加载游戏前会自动向页面注入 `window.GameSDK`,游戏里直接调用即可,无需任何初始化。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 安装
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm install git+https://gitee.com/personal-site-micro/game-sdk.git
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+安装后 TypeScript 自动识别 `GameSDK` 全局类型,无需手动 import。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## API
|
|
|
|
|
+
|
|
|
|
|
+```ts
|
|
|
|
|
+GameSDK.gameId // string — 当前游戏的 id
|
|
|
|
|
+GameSDK.getPlayerName() // string — 当前玩家昵称(来自平台 localStorage)
|
|
|
|
|
+GameSDK.submit(score: number) // Promise — 提交分数
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`submit` 返回值:
|
|
|
|
|
+
|
|
|
|
|
+```ts
|
|
|
|
|
+{ ok: true; rank: number } // 成功,rank 为当前排名
|
|
|
|
|
+{ ok: false; error: string } // 失败
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 开发一个游戏
|
|
|
|
|
+
|
|
|
|
|
+### 1. 初始化项目
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+mkdir my-game && cd my-game
|
|
|
|
|
+npm init -y
|
|
|
|
|
+npm install git+https://gitee.com/personal-site-micro/game-sdk.git
|
|
|
|
|
+npm install --save-dev esbuild
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+在 `package.json` 加 build 脚本:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+"scripts": {
|
|
|
|
|
+ "build": "esbuild src/game.js --bundle --outfile=bundle.js --platform=browser --format=iife"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. 编写游戏
|
|
|
|
|
+
|
|
|
|
|
+游戏入口为 `src/game.js`(或 `.ts`)。平台会把它注入到页面里,游戏需要自己挂载到 `#game-container`:
|
|
|
|
|
+
|
|
|
|
|
+```js
|
|
|
|
|
+;(function () {
|
|
|
|
|
+ const container = document.getElementById('game-container')
|
|
|
|
|
+ if (!container) return
|
|
|
|
|
+
|
|
|
|
|
+ const canvas = document.createElement('canvas')
|
|
|
|
|
+ canvas.style.cssText = 'width:100%;height:100%;display:block;'
|
|
|
|
|
+ container.appendChild(canvas)
|
|
|
|
|
+
|
|
|
|
|
+ // ... 游戏逻辑 ...
|
|
|
|
|
+
|
|
|
|
|
+ // 游戏结束时提交分数
|
|
|
|
|
+ async function gameOver(score) {
|
|
|
|
|
+ const result = await GameSDK.submit(score)
|
|
|
|
|
+ if (result.ok) {
|
|
|
|
|
+ console.log('第', result.rank, '名')
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+})()
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> **注意**:整个游戏逻辑必须包在 IIFE(立即执行函数)里,避免污染全局作用域。
|
|
|
|
|
+
|
|
|
|
|
+### 3. 本地预览
|
|
|
|
|
+
|
|
|
|
|
+写一个 `index.html`,stub 掉 GameSDK,方便离线调试:
|
|
|
|
|
+
|
|
|
|
|
+```html
|
|
|
|
|
+<!DOCTYPE html>
|
|
|
|
|
+<html>
|
|
|
|
|
+<head>
|
|
|
|
|
+ <style>
|
|
|
|
|
+ * { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
|
+ html, body { width: 100%; height: 100%; background: #0a0a0a; }
|
|
|
|
|
+ #game-container { width: 100%; height: 100%; }
|
|
|
|
|
+ </style>
|
|
|
|
|
+</head>
|
|
|
|
|
+<body>
|
|
|
|
|
+ <div id="game-container"></div>
|
|
|
|
|
+ <script>
|
|
|
|
|
+ window.GameSDK = {
|
|
|
|
|
+ gameId: 'my-game',
|
|
|
|
|
+ getPlayerName: () => 'dev',
|
|
|
|
|
+ submit: async (score) => {
|
|
|
|
|
+ console.log('submit score:', score)
|
|
|
|
|
+ return { ok: true, rank: 1 }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ </script>
|
|
|
|
|
+ <script src="bundle.js"></script>
|
|
|
|
|
+</body>
|
|
|
|
|
+</html>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+然后打包并用任意静态服务器预览:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm run build
|
|
|
|
|
+npx serve .
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4. 打包
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+npm run build
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+产物为根目录下的 `bundle.js`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 上传到平台
|
|
|
|
|
+
|
|
|
|
|
+### 上传游戏 bundle
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -X POST https://loganz2.cn/api/games/bundle \
|
|
|
|
|
+ -H "x-game-id: my-game" \
|
|
|
|
|
+ -H "x-game-name: 我的游戏" \
|
|
|
|
|
+ -H "x-game-description: 游戏描述" \
|
|
|
|
|
+ -H "x-game-controls: 方向键移动" \
|
|
|
|
|
+ -H "content-type: application/javascript" \
|
|
|
|
|
+ --data-binary "@bundle.js"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+| Header | 说明 |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| `x-game-id` | 游戏唯一 id,只允许字母、数字、`_`、`-` |
|
|
|
|
|
+| `x-game-name` | 显示名称(需 URL encode) |
|
|
|
|
|
+| `x-game-description` | 简短描述(可选,需 URL encode) |
|
|
|
|
|
+| `x-game-controls` | 操作说明(可选,需 URL encode) |
|
|
|
|
|
+
|
|
|
|
|
+上传成功后游戏立即可用,访问 `https://loganz2.cn/games/<id>` 即可游玩。
|
|
|
|
|
+
|
|
|
|
|
+### 上传静态资源(可选)
|
|
|
|
|
+
|
|
|
|
|
+如果游戏需要图片、音频等资源:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -X POST https://loganz2.cn/api/games/asset \
|
|
|
|
|
+ -H "x-game-id: my-game" \
|
|
|
|
|
+ -H "x-filename: player.png" \
|
|
|
|
|
+ --data-binary "@player.png"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+资源上传后可通过以下路径访问:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+/api/games/<id>/assets/<filename>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+在游戏代码里直接用绝对路径加载:
|
|
|
|
|
+
|
|
|
|
|
+```js
|
|
|
|
|
+const img = new Image()
|
|
|
|
|
+img.src = '/api/games/my-game/assets/player.png'
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 更新游戏
|
|
|
|
|
+
|
|
|
|
|
+重新上传 bundle 即可,同一个 id 会直接覆盖。
|
|
|
|
|
+
|
|
|
|
|
+### 删除游戏
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -X DELETE https://loganz2.cn/api/games/my-game
|
|
|
|
|
+```
|