Блог проекта Growing Crystals продолжает рассказывать об инди-разработке браузерной многопользоательской он-лайн игры Growing Crystals! Сегодня состоялся очень важный и ответственный момент в жизненном цикле разработки любого проекта, запуск альфа версии проекта! Наконец, он настал. Играть в Growing Crystals!
Под катом о трудностях на финише, небольшой краткий обзор всего проекта, первые впечатления и краткие планы на будущее.
Было принято решение пока не обременять пользователей регистрацией и прочими, требующими время вещами, а дать возможность сразу поиграть, введя имя реализовать полноценную регистрацию, чтобы у пользователя была возможность вернуться в игру и продолжить строить свои города, так как этот процесс достаточно длительный.
Хранение объектов игрового мира в БД
Одной из важнейших задач перед релизом была задача сохранения игрового мира в БД. Дело в том, что игровой мир всегда хранился в памяти в виде матрицы объектов и был доступен из демона, что позволяло держать скорость ответа на действие пользователя от 0.001 до 0.015 секунд при разных обстоятельствах. Проблемой была перезагрузка сервера, все данные игрового мира терялись. Для решения этой проблемы я решил сохранять данные в БД по мере изменения игрового мира. Другими словами, когда игра работает, операции с БД совершаются только INSERT и UPDATE, а при загрузке игрового демона, которая происходит только в случаях перезагрузки сервера, делается SELECT, позволяющий загрузить все ранее произведенные изменения над игровым миром. Но меня смущает некоторое падение производительности, вызванное периодическими INSERT-операциями которые приходится совершать сохраняя изменения игрового мира. Теперь скорость ответа может достигать 0.04 секунды, что уже достаточно много, и это может негативно сказаться при высоких нагрузках.
Таблица в которой я храню объекты выглядит очень просто:
CREATE TABLE IF NOT EXISTS `tbl_gamemap` ( `x` int(4) NOT NULL, `y` int(4) NOT NULL, `z` int(4) NOT NULL, `obj` blob NOT NULL, `last_mdf` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`x`,`y`, `z`) );
В obj я храню json данные об объекте игрового мира. Они занимают от 100 до 800 байт. В качестве движка хранения в СУБД MySQL я использую InnoDB. При каждом изменении элемента игрового мира использую INSERT INTO ON DUPLICATE KEY UPDATE запрос. Конечно, в случае просадок производительности при больших нагрузках, придётся перевезти проект на хороший хостинг и провести нагрузочную оптимизацию. Но на данном этапе хранение игрового мира будет осуществляться таким образом, даже невзирая на 3х кратную потерю производительности. Можно оптимизировать производительность задав настройки СУБД с учётом абсолютно преобладающих операций типа INSERT INTO ON DUPLICATE KEY UPDATE, но я пока не стал с этим разбираться.
Распаковка JSON в массив PHP
Вторая задача, на которую пришлось затратить также немало времени — это загрузка карты игрового мира из БД при загрузке игрового демона. Задача осложнилась тем, что функция PHP json_decode(), которая должна была распаковывать данные из поля obj не работает без кавычек вокруг имени переменной. Казалось бы, пользовательская функция json_decode_nice() которую удалось найти на php.net должна была решить проблему.
function json_decode_nice($json, $assoc = FALSE){
$json = str_replace(array("\n","\r"),"",$json);
$json = preg_replace('/([{,]+)(\s*)([^"]+?)\s*:/','$1"$3":',$json);
$json = preg_replace('/(,)\s*}$/','}',$json);
return json_decode($json,$assoc);
}
Но и она оказалась не универсальным решением, добавляя кавычки, но с ошибками отрабатывая разбор массивов. Она не смогла решить задачу преобразования JSON такого типа:
$obj="{x:100,z:0,anim: { move: { onfinish: \"loop\", frames: [ [0,400],[1,300],[3,300],[4,300],[5,300],[6,300],[7,500],[6,200],[5,200],[4,200],[3,200],[2,200],[1,200],[0,3500] ], sprite: 17 }, loop: { onfinish: \"loop\", frames: [ 1,2,3,4 ], sprite: 17 } },id:0}";
Функция хорошо работала только на {name:”val”, …} любой вложенности, но сыпалась на массивах, вставляя неуместные кавычки после первой запятой элемента массива. В итоге, я не стал ковыряться и регулярных выражениях этой функции пытаясь её улучшить, а перебрал большое количество пользовательских функций и библиотек решающих данную задачу. Пришлось затратить действительно много времени, и много просмотреть, начиная от класса Services_JSON 2006 года. Все решения оказались частично работающими и только одно работало на 100%:
- Встроенный json_decode хорошо работал с кавычками, но чтобы привести весь JSON в проекте к виду с кавыками, потребовалось бы переписать очень много уже облегченного для передачи клиенту JSON кода,
- Пользовательская функция json_decode_nice являлась обёрткой для json_decode и не позволяла корректно обрабатывать вложенные массивы,
- Класс Services_JSON был громоздким, разбор строки JSON с элементами массива осуществлял корректно, но возвращал только объект, а не ассоциативный массив, что тоже добавляло неудобств.
- Относительно медленная и не очень защищенная функция json2array, оказалась единственным подходящим решением.
function json2array($json){
if(get_magic_quotes_gpc()){
$json = stripslashes($json);
}
$json = substr($json, 1, -1);
$json = str_replace(array(":", "{", "[", "}", "]"), array("=>", "array(", "array(", ")", ")"), $json);
@eval("\$json_array = array({$json});");
return $json_array;
}
Ревью
Небольшое отступление о том, как это было. Приведу, ключевые, на мой взгляд, точки проекта.
- 25.04.2014 Growing Crystals: разрабатываем игровую механику vol 1. постановка задачи
- 26.04.2014 Growing Crystals vol 2. начало разработки графики
- 29.04.2014 Growing Crystals vol 4. картинка на клиенте и запросы к серверу
- 01.05.2014 Growing Crystals vol 5. сервер и место случайности в игровом процессе
- 11.05.2014 Growing Crystals vol 9. Управление браузерной игрой на мобильном устройстве
- 15.07.2014 Growing Crystals vol 11. Переход на WebSocket и движение вперед
- 23.07.2014 Growing Crystals vol 13. Логика игрового процесса
- 07.08.2014 Growing Crystals vol 14. Балансировка игрового процесса
Видение мира
В результате работы над проектом у меня сформировалось некоторое видение, весьма необычное как мне кажется:
- я полностью отказался от random в коде логики проекта, в этой игре вы не встретите случайности, только закономерности (vol. 5);
- у игрока нет пассивных навыков, и всё что он может развивать это инструменты в инвентаре, которые ведут к той или иной роли (vol. 13);
- в игре все объекты состоят из логических осмысленных компонентов, здания состоят из элементов защиты и функциональных узлов, если это функциональное здание, например, сборщик кристаллов состоит из элементов брони BS, генератора элементов брони и самого устройства сборки кристаллов (vol. 14);
- никакого прегенерированного мира, только то, что создают игроки в процессе игры (к сожалению возможности в этом плане пока весьма скромные, но ведется работа в этом направлении).
Что получилось в итоге
Что я могу сказать относительно исполнения планов сформулированных 25.04.0214 спустя 4 месяца после начала проекта? Напомню, что в планах была отлаженная игровая механика стратегической игры на карте Земли? К сожалению однозначно утвердительно ответить на этот вопрос нельзя, хотя мы и имеем полностью готовый разработанный игровой движок, основу игровой механики и баланса и гибкие методы его настройки, но многие вещи остаются не воплощенными и, в первую очередь, нету конечного понимания того, что именно нужно сделать с точки зрения увеличения интереса игры. Хотя в процессе и родилось много всего интересного, что повысило мои навыки и опыт геймдизайна.
Теперь о своих честных впечатлениях о получившемся alpha релизе. Что есть сейчас и какие планы.
Перед релизом взял несколько дней выходных сразу после отладки багов, чтобы пройти путь игрока с чистой головой, а не в роли тестера. Зарегистрировался, первое впечатление, что мало понятно по сайту о самой игре, сайт выглядит излишне претенциозным. На сайт есть скриншоты, какие-то человечки, а о чем игра и что делать в игре совсем не понятно. Начал игровую сессию, первое впечатление очень напомнило Coockie Clicker и Candy Merchant когда нужно ничего не делать а просто ждать. Понимаю что это отпугнет значительную аудиторию. И вот, спустя несколько минут я поставил несколько Collector’ов, обеспечил себе небольшую прибавку, но скажу честно, игра совершенно не динамичная и очень трудна для вхождения, т.к. первые 30 минут игрового времени вы будете обречены на ожидание и на строительство Collector’ов. Победив скуку, спустя еще немного времени я построил не плохой забор оставив вход на свою территорию. Коплю на MAIN. В общем, включайтесь, стройте, описывайте ощущения. Я очень рассчитываю на то, что смогу этим релизом привлечь хотя бы 5-6 активных игроков вместе с которыми будем проверять оружие на построенных базах. Постараюсь завершить оружие в первые недели сентября, если не будет большой загрузки с учёбой.
В майнд-карту добавил демо видео-ролик, который, как мне кажется, очень нужен на главную страницу.
Маинд-карта
Сводка
Начало: 25 апреля 2014 года.
Приостановка проекта: 21 мая 2014 — 13 июля 2014 года.
Команда: 1 (25 апреля), 1 (14 июля).
Израсходовано: 312 + 32 = 344 чч., 96 + 0 = 96 чч.
Рабочих дней: 42 + 4 = 46, 12 + 0 = 12
Средняя производительность: 344/46 = 7,47 чч/день, 96/12 = 8 чч/день
Описание игрового процесса
Расчет баланса
Игровая графика
Веб-клиент
Игровой сервер
Веб-сайт
ИТОГО