Перейти к основному содержимому

Энергия

Вы можете настраивать автоматические переменные, которые будут начисляться согласно серверному времени, которым можно установить верхний и нижний пределы.

Примеры:

Настройка

Концепция энергии заключается в задании максимального и минимального значения поля игрока, а так же интервала автоматического добавления значения переменной.

Подробнее о настройке полей игрока:

Подробнее о работе с API состояния игрока.

Энергия / Жизни

Для реализации жизней нужно завести поле игрока energy в разделе Игроки в панели управления проектом как показано на скриншоте:

В этом примере Энергия:

  • Доступна в интервале от 0 до 100 (Ограничивать диапазоном);
  • При первом входе полная (Значение по умолчанию);
  • Каждые 60 секунд добавляется 1 единица энергии (Автоначисляемая переменная);
  • Можно установить выше 100 вручную.

Проверка энергии при запуске уровня

function onClickButtonStartLevel() {
// Энергии не достаточно
if (gp.player.get('energy') <= 0) {
// Показываем модальное окно "Не хватает энергии"
showNotEnoughEnergyModal();
return;
}

// Вычитаем 1 единицу энергии
gp.player.add('energy', -1);
// Сохраняем отметку, чтобы при перезагрузке вычтенная энергия сохранилась
gp.player.sync();
// Запускаем уровень
startLevel();
}

Бонусная энергия

Начислить какое-то количество единиц энергии вручную бонусом, например, при использовании предмета / разблокировании достижения / покупке. Если в переменной можно установить значение выше максимального, то в примере ниже добавится 10 энергии, даже если энергия полная.

// Начислить 10 единиц энергии вручную бонусом
async function addMoreEnergy() {
// Добавляем 10 единиц энергии
gp.player.add('energy', 10);
// Сохраняем
gp.player.sync();
}

Восполнить энергию за просмотр рекламы

async function onClickButtonRefillEnergy() {
const success = await gp.ads.showRewardedVideo();
if (!success) {
// Не удалось показать / досмотреть рекламу
return;
}

// Восстанавливаем всю недостающую энергию
gp.player.set('energy', gp.player.getMaxValue('energy'));

// Сохраняем
gp.player.sync();
}

Увеличить объем энергии

Увеличить максимальный объем энергии. Рассмотрим на примере покупки.

async function onClickButtonIncreaseEnergy() {
// Покупаем увеличение энергии
await gp.payments.purchase({ tag: 'ENERGY_100' });

// Добавляем 100 к максимальному значению энергии
gp.player.add('energy:max', 100);
// Восполняем запас энергии
gp.player.set('energy', gp.player.getMaxValue('energy'));

// Сохраняем
await gp.player.sync();

// Расходуем покупку
await gp.payments.consume({ tag: 'GOLD_1000' });
}

Ускоренное восстановление энергии

Ускорить восстановление энергии можно либо уменьшив интервал автоначисления, либо увеличив количество восстанавливаемой энергии за итерацию. Рассмотрим на примере покупки VIP.

Увеличиваем количество восстанавливаемой энергии за интервал:

// Если у игрока есть покупка VIP восстанавливается 2 единицы энергии в минуту вместо 1
async function onGameStart() {
// Устанавливаем количество начисляемой энергии за итерацию
if (gp.payments.has('VIP')) {
gp.player.set('energy:incrementValue', 2);
} else {
gp.player.set('energy:incrementValue', 1);
}
}

Уменьшаем время восстановления энергии:

// Если у игрока есть покупка VIP восстанавливается 1 единица энергии раз в 30 секунд вместо 1 минуты
async function onGameStart() {
// Устанавливаем интервал автообновления
if (gp.payments.has('VIP')) {
gp.player.set('energy:incrementInterval', 30);
} else {
gp.player.set('energy:incrementInterval', 60);
}
}

Узнать время до восстановления

Чтобы показать в интерфейсе сколько времени осталось для следующего восполнения энергии:

Метод:

// Разница в секундах сколько осталось до следующего восполнения
gp.player.get('energy:secondsLeft');

Пример:

// Количество времени до следующего восполнения в человекочитаемом формате 05:47
function getSecondsLeftHuman() {
const secondsLeft = gp.player.get('energy:secondsLeft');
return formatTime(secondsLeft);
}

// Отформатировать в человекочитаемый формат 00:00
function formatTime(seconds) {
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return `${pad(minutes)}:${pad(remainingSeconds)}`;
}

// Добавление лидирующих нулей
function pad(num) {
return String(num).padStart(2, '0');
}

Узнать время до полного восстановления:

Метод:

// Разница в секундах сколько осталось до полного восполнения
gp.player.get('energy:secondsLeftTotal');

Пример:

// Количество времени до полного восполнения в человекочитаемом формате 05:47
function getSecondsLeftTotalHuman() {
const secondsLeftTotal = gp.player.get('energy:secondsLeftTotal');
// Возвращаем в человекочитаемом формате
return formatTime(secondsLeftTotal);
}

Награды / Боксы по времени

Вы можете реализовать механику выдачи наград / сундуков по возобновляемому таймеру.

Например:

  • Обычный сундук каждый час с момента открытия;
  • Редкий сундук каждые 6 часов с момента открытия;
  • Эпичный сундук каждые 24 часа с момента открытия;

Для реализации наград каждый час нужно завести поле игрока common-boxes в разделе Игроки в панели управления проектом как показано на скриншоте:

В этом примере Обычные сундуки:

  • Не больше 1 сундука доступно за промежуток (Ограничивать диапазоном);
  • При первом входе 0 сундуков (Значение по умолчанию), первый будет доступен через 1 час;
  • Каждые 3600 секунд (1 час) добавляется 1 сундук (Автоначисляемая переменная);
  • Можно установить выше 1 вручную.

Проверка готовности

function refreshRewardsUI() {
// Есть боксы для открытия
if (gp.player.get('common-boxes') > 0) {
// Разблокируем кнопку открытия
buttonOpenCommonBox.enable();
} else {
// Блокируем кнопку открытия
buttonOpenCommonBox.disable();
}
}

Бонусные награды

Начислить какое-то количество наград вручную бонусом, например, при прохождении уровня или убийстве босса. Если в переменной можно установить значение выше максимального, то в примере ниже добавится 1 бокс, даже если уже есть неоткрытый бокс.

// Начислить 1 обычный бокс вручную бонусом
async function giveCommonBox() {
// Добавляем 1 обычный бокс
gp.player.add('common-boxes', 1);
// Сохраняем
gp.player.sync();
}

Получить боксы за покупку:

// Начислить боксы за покупку
async function buyCommonBoxPack() {
// Покупаем пак боксов
await gp.payments.purchase({ tag: 'BOXES_PACK' });

// Добавляем 10 обычных боксов
gp.player.add('common-boxes', 10);
// Добавляем 3 редких бокса
gp.player.add('rare-boxes', 3);
// Добавляем 1 эпический бокс
gp.player.add('epic-boxes', 1);

// Сохраняем
await gp.player.sync();

// Отмечаем покупку израсходованной
await gp.payments.consume({ tag: 'BOXES_PACK' });
}

Узнать время до открытия

Чтобы показать в интерфейсе сколько времени осталось для возможности открытия следующего бокса:

Метод:

// Разница в секундах сколько осталось до следующего открытия
gp.player.get('common-boxes:secondsLeft');

Пример:

// Количество времени до следующего открытия в человекочитаемом формате 01:37:42
function getSecondsLeftHuman() {
const secondsLeft = gp.player.get('common-boxes:secondsLeft');
return formatTime(secondsLeft);
}

// Отформатировать в человекочитаемый формат 00:00:00
function formatTime(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
return `${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`;
}

// Добавление лидирующих нулей
function pad(num) {
return String(num).padStart(2, '0');
}

Ускорить открытие за валюту

Пример, как возможно обменять внутриигровую валюту на моментальное открытие. В примере обменяем количество кристаллов у игрока на перезарядку открытия бокса. Курс обмена будет зависеть от оставшегося времени до открытия.

// Узнаём стоимость моментального открытия
function getOpenCost() {
// Курс обмена кристаллов к секунде открытия
// 1 кристалл = 3 минуты (180 секунд)
const gemsRate = 1 / 180;
// Количество секунд до открытия
const secondsLeft = gp.player.get('common-boxes:secondsLeft');
// Высчитываем стоимость открытия
return Math.ceil(secondsLeft * gemsRate);
}

// При нажатии на "Открыть за кристаллы"
function onButtonInstantOpen() {
// Узнаём цену открытия
const price = getOpenCost();

// Время открытия наступило, бокс уже доступен
if (price === 0) {
// Скрываем кнопку
hideInstantOpenButton();
return;
}

// Недостаточно кристаллов
if (gp.player.get('gems') < price) {
showModalNotEnoughGems();
return;
}

// Вычитаем стоимость из кристаллов игрока
gp.player.add('gems', -price);
// Добавляем бокс
gp.player.add('common-boxes', 1);
// Сохраняем игрока
gp.player.sync();
}

Оффлайн копилка

Вы можете реализовать механику начисления игровой валюты даже пока игрок отсутствует с возможностью расширения объема копилки.

Для оффлайн копилки нужно завести поле игрока offline-piggy-bank в разделе Игроки в панели управления проектом как показано на скриншоте:

В этом примере Оффлайн копилка:

  • Емкость не больше 1000 золотых по-умолчанию (Ограничивать диапазоном);
  • При первом входе 0 золотых (Значение по умолчанию);
  • Каждую 1 секунду добавляется 1 золотой (Автоначисляемая переменная).

Опустошить копилку

function usePiggyBank() {
// Получаем количество накопленного золота
const rewardGold = gp.player.get('offline-piggy-bank');
// Добавляем игроку золото
gp.player.add('gold', rewardGold);
// Опустошаем копилку
gp.player.set('offline-piggy-bank', 0);
// Сохраняем
gp.player.sync();
}

Минимальное время для открытия

Вы можете разрешить игроку опустошать копилку, например, не чаще чем раз в 5 минут. В примере будет получено так же количество секунд до открытия.

// Проверяем можно ли использовать копилку
function canUsePiggyBank() {
// Узнаём сколько осталось до полного заполнения копилки
const secondsToRefill = gp.player.get('offline-piggy-bank:secondsLeftTotal');
// Период пополнения (1 секунда в примере)
const iterationTime = gp.player.get('offline-piggy-bank:incrementInterval');
// Доход за итерацию (1 золотой в примере)
const incomePerIteration = gp.player.get('offline-piggy-bank:incrementValue');
// Максимально возможное количество золота в копилке (1000 в примере)
const bankCapacity = gp.player.get('offline-piggy-bank:max');

// Узнаем сколько итераций нужно, чтобы заполнить копилку с нуля
const iterationsToRefillFromEmpty = Math.ceil(bankCapacity / incomePerIteration);
// Узнаем сколько секунд нужно, чтобы заполнить копилку с нуля
const secondsToRefillFromEmpty = iterationTime * iterationsToRefillFromEmpty;
// Узнаем сколько секунд осталось до открытия, требование - не меньше 5 минут прошло
const secondsLeft = secondsToRefill - (secondsToRefillFromEmpty - 5 * 60);

// Можно открывать, если времени не осталось (прошло минимум 5 минут)
return secondsLeft <= 0;
}

Увеличить вместимость копилки

Вы можете увеличить максимальный лимит копилки. Это полезно, когда в игре есть система прогресса, например, прокачка копилки.

// Увеличить объем копилки
async function upgradePiggyBankCapacity() {
// Текущая емкость копилки
const currentCapacity = gp.player.get('offline-piggy-bank:max');
// Увеличиваем емкость копилки вдвое за каждый апгрейд
gp.player.set('offline-piggy-bank:max', 2 * currentCapacity);
// Сохраняем
gp.player.sync();
}

Увеличить доход копилки

Вы можете увеличить количество пополняемого золота за единицу времени. Это полезно, когда в игре есть система прогресса, например, прокачка копилки.

// Увеличить получаемое золото за секунду
async function upgradePiggyBankIncome() {
// Увеличиваем доход за итерацию на 1 золотой за каждый апгрейд
gp.player.add('offline-piggy-bank:incrementValue', 1);
// Сохраняем
gp.player.sync();
}

Очки лояльности

Очки лояльности - показатель активности игрока. Они постоянно уменьшаются и их нужно поддерживать на определенном уровне, чтобы получать дополнительные бонусы за лояльность. Эта механика помогает сподвигнуть игрока участвовать в активностях и проходить больше уровней, чтобы не лишиться привилегий.

Например, вы можете сделать таблицу привилегий:

УровеньОчков лояльностиБонусы
1 уровень1000+10% золота за уровень
2 уровень5000+10% опыта за уровень
3 уровень10000+10 бриллиантов за уровень
4 уровень50000Кружка GamePush (разово)
+100% золота за уровень

Для очков лояльности нужно завести поле игрока loyalty в разделе Игроки в панели управления проектом как показано на скриншоте:

В этом примере Лояльность:

  • Не может падать ниже 0 (Ограничивать диапазоном);
  • При первом входе 0 лояльности (Значение по умолчанию);
  • Каждый 1 час (3600 секунд) отнимается 100 очков (Автоначисляемая переменная).

Выдача привилегий

В любой момент можно обратиться к очкам лояльности, чтобы зачесть бонусы.

// Бонус золота за прохождение уровня, зависит от очков лояльности
function goldBonusMultiplier() {
const loyalty = gp.player.get('loyalty');

// Базовый множитель 100% золота
let multiplier = 1;

// +10% при достижении 1 000 очков
if (loyalty >= 1000) {
multiplier += 0.1;
}

// +100% при достижении 50 000 очков
if (loyalty >= 50000) {
multiplier += 1;
}

return multiplier;
}

// При завершении уровня
function onLevelComplete() {
// Добавляем игроку 500 золотых с учетом множителя от лояльности
gp.player.add('gold', 500 * goldBonusMultiplier());
// Сохраняем
gp.player.sync();
}

Добавить лояльность

Пример, как вознаградить игрока, добавив очков лояльности за прохождение уровня.

async function onLevelComplete() {
// Увеличиваем лояльность на 100
gp.player.add('loyalty', 100);
// Сохраняем
gp.player.sync();
}

Пример, как вознаградить игрока, добавив очков лояльности за любую покупку.

// Купили любой предмет
gp.payments.on('purchase', () => {
// Увеличиваем лояльность на 1000
gp.player.add('loyalty', 1000);
// Сохранение игрока будет в рамках обработки покупки
});

Пример, как вознаградить игрока, добавив очков лояльности за просмотр рекламы.

// Игрок посмотрел рекламу
gp.ads.on('rewarded:reward', () => {
// Увеличиваем лояльность на 200
gp.player.add('loyalty', 200);
// Сохранение игрока будет в рамках обработки вызова рекламы
});

Заморозить уменьшение лояльности

Возможность перестать терять очки лояльности будет дополнительным стимулом для игрока совершить покупку. Например, можно предлагать "Билет лояльности (7 дней)", который позволит остановить уменьшение лояльности в течение 7 дней. Или предлагать эту опцию в рамках "VIP" статуса.

Рассмотрим пример с подпиской на билет лояльности.

// Купить билет лояльности
async function buyLoyaltyPass() {
// Оформляем подписку на билет
await gp.payments.subscribe({ tag: 'LOYALTY_PASS' });
// Замораживаем уменьшение очков лояльности
gp.player.set('loyalty:incrementValue', 0);
// Сохраняем
gp.player.sync();
}

// При старте игры
async function onGameStart() {
// Проверяем заморожено ли снижение лояльности
const isLoyaltyFrozen = gp.player.get('loyalty');

// Проверяем на наличие подписки
if (gp.payments.has('LOYALTY_PASS')) {
// Подписка есть, но лояльность не заморожена
// Возможно были проблемы при начислении покупки
if (!isLoyaltyFrozen) {
// Замораживаем уменьшение очков лояльности
gp.player.set('loyalty:incrementValue', 0);
// Сохраняем
await gp.player.sync();
}
} else if (isLoyaltyFrozen) {
// Подписка истекла и лояльность все еще заморожена

// Размораживаем уменьшение очков лояльности
gp.player.set('loyalty:incrementValue', -100);
// Сохраняем
await gp.player.sync();
}
}

Оставайтесь на связи

С другими разделами документации вы можете ознакомиться здесь. Для начала работы вы можете ознакомиться с нашими туториалами.

Сообщество GamePush в Telegram: @gs_community.

Для ваших обращений e-mail: [email protected]

Желаем вам успехов!