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

2. Базовый интерфейс

В этом уроке мы создадим простой интерфейс для взаимодействия между клиентом и сервером.

В качестве примера, мы сделаем небольшой кликер, в котором нужно нажимать на кнопку (но не слишком часто), и это будет увеличивать наш баланс. За баланс мы сможем покупать усиление: дополнительную скорость бега для котика.

Планирование

Лучше всего начать разработку игрового режима с планирования геймплея.

В нашем случае, план будет таким (для наглядности он слишком подробный):

  1. Пользователю показывается кнопка для получения +1 к балансу.
  2. Пользователю показывается текущий баланс.
  3. При нажатии на кнопку, пользователь увеличивает баланс на 1.
  4. Будет кнопка "Магазин", которая откроет панель магазина.
  5. Будет панель магазина, которая будет содержать товар, который можно купить за баланс.
  6. Будет 2 товара: +1% к текущей скорости передвижения котика и +1 к доходу за клик.
  7. Рядом с каждым товаром будет видна его цена и текущий уровень.
  8. Покупка будет совершаться нажатием на кнопку "Купить" под товаром.
  9. После покупки товара, его уровень повышается на 1.
  10. Каждый новый уровень повышает стоимость товара на 50% от предыдущей цены.
  11. Над котиком игрока будет отображаться его скорость.

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

У нас есть план с игровыми механиками, поэтому мы заранее понимаем, какие элементы интерфейса нам понадобятся.

Кнопка для добычи баланса

Создадим вот такую кнопку:

alt text

Структура будет такой:

alt text

Начнем с создания самой кнопки Button:click. Она будет круглой (файл Circle в проекте KotikiServer в Unity):

alt text

Прижнем эту кнопки вниз экрана, зададим ей размеры и укажем цвет:

Button:click Inspector.

alt text

Добавим кружок поменьше SmallerCircle внутрь текущего кружка по центру, чтобы это выглядело как кружок с круглой рамкой:

alt text

SmallerCircle Inspector.

alt text

Добавим внутрь маленького кружка объект с текстом Text:balancePerClick:

alt text

Text:balancePerClick Inspector.

alt text

Теперь у нас есть основная кнопка:

alt text

Отображение текущего баланса

Теперь создадим блок для отображния баланса.

alt text

Структура:

alt text

Блок отображения баланса представляет из себя горизонтальный список из двух элементов: иконка валюты (квадрат с ромбиком) и само значение баланса.

Block:Balance Inspector.

alt text

Теперь создадим иконку валюты. Это будет 2 картинки: желтый UISprite и внутри розовый UISprite повернутый на 45 градусов.

CoinIcon Inspector.

alt text

Image (1) Inspector.

alt text

Вторым элементом в списке будет значение баланса:

Text:BalanceValue Inspector.

alt text

"Оживление" интерфейса

[Здесь нужно описать процесс переноса сделанного интерфейса на сервер с помощью экспорта его в строку 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;
});

Сохраним и запустим сервер, и подключимся к нему...

Теперь у нас есть рабочая кнопка и отображение актуального баланса.

alt text

Здесь все еще не хватает некоторых вещей, которые стоит добавить:

  1. Отображение актуального баланса раз в секунду (на случай, если у игрока пропал интернет и он не получил последнее обновление значений).
  2. Отображение баланса в первый раз при подключении на сервер (чтобы сразу отобразить текущее значение).

В методе 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;
});

Готово! Теперь игрок будет постоянно видеть актуальный баланс.

Исходник game.js

Полный скрипт файла:

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;
}