Оптимизация большого количества разрушаемых блоков на Python Arcade
Я пишу игру с разрушаемыми блоками которых будет почти 100к на карте. Они все - спрайты, хранятся в спрайт листе, и отрисовываются листом
self.blocks_list.draw(pixelated=True)
Если сделать карту поменьше (примерно 20к блоков) фпс нормальный. Как можно это оптимизировать? Важно сохранить их коллизии чтобы нпс за экраном не падали сквозь блоки.
ps. использую self.blocks_list.use_spatial_hashing=True
для оптимизации коллизий.
Дополняю: вот код загрузки блоков
class Block(arcade.Sprite):
def __init__(self, x, y, id):
super().__init__(f"resources/sprites/blocks/block.png")
self.center_x = x
self.center_y = y
self.id = id
Ответы (1 шт):
Отрисовывать надо не всю карту, а только те объекты, которые находятся в видимой области.
Проверка коллизий обычно требует O(n2) проверок - это можно оптимизировать.
- В первую очередь разделить объекты на подвижные (пусть их будет m<=n) и неподвижные - в коллизии должен участвовать подвижный объект, асимптотика улучшается до O(n*m).
- Если есть существенное количество подвижных объектов, то объекты можно кластреризировать в группы близкорасположенных, что позволит делать проверку только внутри кластера и, возможно, с соседними кластерами. Простейший способ - поделить по сетке с шагом в квадратный корень размера карты - движущийся объект может попадать не более чем в 4 квадрата сетки одновременно, что при равномерном распределении неподвижных объектов по карте сократит асимптотику до O(b2 * (n*m)1/4) ~ O(n1/4 * m).
Я не знаю, на чём ты пишешь игру, но меня смущает вот эта строка:
super().__init__(f"resources/sprites/blocks/block.png")
У меня есть подозрение, что для каждого объекта она создаёт новый спрайт даже если картина передаётся одна и та же. Если это так, то программа весьма нерационально использует память (вплоть до файла подкачки, что может её очень существенно замедлять) и кэш процессора.
Надо убедиться, что каждый файл загружается только один раз и используется единый спрайт для всех объектов. Это вот прям точно надо сделать.
Если копать в эту же сторону, хотя блоки и разрушаемые, вряд ли ожидается, что все они одновременно будут находиться в повреждённом состоянии. Можно воспользоваться паттерном flyweight и до первого повреждения использовать один и тот же объект для одинаковых блоков. Вообще, можно по степени разрушения сделать пул объектов. Но, честно говоря, я не уверен, что это принесёт значительную пользу после выполнения пункта 3.