Dusk World – Дневники разработки, часть 7:
Как сделать регенерацию энергии (здоровья/маны) в браузерной MMORPG
Прежде чем переходить к руководству, хочу поделиться своим удивлением. Рунет существует ~20 лет. Браузерные игры почти столько же. Система регенерации энергии/здоровья/маны используется практически в каждой. И нет ни одной инструкции как её сделать с примером кода (по крайней мере, я найти не смог). Как?! Вопросы как это сделать встречаются, но вот примера реализации нет. При этом в обсуждениях встречаются какие-то феерические сложные советы «используй node.js», «используй CRON» и т.д.
К чему такие сложности, когда с задачей справится и обычный PHP с MySQL (+ JS на фронте).
Мой пример, возможно, не идеальный, но предупрежу сразу за критику буду кидать тапками, потому что Если вы такие умные, почему я первый, кто сделал пример подобного функционала?. Ответ, конечно, напрашивается сам-собой потому что у нас на одного человека, который что-то делает, приходится десятки экспертов-критиков, которые критикуют того, кто что-то сделал, но вот сами не спешат сделать что-то для окружающих.
Ладно, это были эмоции, надо было высказаться :)
Конструктивная критика, конечно, приветствуется.
Для кого это руководство
- Для тех, кто уже знает основы PHP, ООП, MySQL и хоть чуть-чуть знаком с JS
- Для тех, кто делает свою браузерную игру (возможно MMORPG) на PHP и MySQL
- Для тех, кто хочет реализовать механику регенерации энергии/здоровья/маны, но не может сделать её своими силами.
Руководство не для тех, кто работает в веб-разработки 10+ лет вы сами все сделаете, возможно лучше, чем у меня.
О подходе к задаче
При написании данного примера ставил перед собой задачу сделать нужный функционал с минимальным количеством кода. Я мог бы сделать его на Yii2 или Laravel, добавить к этому AJAX, но тогда новичку было бы сложно во всем этом разобраться понять, где код самого фреймворка, а где код скрипта. Да и тот же фреймворк еще надо уметь поставить.
В итоге вышло ~400 строк кода, с комментариями практически к каждой строчке. Даже новичок должен разобраться. А кто не сможет разобраться даже в этих 400 строк кода с подробными комментариями, должен задуматься а сможет ли он вообще сделать свою браузерную MMORPG. Это довольно сложная и многогранная задача, которая требует некоторого уровня профессионализма.
Демо
Хорошим тоном считаю вначале показать что мы собственно будем делать:
Примечание: в демо все посетители «управляют» энергией одного пользователя, и это может создавать иллюзию «бага»: когда два посетителя будут одновременно увеличивать или уменьшать энергию будут учитываться все действия (вы нажали «-30 энергии», а кто-то в этот момент нажал «+30 энергии» в итоге изменения энергии не произойдет вовсе). Можно было бы под каждого уникального посетителя создавать отдельного пользователя, но это излишние навороты. Учитывая крайне низкую вероятность, что два посетителя зайдут на страницу демо одновременно этим можно пренебречь.
Необходимые параметры
Вначале пройдемся по параметрам, которые нужны для работы (использую теже названия, что и в коде):
-
$cost базовый параметр, который будет храниться отдельно (один для всех) необходимое количество
секунд, для восстановления одной энергии. В примере скрипта, указанного ниже он равен 20. Т.е. за 20 секунд
пользователь восстанавливает 1 энергию
Примечание: если в вашей игре вы планируете, к примеру, добавить предметы, которые будут уменьшать требуемое количество секунд на восстановление одной энергии то данный параметр надо хранить у каждого пользователя отдельно; - id id пользователя. Я буду работать с одним пользователем, и id, в общем-то, не нужен, но закладывать его нужно сразу;
- name имя пользователя, чтобы мы определяли энергию не абстактного нечто, а конкретного пользователя с именем;
- energy текущая энергия;
- energy_max максимальное количество энергии;
- time время последнего обновления энергии - именно по разнице между этим временем и текущим мы будем считать, нужно ли пользователю пополнить энергию и на сколько;
- residue остаток времени - необходимость этого параметра опишу ниже;
- eweight длина полоски энергии мы же хотим видеть полоску энергии, и наблюдать как она заполняется со временем, верно?;
- sweight длина полоски секунд
- time_actual текущее время;
- efull параметр отвечающий за то, полная ли энергия у пользователя или нет. Если энергия полная то никаких дополнительных расчетов делать не нужно;
- difference разница между текущим временем и временем последнего обновления энергии;
- addenergy количество энергии которое мы должны добавить пользователю (может быть 0, 1 или больше);
- residue_new новый остаток времени;
Для реализации нам нужно будет реализовать бек-энд и фронт-энд. Задача бек-энда по запросу выдавать количество текущей энергии пользователя (и дополнительные параметры). Задача фронт-энда визуально эмулировать восстановление энергии (здоровья/маны) в браузере пользователя. Дергать постоянно сервер мы не будем это не нужно.
Стркуткра БД
Базовых параметров, которые требуются для рассчета энергии и которые нужно хранить в базе всего 4: текущая энергия, максимум энергии, время последнего обновления энергии и остаток секунд. Чтобы пример был более приближен к реальности добавил еще два: id пользователя и его имя
MySQL-таблица будет выглядеть так:
SQL код для её создания наполнения
CREATE TABLE `energy` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `uname` varchar(255) NOT NULL, `energy` INT(11) DEFAULT '100', `energy_max` INT(11) DEFAULT '100', `time` decimal(20,4) NOT NULL, `residue` INT(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `energy` (`id`, `uname`, `energy`, `energy_max`, `time`, `residue`) VALUES (1, 'Andariel', 94, 120, '1517230970.1444', 12);
Логика работы бек-энда
Ну что ж, давайте начнем. Что такое «энергия» в браузерных играх объяснять думаю не нужно все с ней сталкивались. Наша задача создать её, и сделать механику её «регенерации».
Вариант №1: Энергия полная
- Получаем данные о пользователе из БД
- Узнаем, полная ли у пользователя энергия
- Если да ничего дополнительно делать не нужно
Вариант №2: Энергия не полная
Вначале опишу на примере конкретных цифр, чтобы было проще понять, затем логикой самого скрипта.
К примеру, у нас есть пользователь с 50 энергии из 100. Последнее обновление было 30 секунд назад, а на восстановление одной энергии требуется 20 секунд.
- Узнав, что энергия не полная, нам нужно узнать разницу между текущим временем и временем последнего обновления получаем 30 секунд;
- Считаем, какое количество энергии можем восстановить, на основе прошедшего времени 30 делим на 20 и округляем до меньшего. Получаем 1;
-
Дальше нам нужно рассчитать количество секунд, которые остались после расчетов:
остаток секунд = разница времени (количество восстанавливаемой энергии * количество секунд на восстановление)
В нашем случае остаток будет 10 секунд; - Итак, мы рассчитали, что игроку надо восстановить 1 энергию, и записать остаток секунд 10, чтобы учитывать их при следующем обновлении страницы (и, соответственно, следующем рассчете текущего количества энергии). Записываем все это в бд: новое количество энергии, остаток, и время обновления энергии обновится само;
Теперь перейдем к реальной логике скрипта
- Получаем базовые данные о пользователе из БД (id пользователя, имя, количество энергии, максимальное количество энергии, время последнего обновления и остаток секунд)
- Рассчитываем дополнительные параметры пользователя. Для этого первым делом узнаем, полная ли у пользователя энергия.
- Если энергия не полная, необходимо рассчитать дополнительные параметры:
- Разница времени в сек. = (текущее время - время последнего обновления энергии) + остаток секунд
-
Добавляемая энергия = разница времени в сек. / количество времени на восстановление одной энергии
Полученное значение округляем в меньшую сторону - Новый остаток в сек. = разница времени в сек. - (добавляемая энергия * количество времени на восстановление одной энергии)
- Далее проверяем, можем ли мы добавить одну или более энергии пользователю
- Если да добавляем энергию (попутно проверяя, не стала ли она выше максимальной) и записываем новые параметры
- Так как базовые параметры изменились по новой рассчитываем дополнительные параметры
- Выводим информацию на страницу
Логика работы фронт-энда
Теперь переходим к фронт-энду. Так как у нас не реал-тайм геймплей (PHP для данной цели вообще плохо подходит, я бы смотрел в сторону NodeJS), то знать количество энергии пользователя нужно только в момент отображения (обновления) страницы и каких-либо действий например пользователь хочет войти в локацию, вход в которую стоит 20 энергии, и только в этот момент нам нужно узнать реальное количество энергии пользователя.
В остальных случаях, когда пользователь просто открыл страницу и смотрит на неё нам достаточно сделать эмуляцию восстановления энергии, которая, в тоже время, будет соответствовать реальной энергии.
Для этого пишется довольно простой JS-скрипт-таймер, который каждую секунду (в моем примере это секунды, хотя можно сделать и другие промежутки времени) добавлять «по секунде», а когда накопится нужное количество секунд для восстановления одной энергии увеличивает количество энергии на 1, а счетчик секунд сбрасывает.
Когда энергия полная (или если она полная изначально) таймер останавливается.
Как бек-энд и фронт-энд работают в паре
При запросе к серверу (открытии страницы, или изменении энергии) бек-энд считает все данные, проверяет возможность изменения энергии и формирует html страницу вместе с нужными параметрами для js скрипта.
Когда страница загрузилась начинает работать js, который запускает функцию timer(). Он в свою очередь запускает функцию step(), которая обрабатывает логику счетчика, а он в свою очередь запускает функцию view(), которая обновляет информацию на странице.
Примечания
- Точность: При расчетах остаток секунд округляются до целых, соответственно может теряться до 0.5 секунд. Если игра не подразумевает частых расходов энергии, и частого обновления страницы то это нормально. Иначе нужно будет дорабатывать точность: окгуллять не до целых, а, например, до десятых или сотых.
- AJAX: Сейчас при изменении энергии обновляется страница, и, соответственно, перезапускается js-скрипт. Если вы будете изменять энергию AJAX-ом, то js-таймер нужно будет запускать отдельно.
- Безопасность: В текущей версии все реальные расчеты происходят на бек-энде. Пользователь может со своей стороны что угодно делать с html/js (рисовать какие угодно цифры) это никак не повлияет на реальные значения энергии пользователя.
Смотрите также: | ||
|
Комментарии
|
+3
|
Реклама:
Ответить