Вторник, 2024-03-19, 8:04 PM

Поиск
Меню
Категории раздела
Поддержи проект!
Рекомендуем


Управление памятью

Игры являются тяжеловесными ресурсными приложениями. Изображения и звуковые эффекты могут занять значительное количество оперативной памяти. Кроме того, сборщик мусора Java не управляет большинством этих ресурсов. Вместо этого они управляются посредством собственных драйверов.

Мы хотим иметь точный контроль над временем жизни наших ресурсов. В libgdx есть несколько классов, которые представляют такие ресурсы. Все они реализуют общих Disposable интерфейс, который указывает, что экземпляры класса должны быть удалены вручную в конце времени жизни. Не освобождение ресурсов приведет к серьезными утечками памяти.

Следующие классы должны быть удалены вручную.

  • AssetManager
  • Bitmap
  • BitmapFont
  • BitmapFontCache
  • CameraGroupStrategy
  • DecalBatch
  • ETC1Data
  • FrameBuffer
  • Mesh
  • ParticleEffect
  • Pixmap
  • PixmapPacker
  • ShaderProgram
  • Shape
  • Skin
  • SpriteBatch
  • SpriteCache
  • Stage
  • Texture
  • TextureAtlas
  • TileAtlas
  • TileMapRenderer
  • World

Ресурсы должны быть удалены, как только они больше не нужны, освобождая память связанную с ними. Доступ к удаленному ресурсу приведет к неопределенным ошибкам, поэтому убедитесь, что все ссылки указывающие на удаленных ресурса очищены.

При сомнениях в том, нужно ли удалять ресурсы определенного класса или нет, проверьте его на наличиеdisposed() метода. Если он есть, значит вы работаете с нативным ресурсом и должны его потом удалить.


Объединение объектов

Объединение объектов является принципом повторного использования неактивных или «мертвых» объектов, вместо постоянного создания новых. Это достигается с помощью создания пула объектов, и когда вам нужен новых объект, вы получаете его из этого пула. Если в пуле есть свободный объект, то он его вернет. Если пул пустой или не содержит свободных объектов, то возвращается созданных новый экземпляр объекта. Когда объект больше не нужен вы освобождаете его и это означает его возвращение обратно в пул. Таким образом, повторно используется память для размещения объектов и сборщик мусора просто счастлив.

Это жизненно важно для управления память в игре, которая часто порождает такие объекты как пули, препятствия, монстры и так далее.

Libgdx предлагает несколько для средств для легкой работы с пулом.

Реализация Poolable интерфейс, означает что объект имеет reset() метод, который автоматически вызывается при освобождении объекта.

Ниже приведен краткий пример пула для пуль.

public class Bullet implements Poolable {

    public Vector2 position;
    public boolean alive;

    /**
    * Конструктор пули. Простая инициализация переменных.
    */
    public Bullet() {
       this.position = new Vector2();
       this.alive = false;
    }
    
    /**
    * Инициализация пули. Вызовете это метод после получения пули из пула.
    */
    public void init(float posX, float posY) {
    position.set(posX, posY);
    alive = true;
    }

    /**
    * Метод обратного вызова когда объект освобожден.
    * Автоматически вызывается Pool.free() методом.
    * Необходимо сбросить каждое смысловое поле данной пули
    */
    public void reset() {
       position.set(0,0);
       alive = false;
    }

    /**
    * Метод вызывается при каждом кадре и обновляет пулю.
    */
    public void update (float delta) {
    
    // обновление позиции пули
    position.add(1*delta*60, 1*delta*60);
    
    // если пуля вне экрана, установка состояние в "мертвая"
    if (isOutOfScreen()) alive = false;
    }
}

В классе игрового мира:

public class World() {

    // Массив содержащий активные пули.
    private final Array activeBullets = new Array();

    // Пул для пуль.
    private final Pool bulletPool = new Pool() {
 @Override
 protected Bullet newObject() {
 return new Bullet();
 }
    };

    public void update(float delta) {
 
       // если вам нужно создать новую пулю:
       Bullet item = bulletPool.obtain();
       item.init(2, 2);
       activeBullets.add(item);

       // если вы хотите освободить "мертвые" пули, верните их обратно в пул:
    Bullet item;
    int len = activeBullets.size;
    for (int i = len; --i >= 0;) {
         item = activeBullets.get(i);
         if (item.alive == false) {
             activeBullets.removeIndex(i);
             bulletPool.free(item);
         }
    }
 }
}

Класс Pools предоставляет статические методы для динамического создания пулов любых объектов (используя ReflectionPool). В приведенном выше примере, это можно использовать так:
private final Pool bulletPool = Pools.get(Bullet.class);