mcpField
G
game-distribution-js-sdk

game-distribution-js-sdk

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

关于 game-distribution-js-sdk

面向浏览器游戏的 JavaScript SDK 技能,介绍如何接入 GameDistribution 广告与生命周期事件。内容侧重初始化、广告流程及暂停和音频处理,不涉及玩家或社交服务。

主要功能

  1. 01SDK 初始化与就绪事件
  2. 02插屏、激励和展示广告
  3. 03广告 Promise 生命周期处理
  4. 04暂停与恢复事件处理
  5. 05浏览器可见性处理

适用场景

  1. 01为浏览器游戏接入广告
  2. 02在广告完成后发放奖励
  3. 03广告期间暂停游戏和音频

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hungify/playables-skills --skill game-distribution-js-sdk

安装后在 Claude Code 中输入/game-distribution-js-sdk确认已加载。

详细介绍

GameDistribution JavaScript SDK

概述

GameDistribution 提供单一的浏览器 SDK(window.gdsdk),通过全局 window.GD_OPTIONS 对象进行配置。SDK 会加载,并通过单个 onEvent 回调触发生命周期事件,同时提供返回 Promise 的方法来预加载和展示广告。原生 SDK 支持:

  • 使用 gameId 和单个 onEvent 回调进行初始化
  • 插屏广告(gdsdk.showAd())
  • 激励广告(gdsdk.preloadAd('rewarded') + gdsdk.showAd('rewarded'))
  • 展示横幅广告(gdsdk.showAd('display', { containerId }))
  • 通过 SDK_GAME_PAUSE / SDK_GAME_START 事件发送生命周期暂停/恢复信号

不提供玩家身份验证、存储、支付、排行榜或社交 API。也应避免在此平台上进行外部链接导航。

安装

在定义 window.GD_OPTIONS 后,将 SDK 脚本添加到页面中。脚本 URL 固定:

const SDK_URL = 'https://html5.api.gamedistribution.com/main.min.js';

function loadScript(src) {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
    });
}

SDK_READY 事件触发后,SDK 会通过 window.gdsdk 提供。

初始化

必须在添加 SDK 脚本之前,通过赋值配置 GameDistribution 的 window.GD_OPTIONS。唯一必填字段是 gameId,即你的 GameDistribution 游戏 GUID。所有生命周期事件和广告事件都会通过单个 onEvent(event) 回调传递。

const options = {
    gameId: 'YOUR_GAME_ID'
};

let platformSdk = null;
let isInitialized = false;
let currentAdvertisementIsRewarded = false;

const listeners = {
    interstitialStateChanged: [],
    rewardedStateChanged: [],
    bannerStateChanged: [],
    pauseStateChanged: [],
    audioStateChanged: []
};

function emit(name, payload) {
    listeners[name].forEach((cb) => cb(payload));
}

function initialize() {
    return new Promise((resolve, reject) => {
        if (isInitialized) {
            resolve();
            return;
        }

        if (typeof options.gameId !== 'string') {
            reject(new Error('Game params are not found'));
            return;
        }

        window.GD_OPTIONS = {
            gameId: options.gameId,
            onEvent(event) {
                switch (event.name) {
                    case 'SDK_READY':
                        platformSdk = window.gdsdk;
                        isInitialized = true;

                        // Optional: show an interstitial immediately once the SDK is ready
                        showInterstitial();
                        resolve();
                        break;
                    case 'SDK_GAME_START':
                        // Ad finished — game should resume
                        if (currentAdvertisementIsRewarded) {
                            emit('rewardedStateChanged', 'closed');
                            // Preload the next rewarded ad right away
                            platformSdk.preloadAd('rewarded');
                        } else {
                            emit('interstitialStateChanged', 'closed');
                        }
                        emit('pauseStateChanged', false);
                        emit('audioStateChanged', true);
                        break;
                    case 'SDK_GAME_PAUSE':
                        // Ad started — game should pause
                        if (currentAdvertisementIsRewarded) {
                            emit('rewardedStateChanged', 'opened');
                        } else {
                            emit('interstitialStateChanged', 'opened');
                        }
                        emit('pauseStateChanged', true);
                        emit('audioStateChanged', false);
                        break;
                    case 'SDK_REWARDED_WATCH_COMPLETE':
                        // Reward must be granted here
                        emit('rewardedStateChanged', 'rewarded');
                        break;
                    case 'SDK_GDPR_TRACKING':
                    case 'SDK_GDPR_TARGETING':
                    default:
                        break;
                }
            }
        };

        loadScript(SDK_URL).catch(reject);
    });
}

SDK 通过 onEvent 发出的重要事件名称:

  • SDK_READY — SDK 已就绪,window.gdsdk 可用。
  • SDK_GAME_PAUSE — 广告即将开始;暂停游戏并静音。
  • SDK_GAME_START — 广告已结束(或未展示广告);恢复游戏并取消静音。
  • SDK_REWARDED_WATCH_COMPLETE — 用户已看完激励广告;发放奖励。
  • SDK_GDPR_TRACKING、SDK_GDPR_TARGETING — GDPR 同意信号(通常无需操作)。

广告

GameDistribution 支持插屏广告、激励广告和展示横幅广告。gdsdk 上的所有广告方法都会返回 Promise,并在无法投放广告时拒绝。

你必须记住当前正在播放的广告类型(插屏广告还是激励广告),以便将共享的 SDK_GAME_PAUSE / SDK_GAME_START 事件分派到正确的状态。

插屏广告
function showInterstitial() {
    currentAdvertisementIsRewarded = false;

    if (!platformSdk) {
        emit('interstitialStateChanged', 'failed');
        return;
    }

    platformSdk.showAd().catch(() => {
        emit('interstitialStateChanged', 'failed');
    });
}

GameDistribution 不会在 SDK 层面限制插屏广告之间的最短间隔,因此可在游戏逻辑需要时调用 showAd()。

激励广告

激励广告必须先预加载才能展示。每次激励广告结束后(SDK_GAME_START),都要预加载下一条广告。

function preloadRewarded() {
    if (platformSdk) {
        platformSdk.preloadAd('rewarded');
    }
}

function showRewarded() {
    currentAdvertisementIsRewarded = true;

    if (!platformSdk) {
        emit('rewardedStateChanged', 'failed');
        return;
    }

    platformSdk.showAd('rewarded').catch(() => {
        emit('rewardedStateChanged', 'failed');
    });
}
横幅广告

展示横幅广告会将其渲染到 DOM 容器中,容器 ID 通过 gdsdk.showAd('display', { containerId }) 传入。以下示例使用固定 ID 'banner-container'。

const BANNER_CONTAINER_ID = 'banner-container';

function createBannerContainer(position) {
    const container = document.createElement('div');
    container.id = BANNER_CONTAINER_ID;
    container.style.position = 'fixed';
    container.style.left = '0';
    container.style.right = '0';
    container.style.zIndex = '9999';

    if (position === 'top') {
        container.style.top = '0';
    } else {
        container.style.bottom = '0';
    }

    document.body.appendChild(container);
    return container;
}

function showBanner(position) {
    let container = document.getElementById(BANNER_CONTAINER_ID);
    if (!container) {
        container = createBannerContainer(position);
    }

    container.style.display = 'block';

    platformSdk
        .showAd('display', { containerId: BANNER_CONTAINER_ID })
        .then(() => {
            emit('bannerStateChanged', 'shown');
        })
        .catch(() => {
            emit('bannerStateChanged', 'failed');
            container.style.display = 'none';
        });
}

function hideBanner() {
    const container = document.getElementById(BANNER_CONTAINER_ID);
    if (container) {
        container.style.display = 'none';
    }

    emit('bannerStateChanged', 'hidden');
}

position 接受 'top' 或 'bottom'。隐藏横幅广告只会切换容器的可见性,不会销毁广告位。

生命周期 / 音频 / 暂停

GameDistribution 通过 SDK_GAME_PAUSE 和 SDK_GAME_START 事件控制游戏暂停/恢复,这两个事件会包围每一次广告展示。它没有单独的可见性或音频 API,因此需要根据这些事件处理:

  • 收到 SDK_GAME_PAUSE 时:暂停游戏,并静音或降低音量。
  • 收到 SDK_GAME_START 时:恢复游戏并还原音频。如果没有投放广告,此事件也会在 SDK_READY 后触发一次。

结合标准的浏览器可见性事件处理标签页切换,因为 GameDistribution 本身不会提供这些事件:

document.addEventListener('visibilitychange', () => {
    const isHidden = document.visibilityState === 'hidden';
    emit('pauseStateChanged', isHidden);
    emit('audioStateChanged', !isHidden);
});

window.addEventListener('blur', () => {
    emit('pauseStateChanged', true);
    emit('audioStateChanged', false);
});

window.addEventListener('focus', () => {
    emit('pauseStateChanged', false);
    emit('audioStateChanged', true);
});

存储

GameDistribution 不提供平台存储 API。请直接使用 window.localStorage 持久化玩家进度。

评论

支持 Markdown