Как эффективно хранить и отображать карту тайлов в Интернете?

9

Около

На самом деле это два вопроса в одном. Прежде всего, я ищу способ эффективно хранить большие объемы данных. Другой аспект связан с запросом набора данных и отображением тайлов. Позвольте мне сначала дать вам некоторое представление.

Мы делаем браузерную многопользовательскую игру для магнатов, используя библиотеку CraftyJS для рендеринга в Canvas. На фоне графического интерфейса мы запускаем Yii Framework на PHP, и все это подключается к генератору случайных карт Python и игровому движку.

Вот как выглядит первый грубый рендер карты: http://i.imgur.com/khAXtl.png

Хранение картографических данных

Мир игры генерируется случайным образом при каждом запуске игры. Размер 100x100 гексагональных плиток для каждого игрока. Это означает, что для игры с тремя игроками создано 90 000 плиток. В настоящее время я просто создаю массив JavaScript, из которого я отображаю карту.

Это прекрасно работает для рендеринга, но для любого вида взаимодействия с картой нам нужно хранить информацию о том, какой игрок владеет плиткой, какая структура строится поверх нее, какова ее текущая цена и так далее. Сначала, по крайней мере для прототипа, мы хотели использовать MySQL, но после некоторого тестирования он работает не так быстро, как хотелось бы. Может быть, хранилище объектов, такое как MongoDB, лучше подходит для хранения данных тайлов, а не таблиц SQL. Или может быть что-то еще?

Отображение карты

Еще одна проблема, которую я вижу, это перемещение по карте. В настоящее время я создаю хитроумные объекты для каждой плитки, даже если ее нет в окне просмотра. Это медленно, потому что, хотя Crafty рендерит только те, которые находятся в окне просмотра, он сохраняет и, возможно, перебирает все тайлы в каждом событии рендеринга. В настоящее время у меня есть нарисованная карта, которая загружается очень медленно и заикается при перемещении, теперь я хотел бы сделать ее играбельной.

Моей первой идеей было загрузить отображаемое подмножество плиток, которые находятся в области просмотра. Но когда игрок переместит окно просмотра в пустую область, мне нужно будет запросить сервер и дождаться ответа, только тогда карта будет отображена. Это было бы хорошо в нативном приложении, но оно запаздывает в веб-игре.

Чтобы получить плавную производительность от карты, можно предварительно загрузить большее подмножество плиток в массив javascript и использовать его в качестве кэша. У игрока было бы несколько экранов, «кэшированных», и когда он перемещал окно просмотра, я загружал больше плиток в «кеш» JS.

Я направился в правильном направлении? Я хотел бы получить больше информации от кого-то, кто сделал что-то подобное. Я новичок в разработке игр, но за последние пару недель просматривал множество источников.

элемент
источник
1
Я удивлен, что вы определили MySQL как узкое место. Что вы тестировали, чтобы прийти к выводу, что это замедляет ход событий?
bummzack
@bummzack Если у него есть ряд на плитку, я с трудом могу понять, как все могло быть медленным
aaaaaaaaaaaa
1
@eBusiness Запрос нескольких тысяч строк из БД не должен быть проблемой на самом деле. Это все еще должно быть в диапазоне нескольких миллисекунд. Также это будет не 90 000 строк, а 30 000 строк для 3 игроков (100x100 на игрока).
bummzack
Извините за запутанную математику, между игроками вдвое больше места, чем в зоне игрока, так что они находятся на одинаковом расстоянии друг от друга, что составляет 90 тысяч. Запросы не проблема. Выбор плитки 90К и построение карты. Но это не очень хороший способ сделать это. Я буду сериализовать данные карты и использовать запрос плиток в БД, когда будет запрашиваться подробная информация.
стихия

Ответы:

2

Игровой процесс
Прежде всего я хотел бы спросить вас, вам действительно нужно 10000 плиток на игрока? Несмотря на то, что я не знаю, какую игру вы делаете, в целом верно, что большие карты делают длинные игры. Самая большая карта в Civilization 5 - это 10240 плиток, и это работает только потому, что вам не нужно играть больше, чем на ее долю.

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

Хранилище JavaScript
Что касается клиента, я бы сказал, что вам лучше держать всю карту загруженной, по крайней мере, если вы придерживаетесь gazillion плиток, иметь все это в хорошем дереве объектов может быть слишком много, поэтому вы, вероятно, должны хранить данные в "полубинарном" кодированном формате. Строки отлично работают для такого рода вещей, альтернативно, вы можете безопасно хранить беззнаковые целые числа до 53 бит в 64-битном формате с плавающей запятой, помещать их в массив, и я думаю, вы увидите довольно скромный след памяти.

Визуализация JavaScript
Хотя я не скажу, что вам не обязательно использовать canvas, вам на самом деле он не нужен для подобных вещей. Настройте все это как набор элементов img и измените свойство src для отображения различных частей карты.

Pro tip
Кстати, иногда проще поделиться семенем, использованным для его генерации, чем поделиться всей картой.

AAAAAAAAAAAA
источник
+1, но, к сожалению, веб-приложение, написанное на PHP, обычно не имеет средств для сохранения игрового состояния в памяти.
bummzack
@bummzack, Ааа, верно, я думаю, что почему-то пропустил слово PHP и просто прочитал Python. Тогда смена бэкэнда может быть в порядке. Node.js может быть вариантом.
aaaaaaaaaaaa
Я строю конкурентоспособного транспортного магната, подумайте об OpenTTD, карта размером 512x512 (262k) не такая уж большая для пары игроков. Я понимаю, что это амбициозно, но если карта не такая большая, игра закончится слишком рано. Поскольку это многопользовательская игра, мне нужно синхронизировать изменения на карте между игроками. Моим первым инстинктом было просто использовать концепции, которые я знаю по веб-разработке, и использовать базу данных. Это не должно быть супер в реальном времени. Я собираюсь с визуализацией JS, потому что я хотел бы иметь динамические вещи на карте.
элемент
Считай, что мой ответ - это несколько указателей, в конце концов, тебе придётся самому заняться производительностью, это серьезная проблема, и тебе, возможно, придется пойти на некоторые компромиссы.
aaaaaaaaaaaa
Я согласен, ваш ответ дал мне много пищи для размышлений. Я попытаюсь найти способ сохранить сериализованные данные карты в памяти и сохранить базу данных в качестве резервной копии. Но тогда я должен выяснить, как делиться изменениями между игроками. Я вернусь с тем, что придумаю, после того, как проведу дополнительное тестирование.
стихия
1

MySQL не медленный. Скорее всего, вы выполняете наивные запросы или имеете неоптимальные индексы. Подходы NoSQL, такие как MongoDB, могут быть быстрее, а может и нет. Ваш образец доступа и выбор запроса - вот что здесь действительно важно. Можно дать совет, как улучшить производительность, но не без того, чтобы увидеть, что вы уже делаете.

Чтобы получить плавную производительность от карты, можно предварительно загрузить большее подмножество плиток в массив javascript и использовать его в качестве кэша.

Ну конечно; естественно. Здесь добавить особо нечего - клиент запрашивает плитки с сервера, поэтому вам просто нужно убедиться, что те, которые вы запрашиваете, покрывают область, большую, чем экран.

Приложение:

мы запускаем Yii Framework на PHP и все это соединяется с генератором случайных карт Python и игровым движком.

Если вы хорошо разбираетесь в Python, я бы посоветовал вам отказаться от посредника PHP. Если вы запускаете свою игру как процесс Python, тогда вы можете намного легче хранить данные плитки в памяти и значительно сократить доступ к MySQL. Помогает и то, что Python гораздо более разумный язык, чем PHP.

Kylotan
источник