Как рендерить анимированный QGraphicsPixmapItem из одной общей картинки, размещённой вне QGraphicsPixmapItem?
Есть QGraphicsPixmapItem. Я его сделал анимированным за счёт хранения внутри него исходного спрайта и при каждом кадре QTimer переключает видимую картинку через setPixmap(), копируя туда часть исходного спрайта, соответствующую текущему кадру.
У меня возник этот вопрос потому что, при числе объектов больше 7000 и даже 5000 процесс расстановки из массива на сцену становится значительно дольше, а пока анимация всех объектов включена, общее быстродействие сильно замедляется, а почему, уже ясно, что каждую четверть секунды происходит перекопирование 10000 кадров одновременно, что крайне не оптимально.
Можно ли например через paint() вырисовывать только один экземпляр анимированной картинки из независимого аниматора, который анимирует одну картинку на все объекты своего типа на сцене?
(т.е. хранить в памяти анимацию для каждого вида объекта (Например, кошки, мышки, кролики...) а текущий кадр - элемент внешнего массива. Все размещённые на сцене объекты одного типа выводят именно эту картинку, а внутри себя её не хранят, а если она меняется - обновляет отрисовку).
Идти через paint это правильное решение: логика сцены такова, что любое изменение вызывает вызов paint.
Но я бы шел так: стандартные контейнеры хранят данные разделенным способом и любое вызывов оператора копирования или конструктора копирования меняет лишь счетчик ссылок.
Я-бы отнаследовался от QGraphicsObject (именно object), ну или и QGraphicsitem И QGraphicsObject создал бы метод аля setAnimation ( const QList & value)
И в переопределенным paint-е заставил painter рисовать следующую картинку через drawPixmap или drawPixmapFragments
Попробую через QGraohicsItem, тем более мне нужно руками их хватать, перетскивать, изменять опции, и т.п.
setAnimation() я уже сделал, но она создаёт аниматор внутри самого объекта: количество кадров, скорость кадров, и в итоге исходный спрайт превращается в анимашку. Я хочу попробовать так:
- создать аниматор как независимый объект, который будет выдавать текущий кадр.
- в предзагрузке файла буду создавать массив аниматоров, каждый из которых анимирует свою картинку и по-индексно присваивать элементам ссылку на свой аниматор, чтобы paint() прописовывал именно его кадр. Вопрос ещё в том. как дать понять сцене, что элемент обновился, и что надо вызвать paint()? Но чтобы не звонить update() каждую миллисекунду, процессору от этого будет не хорошо, особенно если в зоне видимости нет анимированных объектов
Эксперимент прошёл на ура, QGraphicsPixmapItem я превратил в QGraphicsItem.
Создал класс аниматора, который хранит только целый спрайт и имеет две выводящие функции:
image(), которая возвращает текущий кадр, читая исходное изображение через copy(), и wholeImage() которая просто отдаёт целый спрайт.
[в памяти хранится только одно цельное изображение, таймер в каждом экземпляре аниматора меняет только значение позиции кадра, а image() генерирует текущий]. Так же сделаю второй тест: создам второй буфер, куда каждый такт таймера кадр будет копироваться (как я сделал в старом по-объектном аниматоре) в выделенный для него QPixmap, а image() просто будет раздавать этот готовый кадр напрямую. Тем самым сделаю вывод, что быстрее и надёжнее. Чтобы анимация отображалась, я поставил внешний таймер, который вызывает update() на сцену (явно указав видимую область). Поставил период в 31 миллисекунду вместо 1, иначе мой одноядерный процессор нагружается на 100%.