Янв
20

AndEngine. Ускоряем графику. SpriteBatch

logo_100Когда спрайтов на экране становится много, FPS игры может сильно упасть.

И слабым местом в этот момент становится вывод графики на экран.

К счастью, это можно исправить, если использовать SpriteGroup и SpriteBatch. И AndEngine с радостью предоставляет нам эту возможность.

Как я недавно узнал, метод SpriteBatch давно известен и используется не только в AndEngine :)

Представьте игру, в которой есть несколько слоёв – задний фон, слой с платформами и передний фон. Число объектов в каждом слое может достигать, например, 200 и более. Без использования SpriteBatch игра не будет плавной, будут рывки, просядет FPS, будет использоваться много процессорного времени и памяти.

SpriteBatch для спрайтов без анимации

Давайте сначала рассмотрим не анимированные спрайты, используемые для фона или украшательств уровня. Сделаем допущение, что в процессе игры они не меняют своего положения.

Если использовать обычный способ вывода спрайтов на экран, то нужно будет создать много спрайтов с нужной графикой, что съест много памяти. Хотя, по сути, в этом спрайте мы храним только его координаты на сцене и ссылку на TextureRegion с графикой.

Используя же SpriteBatch, мы должны передать в него как-раз-таки только ссылку на TextureRegion и координаты на сцене, куда этот TextureRegion выводить. Это экономит память и ОЧЕНЬ сильно ускоряет отрисовку графики. Сам спрайт при этом создавать уже не нужно.

Пример (для GLES2):

final SpriteBatch _MapGfx = new SpriteBatch(GfxAssets.Texture_for_TileMap, 1000); //Указываем Атлас и максимальное кол-во спрайтов
...
/**
* Здесь запихиваем в SpriteBatch Регионы (TextureRegion) и координаты на сцене.
* В данном случаем (взято из моей игры) GfxAssets._Platforms_TR - это TiledTextureRegion с размером тайла 32*32 пикселя
* Frame - какой тайл выводить на экран
* pX, pY - кординаты тайла на сцене
* _TileWidth, _TileHeight = 32
*/
_MapGfx.drawWithoutChecks(GfxAssets._Platforms_TR.getTextureRegion(Frame), pX, pY, _TileWidth, _TileHeight, Color.WHITE_PACKED);
...
/**
* После завершения добавления всех "спрайтов" ОБЯЗАТЕЛЬНО вызываем этот метод,
* иначе на экране ничего не появится
*/
_MapGfx.submit();
/**
* Перед новым использованием SpriteBatch, очищать его не надо.
* Просто пихаете новые "спрайты" и вызываете в конце метод submit()
*/

На своём опыте скажу, что в своей игре-платформере для создания платформ я использую один TiledTextureRegion с графикой. Раньше каждый тайл я создавал в виде TiledSprite и указывал ему номер кадра. При этом каждый такой спрайт создавался со ссылкой на копию TiledTextureRegion через deepCopy (). В версии движка GLES2 происходил просто жор памяти. Создание уровня занимало 1-2 секунды, хотя спрайтов было штук 300. Тайлы добавлялись через обычный attachChild ().

После оптимизации и использования SpriteBatch всё стало работать просто замечательно. Создание уровня занимает меньше секунды, а память почти не расходуется.

SpriteGroup для анимированных спрайтов

Что касается анимированных спрайтов, то для них нужно использовать SpriteGroup. И тут без создания самих спрайтов уже не обойтись, ведь для каждого из них нам надо задать анимацию.

Работа с SpriteGroup ничем не отличается от работы с обычным Entity.

Пример:

final SpriteGroup _BackLayerAnimated = new SpriteGroup(GfxAssets.Texture2, 300);
...
_BackLayerAnimated.attachChild(_AnimatedSprite);

Нюансы

1. У SpriteBatch и SpriteGroup есть особенность – все спрайты, а точнее TextureRegion’s, должны быть размещены в одном и том же Атласе. Имейте это в виду.

2. Вторая особенность – размер SpriteGroup и SpriteBatch нужно указывать при его создании, т.к. внутри себя они создают массив (Array), а не список (ArrayList). При этом размер массива получается равным числу элементов * 30 (в байтах).

3. В версии GLES1 SpriteBatch некорректно работает с упакованными текстурами (Атласами), т.е. с расширением AndEngineTexturePackerExtension. Вместо графики выводятся чёрные прямоугольники. Добиться решения на форуме мне так и не удалось. Поэтому переходите на GLES2, там всё работает как надо.

Совет

Если у вас на заднем (переднем, любом) фоне есть и статические и анимированные спрайты, создайте два разных «слоя» — в один (SpriteBatch) добавляйте статические спрайты, в другой (SpriteGroup) — анимированные.

Затем просто добавьте их на сцену:

_myScene.attachChild(_BackLayerAnimated);
_myScene.attachChild(_MapGfx);



7 комментариев к записи “AndEngine. Ускоряем графику. SpriteBatch”

  • Супер! Спасибо!!

  • Спасибо! Интересный метод, нужно будет изучить поподробнее.

    P.S. Только заметил стандартную форму для комментов)

  • Спасибо! У меня вопрос, немного не по теме. Есть ли способ ускорить работу игры, если я использую ParallaxBackground и у меня 4 слоя (где-то320*300). Чем больше текстуру я использую тем больше падает FPS. можно ли как-то оптимизировать большие(относительно) текстуры?

    • Хм, даже не знаю. Текстуры вроде маленькие

      • Я тоже думал что маленькие. Но с добавлением каждой текстуры в ParallaxBackground (фон со слоями, которые сдвигаются) количество кадров в секунду падало на 10-15% как на емуляторе так и на телефоне:(

  • А спрайты в SpriteBatch динамически можно добавлять/удалять или как создал в начале игры так до окончания SpriteBatch не меняется?

Прокомментировать