2. Базовый интерфейс
В этом уроке мы создадим простой интерфейс для взаимодействия между клиентом и сервером.
В качестве примера, мы сделаем небольшой кликер, в котором нужно нажимать на кнопку (но не слишком часто), и это будет увеличивать наш баланс. За баланс мы сможем покупать усиление: дополнительную скорость бега для котика.
Планирование
Лучше всего начать разработку игрового режима с планирования геймплея.
В нашем случае, план будет таким (для наглядности он слишком подробный):
- Пользователю показывается кнопка для получения +1 к балансу.
- Пользователю показывается текущий баланс.
- При нажатии на кнопку, пользователь увеличивает баланс на 1.
- Будет кнопка "Магазин", которая откроет панель магазина.
- Будет панель магазина, которая будет содержать товар, который можно купить за баланс.
- Будет 2 товара:
+1% к текущей скорости передвижения котика
и+1 к доходу за клик
. - Рядом с каждым товаром будет видна его цена и текущий уровень.
- Покупка будет совершаться нажатием на кнопку "Купить" под товаром.
- После покупки товара, его уровень повышается на 1.
- Каждый новый уровень повышает стоимость товара на 50% от предыдущей цены.
- Над котиком игрока будет отображаться его скорость.
Подготовка интерфейса
У нас есть план с игровыми механиками, поэтому мы заранее понимаем, какие элементы интерфейса нам понадобятся.
Кнопка для добычи баланса
Создадим вот такую кнопку:
Структура будет такой:
Начнем с создания самой кнопки Button:click
. Она будет круглой (файл Circle в проекте KotikiServer в Unity):
Прижнем эту кнопки вниз экрана, зададим ей размеры и укажем цвет:
Button:click Inspector.
Добавим кружок поменьше SmallerCircle
внутрь текущего кружка по центру, чтобы это выглядело как кружок с круглой рамкой:
SmallerCircle Inspector.
Добавим внутрь маленького кружка объект с текстом Text:balancePerClick
:
Text:balancePerClick Inspector.
Теперь у нас есть основная кнопка:
Отображение текущего баланса
Теперь создадим блок для отображния баланса.
Структура:
Блок отображения баланса представляет из себя горизонтальный список из двух элементов: иконка валюты (квадрат с ромбиком) и само значение баланса.
Block:Balance Inspector.
Теперь создадим иконку валюты. Это будет 2 картинки: желтый UISprite и внутри розовый UISprite повернутый на 45 градусов.
CoinIcon Inspector.
Image (1) Inspector.
Вторым элементом в списке будет значение баланса:
Text:BalanceValue Inspector.
"Оживление" интерфейса
[Здесь нужно описать процесс переноса сделанного интерфейса на сервер с помощью экспорта его в строку brotli и сохранение на сервере как файл uiBrotli.txt].
Теперь, когда у нас есть самые базовые вещи, а именно кнопка для увеличения баланса и блок для отображения баланса, мы можем реализовать механику увеличения баланса при нажатии на кнопку.
Для этого мы будем отслеживать нажатие на кнопку Button:click
, увеличивать баланс игрока на сервере, после чего менять Text:BalanceValue
, устанавливая актуальный баланс.
Создадим методы для создания баланса (если такого поля в объекте игрока еще нет) и для отображения баланса игроку:
function prepareBalance(pRef){
if (pRef.objs.balance === undefined){
pRef.objs.balance = 0;
}
return;
}
function sendBalance(pRef){
prepareBalance(pRef);
GUI().get("Text:BalanceValue").setText(pRef.objs.balance).next().send(pRef.id);
return;
}
Вы можете отслеживать событие buttonClicked
, которое вызывается при нажатии на любую кнопку в интерфейсе:
Events.on('buttonClicked', (pID, pRef, buttonName) => {
// Тут Ваш код для обработки кнопок
});
Посмотрите на этот код. В pRef
В pRef содержится референс на объект игрока (со всеми его данными), а в pID содержится ID игрока. buttonName это название кнопки как оно записано в самом интерфейсе (в нашем случае Button:click
).
Добавим внутрь события buttonClicked
код для обработки нажатия на кнопку Button:click
:
Events.on('buttonClicked', (pID, pRef, buttonName) => {
// Тут Ваш код для обработки кнопок
if (buttonName == "Button:click") {
prepareBalance(pRef);
pRef.objs.balance += 1; // Увеличиваем баланс игрока на 1
sendBalance(pRef);
}
return;
});
Сохраним и запустим сервер, и подключимся к нему...
Теперь у нас есть рабочая кнопка и отображение актуального баланса.
Здесь все еще не хватает некоторых вещей, которые стоит добавить:
- Отображение актуального баланса раз в секунду (на случай, если у игрока пропал интернет и он не получил последнее обновление значений).
- Отображение баланса в первый раз при подключении на сервер (чтобы сразу отобразить текущее значение).
В методе function MainLoop
у нас есть цикл, который проходится по всем игрокам.
У нас есть переменная _counterForMainLoop
, которая хранит в себе число вызовов (тиков) MainLoop за все время работы скрипта. С помощью условия if (_counterForMainLoop % N == 0)
можно выполнять код лишь раз в N тиков. 1 вызов MainLoop - это "1 тик сервера".
Найдите такой комментарий:
// For Each Player Logic
Под него мы добавим код, который будет отправлять каждому игроку его актуальный баланс раз в се кунду (раз в 10 тиков):
if (_counterForMainLoop % 10 == 0){
if (pRef.objs.balance === undefined){
pRef.objs.balance = 0;
}
// Обновляем значение текущего баланса игрока и отправляем ему команду на отображение этих данных
GUI().get("Text:BalanceValue").setText(pRef.objs.balance).next().send(pID);
}
Тогда более адекватный вариант для отправки актуального баланса раз в секунду будет таким:
if (_counterForMainLoop % 10 == 0){
sendBalance(pRef);
}
Теперь отправим изначальный баланс пользователя. Для этого воспользуемся событием playerConnected
:
Events.on('playerConnected', (pRef) => {
sendBalance(pRef);
return;
});
Готово! Теперь игрок будет постоянно видеть актуальный баланс.
Полный скрипт файла:
const Server = require('./KotikiServer.js');
const {Events, GUI} = Server;
Server.init(1, 10000); //roomID, roomPort
Events.on('playerConnected', (pRef) => {
// Если у игрока все еще нет никакого баланса, будет выставлено значение 0
pRef.objs.balance = pRef.objs.balance || 0;
sendBalance(pRef);
return;
});
Events.on('buttonClicked', (pID, pRef, buttonName) => {
if (buttonName == "Button:click") {
pRef.objs.balance += 1;
sendBalance(pRef);
}
return;
});
function sendBalance(pRef) {
GUI().get("Text:BalanceValue").setText(pRef.objs.balance).next().send(pRef.id);
return;
}