关于 crazy-games-js-sdk
这是一份面向游戏开发者的 CrazyGames JavaScript SDK 集成技能,涵盖初始化、游戏生命周期钩子、广告、玩家访问、存储及可选的 Xsolla 支付。
主要功能
- 01SDK 加载与初始化指南
- 02游戏和加载生命周期钩子
- 03插屏广告与激励广告流程
- 04玩家授权和资料访问
- 05键值存储接入
- 06可选的 Xsolla 支付流程
适用场景
- 01在游戏中接入 CrazyGames SDK
- 02将游戏状态映射到生命周期调用
- 03展示插屏广告或激励广告
- 04使用 SDK 存储玩家数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hungify/ playables-skills --skill crazy-games-js-sdk安装后在 Claude Code 中输入/crazy-games-js-sdk确认已加载。
详细介绍
CrazyGames JavaScript SDK
集成清单
将 SDK 集成到游戏时,请按以下顺序操作:
- 加载 SDK — 在游戏启动前添加 CDN
<script>标签 - 初始化 — 调用
SDK.init(),并等待其完成后再使用任何 SDK 模块 - 生命周期钩子 — 在整个游戏循环中接入
loadingStart/Stop和gameplayStart/Stop - 广告 — 在合适的间歇点添加插屏广告和/或激励广告调用
- 可选:身份验证与存储 — 根据需要添加登录和持久化键值存储
- 可选:支付 — 集成 Xsolla Pay Station(单独事项;不适用时可跳过)
安装
在启动游戏前,从官方 CDN 加载 SDK。
<script src="https://sdk.crazygames.com/crazygames-sdk-v3.js"></script>
如果动态加载,请等待 window.CrazyGames.SDK.init 定义后再调用。如果脚本被拦截(例如,被 CSP 拦截),全局变量 window.CrazyGames 将未定义 — 请将 sdk.crazygames.com 添加到 script-src 指令中。
初始化
调用一次 SDK.init()。SDK 就绪后,该调用会完成。只有在完成后,才能安全地使用 SDK.user、SDK.data、SDK.ad、SDK.banner、SDK.game 和 SDK.analytics。
async function initCrazyGames() {
if (!window.CrazyGames?.SDK) {
throw new Error('CrazyGames SDK script not loaded');
}
const sdk = window.CrazyGames.SDK;
try {
await sdk.init();
} catch (err) {
throw new Error(`CrazyGames SDK init failed: ${err.message}`);
}
const isUserAccountAvailable = sdk.user.isUserAccountAvailable;
if (isUserAccountAvailable) {
const language = sdk.user.systemInfo.countryCode.toLowerCase();
const deviceType = sdk.user.systemInfo.device.type.toLowerCase(); // 'desktop' | 'mobile' | 'tablet'
console.log('lang/device', language, deviceType);
}
return sdk;
}
验证
调用 initCrazyGames() 后,请先确认 SDK 正常工作,再继续操作:
- 控制台检查 — 不应出现
CrazyGames SDK init failed错误;调用sdk.user.isUserAccountAvailable应返回布尔值,且不抛出异常。 - 生命周期钩子 — 打开游戏对应的 CrazyGames 沙盒 URL,并确认
loadingStart/loadingStop/gameplayStart/gameplayStop调用出现在 CrazyGames 开发者仪表板的事件日志中。 - 广告回调 — 使用 CrazyGames 沙盒环境(在 URL 后附加
?crazygames_sandbox=1)触发测试广告,并确认adStarted和adFinished正常触发。 - 广告拦截检测 — 在启用广告拦截器的情况下运行时调用
sdk.ad.hasAdblock(),并确认其结果为true。
玩家/授权
使用 showAuthPrompt() 提示玩家登录,然后使用 getUser() 读取个人资料数据;还可以使用 getUserToken() 获取已签名的 JWT,以便在后端验证。
async function authorizePlayer(sdk, { useUserToken = false } = {}) {
if (!sdk.user.isUserAccountAvailable) {
// Guest session — no auth possible on this domain
return null;
}
await sdk.user.showAuthPrompt();
const user = await sdk.user.getUser();
if (!user) {
return null;
}
const profile = {
name: user.username || null,
photo: user.profilePictureUrl || null,
extra: user
};
if (useUserToken) {
profile.extra.jwt = await sdk.user.getUserToken();
}
return profile;
}
存储
CrazyGames 通过 SDK.data 提供同步键值存储。值均为字符串;请自行序列化 JSON。
function storageSet(sdk, key, value) {
const data = typeof value === 'string' ? value : JSON.stringify(value);
sdk.data.setItem(key, data);
}
function storageGet(sdk, key, tryParseJson = true) {
const raw = sdk.data.getItem(key);
if (!tryParseJson || raw == null) {
return raw;
}
try {
return JSON.parse(raw);
} catch (_) {
return raw;
}
}
function storageRemove(sdk, key) {
sdk.data.removeItem(key);
}
// Batch helpers — just iterate, the SDK has no native multi-key API
function storageSetMany(sdk, keys, values) {
for (let i = 0; i < keys.length; i++) {
storageSet(sdk, keys[i], values[i]);
}
}
广告
插屏广告(midgame)
调用 SDK.ad.requestAd('midgame', callbacks)。广告生命周期推进时,会同步触发回调。
function showInterstitial(sdk) {
sdk.ad.requestAd('midgame', {
adStarted: () => {
// Mute audio and pause the game here
},
adFinished: () => {
// Resume audio and gameplay here
},
adError: (error) => {
console.warn('interstitial failed', error);
}
});
}
激励广告
使用相同的 API,将 'rewarded' 作为类型传入。adFinished 表示用户已完整观看广告,应向其发放奖励。
function showRewarded(sdk, onReward) {
sdk.ad.requestAd('rewarded', {
adStarted: () => {
// Pause the game
},
adFinished: () => {
onReward();
},
adError: (error) => {
console.warn('rewarded failed', error);
}
});
}
广告拦截检测
async function isAdblockActive(sdk) {
return sdk.ad.hasAdblock();
}
自适应横幅广告
横幅广告会绑定到具有指定 id 的现有 DOM 容器。CrazyGames 会在容器中渲染广告,并选择合适的尺寸。
async function showBanner(sdk, containerId) {
// The container must already be in the DOM and visible
try {
await sdk.banner.requestResponsiveBanner([containerId]);
} catch (e) {
console.warn('banner failed', e);
}
}
async function showAdvancedBanners(sdk, containerIds) {
// Request several banners in parallel
await Promise.all(containerIds.map((id) => sdk.banner.requestResponsiveBanner(id)));
}
function hideBanners(sdk) {
sdk.banner.clearAllBanners();
}
生命周期/游戏事件
CrazyGames 要求宿主游戏在正确的时机调用游戏和加载钩子 — 这些钩子会影响广告投放节奏、游戏内 UI 遮罩效果和分析数据。
请按以下方式将通用游戏生命周期事件映射到 SDK 调用:
| 游戏事件 | SDK 调用 |
|---|---|
level_started、level_resumed、gameplay_started | sdk.game.gameplayStart() |
level_paused、level_completed、level_failed、gameplay_stopped | sdk.game.gameplayStop() |
in_game_loading_started | sdk.game.loadingStart() |
in_game_loading_stopped | sdk.game.loadingStop() |
player_got_achievement | sdk.game.happytime() |
CrazyGames SDK 没有单独的 audio / pause / visibility 回调 — 请通过广告回调(adStarted / adFinished)和标准的 document.visibilitychange 事件控制音频和暂停状态。
支付(可选,通过 Xsolla Pay Station)
如果你没有 Xsolla 项目 ID,请完全跳过本节。 CrazyGames 本身不销售 IAP;此集成会将 CrazyGames 签发的 Xsolla 用户令牌与 Xsolla Pay Station 小组件和 Xsolla Store API 搭配使用。
关键常量:
const XSOLLA_PAYSTATION_EMBED_URL =
'https://cdn.xsolla.net/payments-bucket-prod/embed/1.5.0/widget.min.js';
const XSOLLA_SDK_URL = 'https://store.xsolla.com/api/v2/project';
通过 sdk.user.getXsollaUserToken() 获取 Xsolla 用户令牌。将其用作所有 Xsolla Store API 请求的 Bearer 令牌(目录、购买、库存、消耗)。
目录 — GET /{projectId}/items?limit=50
购买流程:
POST /{projectId}/payment/item/{sku}→ 返回{ token, order_id }- 如果尚未加载
XSOLLA_PAYSTATION_EMBED_URL,则动态加载 - 调用
XPayStationWidget.init({ access_token: token, sandbox: isSandbox }),然后调用.open() - 监听
XPayStationWidget.eventTypes.STATUS;当paymentInfo.status匹配/done|charged|success/i时,获取GET /{projectId}/order/{orderId},并调用sdk.analytics.trackOrder('xsolla', order)记录购买 - 监听
'close'事件以处理取消操作
库存 — GET /{projectId}/user/inventory/items
消耗 — 使用 { sku, quantity } 调用 POST /{projectId}/user/inventory/item/consume
所有 fetch 调用都必须包含 Authorization: Bearer <xsollaToken>。非 OK 响应时抛出错误。开发期间使用 isSandbox: true。