|
|
3 天之前 | |
|---|---|---|
| README.md | 3 天之前 | |
| cli.js | 3 天之前 | |
| game-sdk.d.ts | 3 天之前 | |
| game-sdk.js | 3 天之前 | |
| package.json | 3 天之前 |
这个包同时提供两部分能力:
GameSDK 类型定义。game-sdk publish、game-sdk asset、game-sdk delete。目标用法很简单:
GameSDK。package.json 里写 npm run build 和 npm run publish。npm run publish 发布到正式平台。这个 SDK 只面向正式平台发布,不支持本地部署平台服务。
如果当前还没发到 npm,直接用 git 安装:
npm install git+https://gitee.com/personal-site-micro/game-sdk.git
再安装打包工具,例如:
npm install --save-dev esbuild
package.json:
{
"scripts": {
"build": "esbuild src/game.js --bundle --outfile=bundle.js --platform=browser --format=iife",
"publish": "npm run build && game-sdk publish"
}
}
在项目根目录创建 game-sdk.config.json:
{
"game-id": "my-game",
"name": "我的游戏",
"bundle": "./bundle.js",
"description": "游戏描述",
"controls": "方向键移动"
}
src/game.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)
const ctx = canvas.getContext('2d')
let width = 0
let height = 0
let score = 0
let submitted = false
let startedAt = 0
let ended = false
function resize() {
const rect = container.getBoundingClientRect()
width = rect.width
height = rect.height
if (width <= 0 || height <= 0) return false
const dpr = window.devicePixelRatio || 1
canvas.width = width * dpr
canvas.height = height * dpr
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.scale(dpr, dpr)
return true
}
async function endGame() {
if (submitted) return
submitted = true
ended = true
const result = await GameSDK.submit(score)
if (result.ok) {
console.log('当前排名:', result.rank)
} else {
console.error('提交失败:', result.error)
}
}
function update(now) {
if (ended) return
const elapsed = now - startedAt
score = Math.floor(elapsed / 1000)
if (elapsed >= 30000) {
endGame()
}
}
function render() {
ctx.fillStyle = '#111'
ctx.fillRect(0, 0, width, height)
ctx.fillStyle = '#fff'
ctx.font = '24px sans-serif'
ctx.fillText(`score: ${score}`, 20, 40)
}
function loop(now) {
update(now)
render()
requestAnimationFrame(loop)
}
function boot() {
if (!resize()) {
requestAnimationFrame(boot)
return
}
startedAt = performance.now()
requestAnimationFrame(loop)
}
window.addEventListener('resize', resize)
boot()
})()
npm run publish
发布成功后,游戏地址为:
https://loganz2.cn/games/<game-id>
GameSDK平台会在加载你的 bundle 前自动注入全局变量:
GameSDK.gameId
GameSDK.getPlayerName()
GameSDK.submit(score)
类型:
type GameSDKSubmitResult =
| { ok: true; rank: number }
| { ok: false; error: string }
说明:
gameId 是当前游戏 id。getPlayerName() 返回玩家昵称。submit(score) 提交一局游戏的最终分数。game-sdk 命令这是发布命令,不是浏览器 API。
它负责:
bundle.js常用命令:
game-sdk publish
game-sdk asset --file ./player.png
game-sdk delete --game-id my-game
如果命令参数没有写全,CLI 会继续从这些位置读取配置:
game-sdk.config.jsongame.config.jsonpackage.json 里的 gameSdk这些规则必须满足,否则很容易出现空白页、无法开始、尺寸错误、重复提交分数等问题。
#game-container平台页面只提供这个容器:
<div id="game-container"></div>
你的游戏必须自己把 Canvas、DOM、WebGL 内容挂到这里。
;(function () {
// game code
})()
这样可以避免污染全局作用域。
平台页面由 React 渲染,容器虽然存在,但你的 bundle 执行时它的尺寸可能还没稳定。
所以:
resize。0 宽高时要等待下一帧重试。推荐模式:
function resize() {
const rect = container.getBoundingClientRect()
const width = rect.width
const height = rect.height
const dpr = window.devicePixelRatio || 1
if (width <= 0 || height <= 0) return false
canvas.width = width * dpr
canvas.height = height * dpr
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.scale(dpr, dpr)
return true
}
平台不会替你判断一局是否结束。
你必须自己定义,例如:
结束时应该:
GameSDK.submit(finalScore)submit 只在一局结束时调用一次不要这样用:
推荐加保护:
let submitted = false
async function endGame(score) {
if (submitted) return
submitted = true
await GameSDK.submit(score)
}
资源上传后,运行时请用:
/api/games/<game-id>/assets/<filename>
例如:
const img = new Image()
img.src = '/api/games/my-game/assets/player.png'
不要依赖本地相对路径结构。
如果配置文件已经写好,直接:
game-sdk publish
也可以显式传参:
game-sdk publish \
--game-id my-game \
--name "我的游戏" \
--bundle ./bundle.js \
--description "游戏描述" \
--controls "方向键移动"
参数:
--game-id:必填。只允许字母、数字、_、-。--name:必填。平台展示名称。--bundle:必填。bundle 文件路径。--description:可选。简短描述。--controls:可选。操作说明。game-sdk asset --game-id my-game --file ./player.png
或者:
game-sdk asset --file ./player.png
上面这个简写成立的前提是 game-id 已经写进配置文件。
如果你想指定平台上的文件名:
game-sdk asset \
--game-id my-game \
--file ./assets/player-v2.png \
--name player.png
game-sdk delete --game-id my-game
本地只能 stub window.GameSDK 来调试游戏逻辑,不代表本地部署平台。
index.html:
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
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: function () { return 'dev' },
submit: async function (score) {
console.log('submit score:', score)
return { ok: true, rank: 1 }
}
}
</script>
<script src="./bundle.js"></script>
</body>
</html>
预览:
npm run build
npx serve .
优先检查:
#game-container0 尺寸后就再也没重试通常是因为:
GameSDK.submitsubmitted 保护通常是因为:
/api/games/<id>/assets/<filename>这个 SDK 故意保持很薄。
平台只关心三件事:
#game-container 里正确运行其余渲染、输入、状态机、资源管理,都由游戏自己决定。