关于 youtube-playables-js-sdk
youtube-playables-js-sdk 是用于将 YouTube Playables JavaScript SDK 集成到游戏中的技能,面向游戏开发者,说明初始化、存档数据、广告和分数提交流程。
主要功能
- 01等待 ytgame 全局对象
- 02按顺序调用游戏就绪接口
- 03读取和写入存档数据
- 04请求插屏与激励广告
- 05提交整数排行榜分数
适用场景
- 01将 YouTube Playables 集成到游戏
- 02持久化并更新玩家数据
- 03添加广告流程和分数提交
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ hungify/ playables-skills --skill youtube-playables-js-sdk安装后在 Claude Code 中输入/youtube-playables-js-sdk确认已加载。
详细介绍
YouTube Playables JavaScript SDK
安装
ytgame 全局对象由 YouTube 宿主注入,无需安装任何内容。轮询直到它出现,然后进行解析:
function waitForYtgame(timeoutMs = 10000) {
return new Promise((resolve, reject) => {
if (window.ytgame) {
resolve(window.ytgame);
return;
}
const deadline = Date.now() + timeoutMs;
const intervalId = setInterval(() => {
if (window.ytgame) {
clearInterval(intervalId);
resolve(window.ytgame);
} else if (Date.now() >= deadline) {
clearInterval(intervalId);
reject(new Error('ytgame SDK not available — running outside YouTube Playables?'));
}
}, 100);
});
}
初始化
顺序:等待 ytgame → 并行读取语言和加载已保存的数据 → 调用 firstFrameReady() → 完全可交互后调用 gameReady()。
let ytgame = null;
let platformLanguage = 'en';
let savedData = {};
waitForYtgame()
.then((sdk) => {
ytgame = sdk;
const getLanguagePromise = ytgame.system.getLanguage().then((language) => {
platformLanguage = language.length > 2 ? language.slice(0, 2) : language;
});
const getDataPromise = ytgame.game.loadData().then((data) => {
if (typeof data === 'string' && data !== '') {
try {
savedData = JSON.parse(data);
} catch (e) {
console.error('Failed to parse saved data, starting fresh', e);
savedData = {};
}
}
});
ytgame.system.onAudioEnabledChange((isEnabled) => {
// Mute or unmute the game audio based on isEnabled
});
ytgame.system.onPause(() => {
// Pause the game loop and audio
});
ytgame.system.onResume(() => {
// Resume the game loop and audio
});
return Promise.all([getLanguagePromise, getDataPromise]);
})
.then(() => {
ytgame.game.firstFrameReady();
})
.catch((err) => {
console.error('YouTube Playables SDK initialization failed', err);
// Fall back to a non-Playables code path if needed
});
游戏完全可交互时:
function notifyGameReady() {
ytgame.game.gameReady();
}
存储(已保存的数据)
每位玩家的已保存数据是一个可序列化为 JSON 的单一数据块。始终先读取,再合并,最后写入,以免覆盖无关的键。写入后,重新读取以确认数据已持久化。
// Read one or many keys from saved data
function getDataFromStorage(key, tryParseJson) {
return ytgame.game.loadData().then((data) => {
if (typeof data === 'string' && data !== '') {
try {
savedData = JSON.parse(data);
} catch (e) {
console.error('loadData parse error', e);
}
}
const readOne = (k) => {
let value = typeof savedData[k] === 'undefined' ? null : savedData[k];
if (typeof value === 'string' && tryParseJson) {
try {
value = JSON.parse(value);
} catch (e) {
/* keep as-is */
}
}
return value;
};
return Array.isArray(key) ? key.map(readOne) : readOne(key);
});
}
// Write one or many keys, then verify by reloading
function setDataToStorage(key, value) {
const data = savedData !== null ? { ...savedData } : {};
if (Array.isArray(key)) {
for (let i = 0; i < key.length; i++) data[key[i]] = value[i];
} else {
data[key] = value;
}
return ytgame.game
.saveData(JSON.stringify(data))
.then(() => {
savedData = data;
return ytgame.game.loadData();
})
.then((persisted) => {
if (persisted !== JSON.stringify(data)) {
console.warn(
'saveData verification mismatch — persisted value differs from written value'
);
}
})
.catch((err) => {
console.error('saveData failed', err);
});
}
// Delete one or many keys
function deleteDataFromStorage(key) {
const data = savedData !== null ? { ...savedData } : {};
if (Array.isArray(key)) {
for (const k of key) delete data[k];
} else {
delete data[key];
}
return ytgame.game
.saveData(JSON.stringify(data))
.then(() => {
savedData = data;
})
.catch((err) => {
console.error('deleteData (saveData) failed', err);
});
}
广告
插页式广告
ytgame.ads.requestInterstitialAd() 会在广告流程结束时完成解析。请求前暂停;解析或拒绝后恢复。
function showInterstitial() {
// Pause game and mute audio before requesting
ytgame.ads
.requestInterstitialAd()
.then(() => {
// Resume game and unmute audio
})
.catch(() => {
// Ad failed to deliver — resume game and continue
});
}
激励广告
ytgame.ads.requestRewardedAd(placement) 会解析为布尔值。只有解析结果为真值时才发放奖励。
function showRewarded(placement) {
// Pause game and mute audio before requesting
ytgame.ads
.requestRewardedAd(placement)
.then((isRewardEarned) => {
if (isRewardEarned) {
// Grant reward to the player
}
// Resume game and unmute audio
})
.catch(() => {
// Ad failed to deliver — resume game and continue
});
}
排行榜
通过 ytgame.engagement.sendScore({ value }) 提交整数分数。发送前将字符串转换为整数。
function submitScore(score) {
const value = typeof score === 'string' ? parseInt(score, 10) : score;
return ytgame.engagement.sendScore({ value });
}
评论
支持 Markdown