SDK для разработчиков

Как подключить нашу игру к платформе. Один скрипт даёт облачные сохранения, таблицы рекордов и достижения. Игроку не нужен отдельный вход: он один для всей платформы.

Подключение

Добавьте скрипт в index.html игры и дождитесь инициализации:

<script src="/sdk.js"></script>

const sdk = await GamePlatform.init();

sdk.player.authorized   // false — гость
sdk.player.name         // имя игрока
sdk.lang                // 'ru'

Игра работает в iframe, и каждый вызов SDK передаётся странице платформы через postMessage. Если открыть игру саму по себе, SDK перейдёт в автономный режим: игрок будет гостем, сохранения пойдут в localStorage, а таблицы рекордов будут недоступны. Это удобно при локальной разработке.

Игрок и сохранения

Сохранение — это произвольный JSON-объект размером до 200 КБ. Гостю оно сохраняется в браузере. Когда гость входит в аккаунт, сохранение переносится в облако, если там ещё пусто.

const save = await sdk.player.getData();          // весь объект
const { level } = await sdk.player.getData(['level']);

await sdk.player.setData({ level: 3, coins: 120 }); // запись откладывается на ~1,5 с и склеивается
await sdk.player.setData(data, true);              // true — записать сразу

// Числовая статистика (до 100 ключей)
await sdk.player.incrementStats({ wins: 1 });      // → { wins: 12, ... }
await sdk.player.setStats({ bestTime: 93 });
const stats = await sdk.player.getStats();

// Предложить войти (окно поверх игры, без перезагрузки)
const { authorized } = await sdk.auth.openDialog();
sdk.on('auth', ({ player }) => { /* игрок вошёл */ });

Таблицы рекордов

Таблицы описываются в манифесте игры (см. «Публикация»). В зачёт идёт лучший результат игрока. Записывать результаты могут только вошедшие игроки, а читать таблицы могут все.

await sdk.leaderboards.setScore('score', 4200, 'необязательная строка до 128 символов');

const { entries, userRank } = await sdk.leaderboards.getEntries('score', {
    top: 10,              // до 20
    includeUser: true,    // добавить игрока и соседей, если он не в топе
    around: 3,            // до 10
});
// entries[i] = { rank, score, formattedScore, extraData, player: { id, name, isMe } }

const me = await sdk.leaderboards.getPlayerEntry('score');

Достижения

Достижения тоже объявляются в манифесте. Платформа сама показывает уведомление и начисляет очки в общий рейтинг. Если гость получил достижение, оно выдаётся после входа.

await sdk.achievements.unlock('first_win');   // { new: true, achievement }
const list = await sdk.achievements.list();    // [{ key, title, unlocked, ... }]

Загрузка, пауза, реклама

sdk.game.ready();           // игра загрузилась — платформа убирает свой экран загрузки
sdk.game.gameplayStart();   // начался/закончился активный геймплей
sdk.game.gameplayStop();

sdk.on('pause', () => { /* выключить звук и остановить время */ });
sdk.on('resume', () => { /* продолжить */ });

const { rewarded } = await sdk.ads.showRewarded();   // выдать награду, если rewarded
await sdk.ads.showFullscreen();

Реклама пока не подключена. Ролик за вознаграждение заменяет короткая пауза, после которой награда выдаётся. Полноэкранная реклама не показывается совсем (shown: false). Когда монетизацию подключат, код игры менять не придётся.

Публикация

Каждая игра описывается манифестом в database/catalog/<slug>.json:

{
    "slug": "my-game",
    "title": "Моя игра",
    "tagline": "Короткое описание для карточки",
    "description": "Абзацы через пустую строку",
    "controls": "Прыжок — пробел\nСтрельба — ЛКМ",
    "genre": "arcade",
    "accent": "#12b886",
    "glyph": "🚀",
    "cover": "icons/icon-512.png",
    "orientation": "landscape",
    "source": "games/my-game/dist",
    "leaderboards": [{ "name": "score", "title": "Лучший счёт", "default": true }],
    "achievements": [{ "key": "first_win", "title": "Первая победа", "description": "…", "icon": "🏆", "points": 10 }]
}

Если игра не использует SDK и хранит прогресс в своём localStorage, перечислите эти ключи в поле "storage": ["my-game.save.v1"]. Платформа сама сохранит их в аккаунте игрока и восстановит перед запуском.

Сборка — это папка или zip-архив с index.html в корне. Все пути в ней должны быть относительными, кроме /sdk.js.

php artisan catalog:sync                              # манифесты + сборки
php artisan game:import my-game path/to/build.zip --prune   # выложить новую версию

Каждая сборка получает свою версию (хеш содержимого) и отдаётся по адресу /play/<slug>/<версия>/. Поэтому файлы кешируются навсегда, а игроки сразу получают новую версию.