Комментарии 6
Самой ресурсоемкой функцией в движке является метод для подготовки данных из файла .tmj... для отрисовки нужно перебрать его, собрать координаты каждого тайла, координаты его текстуры, индекс текстуры, записать в буфер и отправить все на webgl для отрисовки
Сразу возникает вопрос: вы же не делаете это каждый кадр? Файл не меняется. Все, что на карте зафиксировано на одном месте, может быть собрано в текстуры больше, чем 16x16 пикселей. И переиспользовано. Для игровой логики там могут быть и земля, и стены, и десятки тысяч формально разных областей пространства. А картинка для фона - это картинка для фона. Она своей жизнью может жить. Ее даже собрать можно заранее. В реальном времени нужно что-то делать только с текстурами для меняющихся объектов, которых в зафиксированном файле по определению нет.
В первом случае мы можем столкнуться с уже описанной проблемой, когда объектов слишком много в самом детекторе коллизий
Но ведь у вас карта из квадратных ячеек, и детектор коллизий с самой простой логикой должен проверять столкновения только того, что подвигалось, и только с тем, что есть в соседних 8 ячейках. Даже не в 8, а только в тех, в сторону которых этот объект подвигался. Каким образом наличие данных о границах стен где-то у черта на куличиках будет влиять на столкновения с объектами в соседних ячейках? Хотя сама идея останавливать логику мира далеко за пределами камеры может быть хорошей, если конкретный игровой процесс на это никак не завязан, но что-то здесь не так.
Сразу возникает вопрос: вы же не делаете это каждый кадр?
Да, именно так, каждый кадр идет перерисовка всего.
Файл не меняется. Все, что на карте зафиксировано на одном месте, может быть собрано в текстуры больше, чем 16x16 пикселей. И переиспользовано. Для игровой логики там могут быть и земля, и стены, и десятки тысяч формально разных областей пространства. А картинка для фона - это картинка для фона. Она своей жизнью может жить. Ее даже собрать можно заранее. В реальном времени нужно что-то делать только с текстурами для меняющихся объектов, которых в зафиксированном файле по определению нет.
У меня есть тестовая карта с ячейками 32х32, при той же детализации, она работает намного быстрее, чем с меньшими ячейками, т.к. их банально меньше. Так что да - в укрупнении ячеек есть смысл. Если собрать заранее фон и как текстуру держать его в памяти, передавая на отрисовку только координаты смещения, работу в js можно сократить - это тоже верно. Но в обоих случаях, в памяти придется постоянно держать гораздо большее число графических объектов, что может сказаться на производительности не в лучшую сторону. Если взять из примера карту 200х200 ячеек по 16 пикселей, получится текстура 3200 х 3200 пикселей, не знаю как будет справляться webgl.
Но ведь у вас карта из квадратных ячеек, и детектор коллизий с самой простой логикой должен проверять столкновения только того, что подвигалось, и только с тем, что есть в соседних 8 ячейках. Даже не в 8, а только в тех, в сторону которых этот объект подвигался.
Да верно, но ячейки на экране, а программно объекты хранятся в виде массива, чтобы знать какие из ячеек находятся поблизости нужна другая структура данных, например, дерево или граф, а массив приходится перебирать полностью, или есть другой способ?
в памяти придется постоянно держать гораздо большее число графических объектов
Текстуры будут большего размера, но полигонов будет на порядок меньше по количеству. Мы размениваем одно на другое, а не ухудшаем все сразу.
текстура 3200 х 3200 пикселей, не знаю как будет справляться webgl
В мире WebGL есть ограничения на максимальный размер текстур. Зависят от устройств. Текстуры в 2048px сейчас поддерживают 100% устройств и браузеров. Бывают и больше, хотя я бы считал 2048px за безопасный в коммерции предел, где не будет сюрпризов на телефонах. Но даже не беря в расчет теоретические пределы - не обязательно же идти в крайности и все в одну текстуру собирать. Можно найти баланс и собирать кусками по 256x256px например.
массив приходится перебирать полностью
Плоский массив придется перебирать. На то он и плоский. Но "другая структура данных" - это не обязательно что-то логически сложное. Вам на карте из квадратных ячеек не нужна полноценная кластеризация, не нужны хитрые сравнения расстояний во все стороны. Вопрос только в том, чтобы добавить размерностей в массив объектов.
В мире WebGL есть ограничения на максимальный размер текстур. Зависят от устройств. Текстуры в 2048px сейчас поддерживают 100% устройств и браузеров. Бывают и больше, хотя я бы считал 2048px за безопасный в коммерции предел, где не будет сюрпризов на телефонах. Но даже не беря в расчет теоретические пределы - не обязательно же идти в крайности и все в одну текстуру собирать. Можно найти баланс и собирать кусками по 256x256px например.
Верно, еще есть ограничение на количество одновременно используемых текстур в webgl, у меня это 16, а бывает и 8. Так что хранить нарезанные текстуры в webgl не получится вообще. Можно, наверное, держать их в памяти js и на каждый цикл передавать их в webgl, дробя вызовы отрисовки по достижении лимита. Фактический, все это будет попросту программным укрупнением ячеек, с нагрузкой в ввиде большого количества изображений в памяти и доп. вызовов отрисовки.
Могу предложить использование нескольких канвасов.
Можно собрать весь статичный background tilemap в одно изображение и рендерить его на canvas2d с z-index, условно, 1. Остальной кадр рендерить также как сейчас в webgl, но другом канвасе с z-index 2. Таким образом у нас получится лееринг, с финальным наложением двух канвасов средствами css. К тому же, каждый отдельный канвас можно передать на обработку воркеру, чтобы заработала многопоточная обработка.
Спасибо за идею. Такой подход я пробовал в самом начале (до версии v0.3.1), правда без Worker.
Но пришлось отказаться в пользу одного canvas и масок для наложений, рисовать несколько canvas друг на друге - выходит накладно. Есть сомнения, что Worker решил бы эту проблему.
Оптимизация js/WebGL/Web Assembly