SlideShare a Scribd company logo
Быстрое прототипирование
бэкенда игры с геолокацией
на OpenResty, Redis и Docker
Александр Гладыш
CTO, LogicEditor
План доклада
1. Кейс
2. Задача
3. Философия
4. План разработки
5. Docker
6. HTTP API
7. Устройство игрового мира
8. Демонстрация
9. Клиент
10. Итоги
11. Вопросы?
2 / 63
Обо мне
• В разработке ПО с 2002-го,
• большую часть этого времени — в геймдеве (разработка,
проектирование, управление),
• вне геймдева — нагруженные интернет-решения, enterprise ПО и др.
• Организатор meetup.com/Lua-in-Moscow
3 / 63
Мобильные игры с геолокацией
4 / 63
Цели прототипирования в общем
• Проверить ряд подходов к построению игрового процесса,
• выработать новые идеи,
• найти, в чём фан, а в чём — нет.
5 / 63
Цели технологической части прототипирования
• С минимальными затратами получить код,
• дающий возможность быстро итерироваться по вариантам геймплея.
• Прояснить на практике технические ограничения жанра.
6 / 63
Результаты
За два календарных месяца (менее 100 человеко-часов) разработан прототип
серверной части игры с геолокацией и рудиментарный клиент для неё.
Ведётся быстрое итерирование по вариантам построения игрового процесса
и дальнейшая разработка технологической части проекта.
7 / 63
О чём этот доклад?
• Доклад — технологической части проекта,
• не о геймдизайне
• и не о монетизации.
8 / 63
Зачем этот доклад?
Делать игры с геолокацией сейчас проще чем когда-либо.
Я покажу с чего можно начать.
9 / 63
Задача
• Максимально быстро написать сервер для быстрого прототипирования.
• Параллельно с сервером реализовать минимальный клиент.
• Проверять гипотезы уже во время написания, если возможно.
• Выявить основные технические ограничения на проект.
10 / 63
Стадии разработки
• Препродакшен
• Продакшен
• Поддержка
11 / 63
Стадии разработки: Препродакшен
• Препродакшен
• Поиск геймплея, эскизы, выяснение ограничений.
• Более глубокая проработка удачных вариантов геймплея.
• Подготовка к продакшену выбранного варианта.
12 / 63
Продакшен: приоритеты разработки
• Восприятие проекта
• Устойчивость ко взлому
• Масштабируемость
• Производительность
• Стабильность
• Гибкость
• Скорость итерирования
• Простота
13 / 63
Препродакшен: время на вес золота
• Скорость итерирования
• Гибкость
• Простота
• Восприятие проекта
• Стабильность
• Производительность
• Масштабируемость
• Устойчивость ко взлому
14 / 63
Фокус на скорость и лёгкость разработки
• Механизмы, а не решения.
• Лучше быстро чем правильно.
• Много коротких итераций.
15 / 63
Лучше быстро чем правильно. Переориентация
перфекционизма
• Чем меньше кода тем лучше.
• Плохой код лучше сложного.
• Хаки в механизмах допустимы, хаки в решениях — нет.
• Рефакторить нужно только то, что болит.
16 / 63
Основные этапы разработки
• Выбор геймплея пилотного прототипа.
• Выбор технологического стека.
• Реализация минимального пилотного прототипа.
• Итерирование с гейм-дизайнерами.
17 / 63
Выбор геймплея пилотного прототипа: Задачи
• Максимально простой
• но играбельный
• повод реализовать все базовые игровые сущности и механизмы
прототипа.
18 / 63
Геймплей первого прототипа
• Игрок, перемещаясь по карте, ищет расставленных на ней мобов;
• найдя моба может попробовать его поймать с заданной вероятностью
успеха;
• успешная поимка моба увеличивает счётчик в характеристиках игрока;
• пойманный моб исчезает с карты;
• через некоторое время моб респавнится в том же месте;
• администраторы могут добавлять новых мобов на карту.
19 / 63
Критерии выбора технологического стека
• Что-то знакомое, на чём можно написать быстро,
• или что-то интересное и зажигающее.
• Главное не забыть вовремя выбросить весь код.
20 / 63
Технологический стек
• Сервер:
• Redis,
• OpenResty,
• Docker.
• Клиент:
• Одностраничное веб-приложение в браузере,
• HTML5.
21 / 63
Почему не что-то готовое?
Not Invented Here Syndrome?
И да и нет.
22 / 63
Redis
• Надёжное, хорошо зарекомендовавшее себя решение.
• Работа с координатами из коробки:
• GEOADD key longitude latitude member
• GEORADIUS key longitude latitude radius m
• Достаточно удобный набор примитивов для хранения игровых объектов.
• Хранимые процедуры на Lua.
23 / 63
OpenResty
• Дистрибутив nginx с поддержкой Lua, Redis и многим другим из коробки.
• Очень быстро работает, достаточно дружелюбен, хорошо
поддерживается.
• Пригоден как для быстрого прототипирования, так и для продакшена.
24 / 63
Docker
• Воспроизводимая кроссплатформенная среда для разработки.
• Хорошо снимает боль по настройке окружения разработчика.
• Окружение разработчика можно быстро превратить в прототип
серверного окружения.
• Требует обновления до достаточно свежей версии.
25 / 63
Браузер, HTML5
• На начальном этапе сервер важнее.
• Бои в augmented reality и прочие рюшечки делать не нужно, можно
представлять в голове.
• На HTML5 можно быстро написать дёшевый и сердитый клиент.
• Есть ограниченный (но достаточный) доступ к данным геолокации.
26 / 63
Docker: как установить на Ubuntu
• В Ubuntu, традиционно, старая версия.
• За wget | sh больно бьём по рукам.
• docker и docker-machine устанавливаем из apt-репозитория докера.
• docker-compose устанавливаем через pip install.
• Про установку на других платформах читаем официальную
документацию.
27 / 63
Docker на машине разработчика
Клиент
localhost:8080
OpenResty
Redis
28 / 63
docker-compose.yml для разработки: Redis
version: "2"
services:
redis:
image: redis
volumes:
- ./redis:/data
command: redis-server --appendonly yes
openresty: <...>
29 / 63
OpenResty: интересные места nginx.conf (в сокращении)
error_log logs/error.log notice;
http {
include resolvers.conf;
lua_package_path "$prefix/lualib/?.lua;;";
lua_code_cache off; # TODO: Enable on production!
server {
listen 8080;
include mime.types;
default_type application/json;
location / { index index.html; root static/; }
location = /api/v1/ { content_by_lua_file 'api/index.lua'; }
}
}
30 / 63
OpenResty: Dockerfile
FROM openresty/openresty
COPY bin/entrypoint.sh /usr/local/bin/openresty-entrypoint.sh
COPY nginx/conf /usr/local/openresty/nginx/conf
COPY nginx/lualib /usr/loca/openresty/nginx/lualib
COPY nginx/lua /usr/loca/openresty/nginx/lua
COPY nginx/static /usr/loca/openresty/nginx/static
ENTRYPOINT /usr/local/bin/openresty-entrypoint.sh
31 / 63
OpenResty: entrypoint.sh
#!/bin/sh
grep nameserver /etc/resolv.conf 
| awk '{print "resolver " $2 ";"}' 
> /usr/local/openresty/nginx/conf/resolvers.conf
/usr/local/openresty/bin/openresty -g 'daemon off;' "$@"
32 / 63
docker-compose.yml для разработки: OpenResty
<...>
openresty:
build: .
ports:
- "8080:8080"
volumes:
- ./nginx/lualib:/usr/local/openresty/nginx/lualib:ro
- ./nginx/api:/usr/local/openresty/nginx/api:ro
- ./nginx/static:/usr/local/openresty/nginx/static:ro
links:
- redis
33 / 63
Вызовы API
• Пользовательские вызовы:
• / состояние игрового мира,
• /go/:go-id/ состояние игрового объекта,
• /go/:go-id/act/:action-id выполнение действия.
• Системные вызовы:
• /register создание пользователя,
• /reset сброс базы в исходное состояние,
• /patch апгрейд базы до текущей версии.
• NB: Админку (бэкофис) не делаем, используем внутриигровые механики
для администрирования игрового мира.
34 / 63
Игровой объект
• С точки зрения сервера игровой мир состоит из игровых объектов.
• Игровой объект имеет численные характеристики и действия.
• Игровые объекты могут иметь координаты.
• Игровые объекты без координат должны принадлежать другим
объектам или быть их прототипами.
35 / 63
Цепочка прототипов
• Игровой объект может иметь прототип.
• Игровой объект — прототип в свою очередь также может иметь
прототип.
• Игровой объект наследует характеристики и действия своих прототипов.
36 / 63
Характеристики
• Характеристика — именованное численное свойство игрового объекта.
• Если у игрового объекта нет какой-то характеристики, её значение
берётся у ближайшего прототипа по цепочке (если не нашли — 0).
37 / 63
Действия
• Действие на игровом объекте — идентификатор из таблицы
обработчиков действий.
• Действие может быть инициировано игроком, если у него достаточно на
это прав.
38 / 63
Моб: Зелёная Жаба
{
id = 'proto.mob.collectable';
chrs = { respawn_dt = 10 * 60 };
actions = { 'mob.collect' };
};
{
id = 'proto.mob.toad.green';
proto_id = 'proto.mob.collectable';
chrs = { escape_chance = 0.25 };
};
{
id = 'fa2eb7bca46c11e6be447831c1cebc82';
proto_id = 'proto.mob.toad.green';
geo = { lat = 55.7558, lon = 37.6173 };
};39 / 63
Действие: поймать моба
ACTIONS['mob.collect'] = function(target, initiator)
if
math.random() * initiator.chrs.collect_skill >
target.chrs.escape_chance
then
-- Inc number of catches for this mob type
go_inc_chr(initiator.id, target.proto_id, 1)
go_schedule_action_initiation( -- Schedule respawn
target.chrs.respawn_dt, 'mob.spawn',
{ proto_id = target.proto_id, pos = target.pos },
initiator.id
)
go_remove(target.id) -- Mob is caught, remove
end
end40 / 63
Выполнение отложенных действий
local timestamp = os.time()
local action_ids = redis:zrangebyscore('da', '-inf', timestamp)
for i = 1, #action_ids do
-- Execute action_ids[i] action
end
redis:zremrangebyscore('da', '-inf', timestamp)
41 / 63
Игрок
{
id = 'proto.user';
chrs = { vision = 100, reach = 50 };
};
{
id = 'user.1';
geo = { lat = 55.7558, lon = 37.6173 };
chrs = { collect_skill = 0.5 };
};
42 / 63
Предмет: Админская шапка
{
id = 'proto.item.wearable';
actions = {
['item.don'] = { enabled = true };
['item.doff'] = { enabled = false };
};
}
{
id = 'proto.item.admin-hat';
proto_id = 'proto.item.wearable';
grants = { 'user.admin' };
chrs = { collect_skill = 0.25 };
};
43 / 63
Выдадим админскую шапку пользователю
local hat = go_new('proto.item.admin-hat')
assert(go_get('user.1').stored[1] == nil)
go_store('user.1', hat.id)
assert(go_get('user.1').stored[1] == hat.id)
44 / 63
Хранение (”storage”)
• Игровой объект может ”хранить” другие объекты.
• Хранимые объекты не ”видны” извне хранящего объекта.
• Пользователю доступны действия непосредственно хранимых им
объектов.
• Характеристики хранимых объектов никак не влияют на характеристики
хранящих их объектов.
45 / 63
Действия на админской шапке
ACTIONS['item.don'] = function(target, initiator)
go_unstore(initiator.id, target.id)
go_attach(initiator.id, target.id)
go_disable_action(target.id, 'item.don')
go_enable_action(target.id, 'item.doff')
end
ACTIONS['item.doff'] = function(target, initiator)
go_attach(initiator.id, target.id)
go_store(initiator.id, target.id)
go_disable_action(target.id, 'item.doff')
go_enable_action(target.id, 'item.don')
end
46 / 63
Прикрепление / надевание (”attachment”)
• К игровому объекту могут быть ”прикреплены” другие объекты.
• Прикреплённые объекты видны извне родительского объекта.
• Пользователю доступны действия прикреплённых непосредственно к
нему объектов.
• Характеристики прикреплённых объектов прибавляются к
характеристикам родительских объектов.
47 / 63
Предмет: Спавнилка зелёных жаб
{
id = 'proto.item.spawner.toad.green';
actions = {
['mob.spawn'] = {
requires = { 'user.admin' };
param = { proto_id = 'proto.mob.toad.green' };
};
};
};
48 / 63
Права на действия
• Действие доступно для выполнения только если grants игрока
содержит все записи из requires действия.
• Прикреплённые к игроку (”надетые”) предметы добавляют ему свои
grants.
49 / 63
Демонстрация
• Текущую версию приложения вы можете найти на geo.logiceditor.com.
• Ссылка на репозиторий с кодом будет опубликована там же на этой
неделе, следите за анонсами в Twitter @agladysh.
• Самый первый клиент — всегда curl. API можно пощупать им, добавив
к адресу приложения /api/v1.
50 / 63
Как работает клиент?
• Инициализируются геолокация и гуглекарты.
• Текущая позиция отправляется на сервер.
• Сервер возвращает перечень видимых объектов с возможными
действиями.
• Объекты помечаются маркерами на карте и выводятся под ней вёрсткой.
• Ожидаем активации действия пользователем либо смены координат.
NB:
• Для генерации имён жаб на основе их идентификаторов используется
chance.js.
• Перерисовку лучше проводить по таймеру, вне зависимости от цикла
обновления данных.
51 / 63
Геолокация на HTML5
• navigator.geolocation.watchPosition(callback, options).
• В Chrome пользуйтесь панелью разработчика Sensors для отладки
геолокации.
• В Chrome по соображением безопасности отключена геолокация для
протокола HTTP (за исключением сайтов на localhost). Используйте
HTTPS, например, с сертификатами от Let’s Encrypt.
52 / 63
Google Maps
new google.maps.Map(assert(document.getElementById('map')), {
center: new google.maps.LatLng(pos.lat, pos.lon),
zoom: 18,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true,
disableDoubleClickZoom: true,
draggable: false,
scrollwheel: false,
styles: [ { featureType: "poi",
stylers: [ { visibility: "off" } ]
} ]
});
53 / 63
Проблемы проекта
• Шумные данные от GPS.
• Крайне низкая точность геолокации в зданиях.
• ...
54 / 63
Проблемы Технические ограничения проекта
• Шумные данные от GPS.
• Крайне низкая точность геолокации в зданиях.
• ...
Нет проблем. Есть ограничения, под которые нужно подстраивать геймплей.
Часть из них решается технологически. Нужно ли тратить время на это
решение — один из вопросов, на которые должен ответить этап
препродакшена.
55 / 63
Недостающие механизмы
• Самое крупное — система событий.
• Много мелких функций, например счётчик пройденных метров.
56 / 63
Ошибки
• Поздновато добавили геолокациию.
• Поздновато добавили карту в клиенте.
• Мало выходили на улицу чтобы тестировать.
• ...
• Найдите сами, сравнив код на слайдах с кодом в проекте.
57 / 63
Итоги
• Относительно малыми усилиями
• мы сделали крошечную мобильную игру с геолокацией
• и заложили фундамент для быстрой разработки большого числа
несложных прототипов
• для поиска удачных вариантов геймплея в этом жанре.
58 / 63
Благодаря чему разработка быстрая?
• В проекте небольшой объём простого кода,
• использующего базовые механизмы и надёжные сторонние решения
• для решения большого числа поставленных геймдизайнером задач.
• Аккуратное расширение возможностей этого кода
• ещё больше расширит круг задач, которые можно будет решить,
• поменяв несколько строк в конфиге.
59 / 63
Векторы развития проекта
• Новые варианты геймплея
• Новые функции и механизмы
• Решение технических проблем
60 / 63
Как работать с гейм-дизайнером на ранних этапах
прототипирования?
• Быстро итерироваться. В идеале — садиться рядом, кодить и сразу
получать фидбек. Пробовать самому иногда делать рутинную часть
работы гейм-дизайнера, чтобы лучше понять, что именно мешает и
тормозит процесс.
• В первую очередь исправлять мешающие тестировать геймплей баги,
потом улучшать старые механизмы в коде и добавлять новые.
• Если для новой геймплейной фичи нет механизма, добавлять его, хотя
бы в самой грубой форме, а не реализовывать решение в лоб.
• Все прочие задуманные изменения в коде, в том числе рефакторинг,
реализовывать в порядке убывания боли от их отсутствия.
61 / 63
Дорога к релизу
• Выбросить весь код и написать заново.
• Создать новый проект и вдумчиво вручную перенести в него удачные
части кода.
• Неудачные — переписать с нуля.
62 / 63
Вопросы?
@agladysh
ag@logiceditor.com
meetup.com/Lua-in-Moscow

More Related Content

PDF
Алексей Фомкин, Практическое применение Web Workers
PPTX
Что нового в nginx? / Максим Дунин (Nginx, Inc.)
PDF
Максим Дунин, Nginx, Inc.
PPTX
Автоматизация тестирования клиентской производительности / Николай Лавлинский...
PDF
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
PPTX
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
PDF
DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel)
PDF
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
Алексей Фомкин, Практическое применение Web Workers
Что нового в nginx? / Максим Дунин (Nginx, Inc.)
Максим Дунин, Nginx, Inc.
Автоматизация тестирования клиентской производительности / Николай Лавлинский...
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
MySQL 5.7 - NoSQL - JSON, Protocol X, Document Store / Петр Зайцев (Percona)
DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel)
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...

What's hot (20)

PPTX
обзор архитектуры и подсистем деплоя и мониторинга
PDF
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
PDF
Чему мы научились разрабатывая микросервисы?
PDF
RootConf 2015
PPTX
Евгений Потапов (Сумма Айти)
PPTX
Системный администратор Vkontakte. Как? / Антон Кирюшкин (Vkontakte)
PDF
Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...
PDF
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
PPTX
Мониторинг в высоконагруженных (и не только) проектах: сравнительный анализ с...
PDF
Последние новости постгреса с PGCon / О.Бартунов, А.Коротков, Ф.Сигаев (Postg...
PPTX
Жизнь проекта на production советы по эксплуатации / Николай Сивко (okmeter.io)
PDF
5 способов деплоя PHP-кода в условиях хайлоада / Юрий Насретдинов (Badoo)
PDF
Артём Ерошенко «Рецепт приготовления облачных тестингов»
PDF
Облако в Badoo год спустя
PDF
Анатомия веб-сервиса (РИТ-2014)
PPTX
DNS в условиях хостинг-провайдера / Константин Новаковский (Selectel)
PDF
Конструктор / Денис Паясь (Яндекс)
PDF
Денис Иванов
PDF
DC/OS – больше чем PAAS, Никита Борзых (Express 42)
PDF
Как devops исчерпывает себя, и что будет дальше / Кирилл Вечера (Jetware)
обзор архитектуры и подсистем деплоя и мониторинга
Кластеры баз данных делаем сложные вещи просто / Андрей Тихонов (Avito)
Чему мы научились разрабатывая микросервисы?
RootConf 2015
Евгений Потапов (Сумма Айти)
Системный администратор Vkontakte. Как? / Антон Кирюшкин (Vkontakte)
Веб-разработка без наркотиков с помощью PostgreSQL, Nginx и c2h5oh / Миша Кир...
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
Мониторинг в высоконагруженных (и не только) проектах: сравнительный анализ с...
Последние новости постгреса с PGCon / О.Бартунов, А.Коротков, Ф.Сигаев (Postg...
Жизнь проекта на production советы по эксплуатации / Николай Сивко (okmeter.io)
5 способов деплоя PHP-кода в условиях хайлоада / Юрий Насретдинов (Badoo)
Артём Ерошенко «Рецепт приготовления облачных тестингов»
Облако в Badoo год спустя
Анатомия веб-сервиса (РИТ-2014)
DNS в условиях хостинг-провайдера / Константин Новаковский (Selectel)
Конструктор / Денис Паясь (Яндекс)
Денис Иванов
DC/OS – больше чем PAAS, Никита Борзых (Express 42)
Как devops исчерпывает себя, и что будет дальше / Кирилл Вечера (Jetware)
Ad

Similar to Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Docker / Александр Гладыш (LogicEditor) (20)

PPTX
Управление облачной инфраструктурой
PDF
ekbpy'2012 - Данила Штань - Распределенное хранилище
PDF
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
PDF
Большая книга рецептов или часто задаваемые вопросы по управлению сложными пр...
PDF
Большая книга рецептов или часто задаваемые вопросы по управлению сложными си...
PPT
История проекта, который никогда не падает / Андрей Шетухин
PDF
"Девопс - это не только для программистов. Практические примеры из жизни одно...
PDF
Истинный DevOps. Секрет 42.
PDF
IT-инфраструктура. FAQ для разработчика
PDF
IForum 2016: Никита Семенов. Серьезный подход к серьезным проектам
PDF
Путь от монолита на PHP к микросервисам на Scala / Денис Иванов (2GIS)
PDF
PDF
SECON'2016. Парамонов Сергей, Автоматизируй это! Как не погрязнуть в рутине п...
PDF
CodeFest 2012. Титов А. — Инженерный дзен. Непрерывные изменения
PDF
Сергей Парамонов — Что наша жизнь — игра!
PPTX
OpenResty: превращаем NGINX в полноценный сервер приложений / Владимир Прота...
PDF
Bachelors Diploma Slides Short Version
PDF
Инженерный дзен. Непрерывные изменения (Александр Титов)
PDF
DevOps в Agile среде. Как, почему и когда инструменты помогают.
Управление облачной инфраструктурой
ekbpy'2012 - Данила Штань - Распределенное хранилище
Микросервисы: опыт использования в нагруженном проекте / Вадим Мадисон (М-Тех)
Большая книга рецептов или часто задаваемые вопросы по управлению сложными пр...
Большая книга рецептов или часто задаваемые вопросы по управлению сложными си...
История проекта, который никогда не падает / Андрей Шетухин
"Девопс - это не только для программистов. Практические примеры из жизни одно...
Истинный DevOps. Секрет 42.
IT-инфраструктура. FAQ для разработчика
IForum 2016: Никита Семенов. Серьезный подход к серьезным проектам
Путь от монолита на PHP к микросервисам на Scala / Денис Иванов (2GIS)
SECON'2016. Парамонов Сергей, Автоматизируй это! Как не погрязнуть в рутине п...
CodeFest 2012. Титов А. — Инженерный дзен. Непрерывные изменения
Сергей Парамонов — Что наша жизнь — игра!
OpenResty: превращаем NGINX в полноценный сервер приложений / Владимир Прота...
Bachelors Diploma Slides Short Version
Инженерный дзен. Непрерывные изменения (Александр Титов)
DevOps в Agile среде. Как, почему и когда инструменты помогают.
Ad

More from Ontico (20)

PDF
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
PDF
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
PPTX
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
PDF
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
PDF
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PDF
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
PDF
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
PDF
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
PPTX
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
PPTX
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
PDF
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
PPTX
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
PPTX
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
PDF
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
PPT
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
PPTX
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
PPTX
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
PPTX
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
PPTX
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
PDF
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
One-cloud — система управления дата-центром в Одноклассниках / Олег Анастасье...
Масштабируя DNS / Артем Гавриченков (Qrator Labs)
Создание BigData-платформы для ФГУП Почта России / Андрей Бащенко (Luxoft)
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Новые технологии репликации данных в PostgreSQL / Александр Алексеев (Postgre...
PostgreSQL Configuration for Humans / Alvaro Hernandez (OnGres)
Inexpensive Datamasking for MySQL with ProxySQL — Data Anonymization for Deve...
Опыт разработки модуля межсетевого экранирования для MySQL / Олег Брославский...
ProxySQL Use Case Scenarios / Alkin Tezuysal (Percona)
MySQL Replication — Advanced Features / Петр Зайцев (Percona)
Внутренний open-source. Как разрабатывать мобильное приложение большим количе...
Подробно о том, как Causal Consistency реализовано в MongoDB / Михаил Тюленев...
Балансировка на скорости проводов. Без ASIC, без ограничений. Решения NFWare ...
Перехват трафика — мифы и реальность / Евгений Усков (Qrator Labs)
И тогда наверняка вдруг запляшут облака! / Алексей Сушков (ПЕТЕР-СЕРВИС)
Как мы заставили Druid работать в Одноклассниках / Юрий Невиницин (OK.RU)
Разгоняем ASP.NET Core / Илья Вербицкий (WebStoating s.r.o.)
100500 способов кэширования в Oracle Database или как достичь максимальной ск...
Apache Ignite Persistence: зачем Persistence для In-Memory, и как он работает...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...

Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Docker / Александр Гладыш (LogicEditor)

  • 1. Быстрое прототипирование бэкенда игры с геолокацией на OpenResty, Redis и Docker Александр Гладыш CTO, LogicEditor
  • 2. План доклада 1. Кейс 2. Задача 3. Философия 4. План разработки 5. Docker 6. HTTP API 7. Устройство игрового мира 8. Демонстрация 9. Клиент 10. Итоги 11. Вопросы? 2 / 63
  • 3. Обо мне • В разработке ПО с 2002-го, • большую часть этого времени — в геймдеве (разработка, проектирование, управление), • вне геймдева — нагруженные интернет-решения, enterprise ПО и др. • Организатор meetup.com/Lua-in-Moscow 3 / 63
  • 4. Мобильные игры с геолокацией 4 / 63
  • 5. Цели прототипирования в общем • Проверить ряд подходов к построению игрового процесса, • выработать новые идеи, • найти, в чём фан, а в чём — нет. 5 / 63
  • 6. Цели технологической части прототипирования • С минимальными затратами получить код, • дающий возможность быстро итерироваться по вариантам геймплея. • Прояснить на практике технические ограничения жанра. 6 / 63
  • 7. Результаты За два календарных месяца (менее 100 человеко-часов) разработан прототип серверной части игры с геолокацией и рудиментарный клиент для неё. Ведётся быстрое итерирование по вариантам построения игрового процесса и дальнейшая разработка технологической части проекта. 7 / 63
  • 8. О чём этот доклад? • Доклад — технологической части проекта, • не о геймдизайне • и не о монетизации. 8 / 63
  • 9. Зачем этот доклад? Делать игры с геолокацией сейчас проще чем когда-либо. Я покажу с чего можно начать. 9 / 63
  • 10. Задача • Максимально быстро написать сервер для быстрого прототипирования. • Параллельно с сервером реализовать минимальный клиент. • Проверять гипотезы уже во время написания, если возможно. • Выявить основные технические ограничения на проект. 10 / 63
  • 11. Стадии разработки • Препродакшен • Продакшен • Поддержка 11 / 63
  • 12. Стадии разработки: Препродакшен • Препродакшен • Поиск геймплея, эскизы, выяснение ограничений. • Более глубокая проработка удачных вариантов геймплея. • Подготовка к продакшену выбранного варианта. 12 / 63
  • 13. Продакшен: приоритеты разработки • Восприятие проекта • Устойчивость ко взлому • Масштабируемость • Производительность • Стабильность • Гибкость • Скорость итерирования • Простота 13 / 63
  • 14. Препродакшен: время на вес золота • Скорость итерирования • Гибкость • Простота • Восприятие проекта • Стабильность • Производительность • Масштабируемость • Устойчивость ко взлому 14 / 63
  • 15. Фокус на скорость и лёгкость разработки • Механизмы, а не решения. • Лучше быстро чем правильно. • Много коротких итераций. 15 / 63
  • 16. Лучше быстро чем правильно. Переориентация перфекционизма • Чем меньше кода тем лучше. • Плохой код лучше сложного. • Хаки в механизмах допустимы, хаки в решениях — нет. • Рефакторить нужно только то, что болит. 16 / 63
  • 17. Основные этапы разработки • Выбор геймплея пилотного прототипа. • Выбор технологического стека. • Реализация минимального пилотного прототипа. • Итерирование с гейм-дизайнерами. 17 / 63
  • 18. Выбор геймплея пилотного прототипа: Задачи • Максимально простой • но играбельный • повод реализовать все базовые игровые сущности и механизмы прототипа. 18 / 63
  • 19. Геймплей первого прототипа • Игрок, перемещаясь по карте, ищет расставленных на ней мобов; • найдя моба может попробовать его поймать с заданной вероятностью успеха; • успешная поимка моба увеличивает счётчик в характеристиках игрока; • пойманный моб исчезает с карты; • через некоторое время моб респавнится в том же месте; • администраторы могут добавлять новых мобов на карту. 19 / 63
  • 20. Критерии выбора технологического стека • Что-то знакомое, на чём можно написать быстро, • или что-то интересное и зажигающее. • Главное не забыть вовремя выбросить весь код. 20 / 63
  • 21. Технологический стек • Сервер: • Redis, • OpenResty, • Docker. • Клиент: • Одностраничное веб-приложение в браузере, • HTML5. 21 / 63
  • 22. Почему не что-то готовое? Not Invented Here Syndrome? И да и нет. 22 / 63
  • 23. Redis • Надёжное, хорошо зарекомендовавшее себя решение. • Работа с координатами из коробки: • GEOADD key longitude latitude member • GEORADIUS key longitude latitude radius m • Достаточно удобный набор примитивов для хранения игровых объектов. • Хранимые процедуры на Lua. 23 / 63
  • 24. OpenResty • Дистрибутив nginx с поддержкой Lua, Redis и многим другим из коробки. • Очень быстро работает, достаточно дружелюбен, хорошо поддерживается. • Пригоден как для быстрого прототипирования, так и для продакшена. 24 / 63
  • 25. Docker • Воспроизводимая кроссплатформенная среда для разработки. • Хорошо снимает боль по настройке окружения разработчика. • Окружение разработчика можно быстро превратить в прототип серверного окружения. • Требует обновления до достаточно свежей версии. 25 / 63
  • 26. Браузер, HTML5 • На начальном этапе сервер важнее. • Бои в augmented reality и прочие рюшечки делать не нужно, можно представлять в голове. • На HTML5 можно быстро написать дёшевый и сердитый клиент. • Есть ограниченный (но достаточный) доступ к данным геолокации. 26 / 63
  • 27. Docker: как установить на Ubuntu • В Ubuntu, традиционно, старая версия. • За wget | sh больно бьём по рукам. • docker и docker-machine устанавливаем из apt-репозитория докера. • docker-compose устанавливаем через pip install. • Про установку на других платформах читаем официальную документацию. 27 / 63
  • 28. Docker на машине разработчика Клиент localhost:8080 OpenResty Redis 28 / 63
  • 29. docker-compose.yml для разработки: Redis version: "2" services: redis: image: redis volumes: - ./redis:/data command: redis-server --appendonly yes openresty: <...> 29 / 63
  • 30. OpenResty: интересные места nginx.conf (в сокращении) error_log logs/error.log notice; http { include resolvers.conf; lua_package_path "$prefix/lualib/?.lua;;"; lua_code_cache off; # TODO: Enable on production! server { listen 8080; include mime.types; default_type application/json; location / { index index.html; root static/; } location = /api/v1/ { content_by_lua_file 'api/index.lua'; } } } 30 / 63
  • 31. OpenResty: Dockerfile FROM openresty/openresty COPY bin/entrypoint.sh /usr/local/bin/openresty-entrypoint.sh COPY nginx/conf /usr/local/openresty/nginx/conf COPY nginx/lualib /usr/loca/openresty/nginx/lualib COPY nginx/lua /usr/loca/openresty/nginx/lua COPY nginx/static /usr/loca/openresty/nginx/static ENTRYPOINT /usr/local/bin/openresty-entrypoint.sh 31 / 63
  • 32. OpenResty: entrypoint.sh #!/bin/sh grep nameserver /etc/resolv.conf | awk '{print "resolver " $2 ";"}' > /usr/local/openresty/nginx/conf/resolvers.conf /usr/local/openresty/bin/openresty -g 'daemon off;' "$@" 32 / 63
  • 33. docker-compose.yml для разработки: OpenResty <...> openresty: build: . ports: - "8080:8080" volumes: - ./nginx/lualib:/usr/local/openresty/nginx/lualib:ro - ./nginx/api:/usr/local/openresty/nginx/api:ro - ./nginx/static:/usr/local/openresty/nginx/static:ro links: - redis 33 / 63
  • 34. Вызовы API • Пользовательские вызовы: • / состояние игрового мира, • /go/:go-id/ состояние игрового объекта, • /go/:go-id/act/:action-id выполнение действия. • Системные вызовы: • /register создание пользователя, • /reset сброс базы в исходное состояние, • /patch апгрейд базы до текущей версии. • NB: Админку (бэкофис) не делаем, используем внутриигровые механики для администрирования игрового мира. 34 / 63
  • 35. Игровой объект • С точки зрения сервера игровой мир состоит из игровых объектов. • Игровой объект имеет численные характеристики и действия. • Игровые объекты могут иметь координаты. • Игровые объекты без координат должны принадлежать другим объектам или быть их прототипами. 35 / 63
  • 36. Цепочка прототипов • Игровой объект может иметь прототип. • Игровой объект — прототип в свою очередь также может иметь прототип. • Игровой объект наследует характеристики и действия своих прототипов. 36 / 63
  • 37. Характеристики • Характеристика — именованное численное свойство игрового объекта. • Если у игрового объекта нет какой-то характеристики, её значение берётся у ближайшего прототипа по цепочке (если не нашли — 0). 37 / 63
  • 38. Действия • Действие на игровом объекте — идентификатор из таблицы обработчиков действий. • Действие может быть инициировано игроком, если у него достаточно на это прав. 38 / 63
  • 39. Моб: Зелёная Жаба { id = 'proto.mob.collectable'; chrs = { respawn_dt = 10 * 60 }; actions = { 'mob.collect' }; }; { id = 'proto.mob.toad.green'; proto_id = 'proto.mob.collectable'; chrs = { escape_chance = 0.25 }; }; { id = 'fa2eb7bca46c11e6be447831c1cebc82'; proto_id = 'proto.mob.toad.green'; geo = { lat = 55.7558, lon = 37.6173 }; };39 / 63
  • 40. Действие: поймать моба ACTIONS['mob.collect'] = function(target, initiator) if math.random() * initiator.chrs.collect_skill > target.chrs.escape_chance then -- Inc number of catches for this mob type go_inc_chr(initiator.id, target.proto_id, 1) go_schedule_action_initiation( -- Schedule respawn target.chrs.respawn_dt, 'mob.spawn', { proto_id = target.proto_id, pos = target.pos }, initiator.id ) go_remove(target.id) -- Mob is caught, remove end end40 / 63
  • 41. Выполнение отложенных действий local timestamp = os.time() local action_ids = redis:zrangebyscore('da', '-inf', timestamp) for i = 1, #action_ids do -- Execute action_ids[i] action end redis:zremrangebyscore('da', '-inf', timestamp) 41 / 63
  • 42. Игрок { id = 'proto.user'; chrs = { vision = 100, reach = 50 }; }; { id = 'user.1'; geo = { lat = 55.7558, lon = 37.6173 }; chrs = { collect_skill = 0.5 }; }; 42 / 63
  • 43. Предмет: Админская шапка { id = 'proto.item.wearable'; actions = { ['item.don'] = { enabled = true }; ['item.doff'] = { enabled = false }; }; } { id = 'proto.item.admin-hat'; proto_id = 'proto.item.wearable'; grants = { 'user.admin' }; chrs = { collect_skill = 0.25 }; }; 43 / 63
  • 44. Выдадим админскую шапку пользователю local hat = go_new('proto.item.admin-hat') assert(go_get('user.1').stored[1] == nil) go_store('user.1', hat.id) assert(go_get('user.1').stored[1] == hat.id) 44 / 63
  • 45. Хранение (”storage”) • Игровой объект может ”хранить” другие объекты. • Хранимые объекты не ”видны” извне хранящего объекта. • Пользователю доступны действия непосредственно хранимых им объектов. • Характеристики хранимых объектов никак не влияют на характеристики хранящих их объектов. 45 / 63
  • 46. Действия на админской шапке ACTIONS['item.don'] = function(target, initiator) go_unstore(initiator.id, target.id) go_attach(initiator.id, target.id) go_disable_action(target.id, 'item.don') go_enable_action(target.id, 'item.doff') end ACTIONS['item.doff'] = function(target, initiator) go_attach(initiator.id, target.id) go_store(initiator.id, target.id) go_disable_action(target.id, 'item.doff') go_enable_action(target.id, 'item.don') end 46 / 63
  • 47. Прикрепление / надевание (”attachment”) • К игровому объекту могут быть ”прикреплены” другие объекты. • Прикреплённые объекты видны извне родительского объекта. • Пользователю доступны действия прикреплённых непосредственно к нему объектов. • Характеристики прикреплённых объектов прибавляются к характеристикам родительских объектов. 47 / 63
  • 48. Предмет: Спавнилка зелёных жаб { id = 'proto.item.spawner.toad.green'; actions = { ['mob.spawn'] = { requires = { 'user.admin' }; param = { proto_id = 'proto.mob.toad.green' }; }; }; }; 48 / 63
  • 49. Права на действия • Действие доступно для выполнения только если grants игрока содержит все записи из requires действия. • Прикреплённые к игроку (”надетые”) предметы добавляют ему свои grants. 49 / 63
  • 50. Демонстрация • Текущую версию приложения вы можете найти на geo.logiceditor.com. • Ссылка на репозиторий с кодом будет опубликована там же на этой неделе, следите за анонсами в Twitter @agladysh. • Самый первый клиент — всегда curl. API можно пощупать им, добавив к адресу приложения /api/v1. 50 / 63
  • 51. Как работает клиент? • Инициализируются геолокация и гуглекарты. • Текущая позиция отправляется на сервер. • Сервер возвращает перечень видимых объектов с возможными действиями. • Объекты помечаются маркерами на карте и выводятся под ней вёрсткой. • Ожидаем активации действия пользователем либо смены координат. NB: • Для генерации имён жаб на основе их идентификаторов используется chance.js. • Перерисовку лучше проводить по таймеру, вне зависимости от цикла обновления данных. 51 / 63
  • 52. Геолокация на HTML5 • navigator.geolocation.watchPosition(callback, options). • В Chrome пользуйтесь панелью разработчика Sensors для отладки геолокации. • В Chrome по соображением безопасности отключена геолокация для протокола HTTP (за исключением сайтов на localhost). Используйте HTTPS, например, с сертификатами от Let’s Encrypt. 52 / 63
  • 53. Google Maps new google.maps.Map(assert(document.getElementById('map')), { center: new google.maps.LatLng(pos.lat, pos.lon), zoom: 18, mapTypeId: google.maps.MapTypeId.ROADMAP, disableDefaultUI: true, disableDoubleClickZoom: true, draggable: false, scrollwheel: false, styles: [ { featureType: "poi", stylers: [ { visibility: "off" } ] } ] }); 53 / 63
  • 54. Проблемы проекта • Шумные данные от GPS. • Крайне низкая точность геолокации в зданиях. • ... 54 / 63
  • 55. Проблемы Технические ограничения проекта • Шумные данные от GPS. • Крайне низкая точность геолокации в зданиях. • ... Нет проблем. Есть ограничения, под которые нужно подстраивать геймплей. Часть из них решается технологически. Нужно ли тратить время на это решение — один из вопросов, на которые должен ответить этап препродакшена. 55 / 63
  • 56. Недостающие механизмы • Самое крупное — система событий. • Много мелких функций, например счётчик пройденных метров. 56 / 63
  • 57. Ошибки • Поздновато добавили геолокациию. • Поздновато добавили карту в клиенте. • Мало выходили на улицу чтобы тестировать. • ... • Найдите сами, сравнив код на слайдах с кодом в проекте. 57 / 63
  • 58. Итоги • Относительно малыми усилиями • мы сделали крошечную мобильную игру с геолокацией • и заложили фундамент для быстрой разработки большого числа несложных прототипов • для поиска удачных вариантов геймплея в этом жанре. 58 / 63
  • 59. Благодаря чему разработка быстрая? • В проекте небольшой объём простого кода, • использующего базовые механизмы и надёжные сторонние решения • для решения большого числа поставленных геймдизайнером задач. • Аккуратное расширение возможностей этого кода • ещё больше расширит круг задач, которые можно будет решить, • поменяв несколько строк в конфиге. 59 / 63
  • 60. Векторы развития проекта • Новые варианты геймплея • Новые функции и механизмы • Решение технических проблем 60 / 63
  • 61. Как работать с гейм-дизайнером на ранних этапах прототипирования? • Быстро итерироваться. В идеале — садиться рядом, кодить и сразу получать фидбек. Пробовать самому иногда делать рутинную часть работы гейм-дизайнера, чтобы лучше понять, что именно мешает и тормозит процесс. • В первую очередь исправлять мешающие тестировать геймплей баги, потом улучшать старые механизмы в коде и добавлять новые. • Если для новой геймплейной фичи нет механизма, добавлять его, хотя бы в самой грубой форме, а не реализовывать решение в лоб. • Все прочие задуманные изменения в коде, в том числе рефакторинг, реализовывать в порядке убывания боли от их отсутствия. 61 / 63
  • 62. Дорога к релизу • Выбросить весь код и написать заново. • Создать новый проект и вдумчиво вручную перенести в него удачные части кода. • Неудачные — переписать с нуля. 62 / 63