mcpField
Y
youtube-playables-js-sdk

youtube-playables-js-sdk

github.com/hungify开发016 次安装1 周前更新
代码仓库

关于 youtube-playables-js-sdk

youtube-playables-js-sdk 是用于将 YouTube Playables JavaScript SDK 集成到游戏中的技能,面向游戏开发者,说明初始化、存档数据、广告和分数提交流程。

主要功能

  1. 01等待 ytgame 全局对象
  2. 02按顺序调用游戏就绪接口
  3. 03读取和写入存档数据
  4. 04请求插屏与激励广告
  5. 05提交整数排行榜分数

适用场景

  1. 01将 YouTube Playables 集成到游戏
  2. 02持久化并更新玩家数据
  3. 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