Управление активами в LibGDX

Вот моя настройка ООП:

Класс MainGame расширяет игру:

...

public void create () {
    assets = new Assets(); // my custom Assets object (constructor creates manager and AssetDescriptors
    assets.load(); // loads Asset Descriptors into manager
    assets.getManager().finishLoading();
    batch = new SpriteBatch();
    setScreen(new PlayScreen(this, assets));
}

...

public void dispose () {

    assets.dispose(); // disposes asset manager
    super.dispose();
    batch.dispose();
}

Класс PlayScreen реализует Screen:

public PlayScreen(MainGame game, Assets assets) {

    this.assets = assets;
    this.game = game;

    background = assets.getManager().get(assets.getBackground());
    hero = new HeroSprite(290, 1100, this, assets);

    // Create Game camera and Hub also
}

public void render(float delta) {

    // Clear screen
    // Use game batch to draw to screen

}

public void dispose() {
    assets.dispose();
}

Класс HeroSprite:

public HeroSprite(int x, int y, PlayScreen screen, Assets assets){

    this.assets = assets;
    this.screen = screen;

    // Animation Textures
    heroWalking = assets.getManager().get(assets.getWalking()); // This is an Asset Descriptor

    walkAnime = new Animation(heroWalking) // my own custom animation class which takes the spritesheet and returns the appropriate frames

    ...

 }

// This does not contain a dispose method

Извините, если там много кода, я постарался максимально свести его к минимуму. Мой главный вопрос: правильно ли я утилизирую?

Вроде нормально, моя игра работает нормально. Но когда я выхожу из игры и снова вхожу, появляется черный экран. Это происходит как на ПК, так и на Android.

Решение, которое работает, - очистить память на Android с помощью приложения Super Cleaner. Поскольку это проблема с памятью, я полагаю, что это как-то связано с тем, что я неправильно утилизирую.

РЕДАКТИРОВАТЬ: раскрытие моего класса активов

public class Assets {

    private AssetManager manager;

    private AssetDescriptor<Texture> background;
    private AssetDescriptor<Texture> wood;

    public AssetManager getManager() {
        return manager;
    }

    public AssetDescriptor<Texture> getBackground() {
        return background;
    }

    public AssetDescriptor<Texture> getWood() {
        return hero;
    }    

    public Assets(){

        manager = new AssetManager();

        background = new AssetDescriptor<Texture>("textures/static/bg.png", Texture.class);
        hero = new AssetDescriptor<Texture>("textures/static/hero.png", Texture.class);
        ...

    }

    public void load(){

        manager.load(background);
        manager.load(hero);
        ...

    }

    public void dispose(){
        manager.dispose();
    }
}

person Greg Peckory    schedule 05.02.2017    source источник
comment
Зачем нужно удалять активы из метода dispose () PlayScreen?   -  person Abhishek Aryan    schedule 05.02.2017
comment
как вы выходите из игры? Вы используете Gdx.app.exit (); ?   -  person Abhishek Aryan    schedule 05.02.2017
comment
На рабочем столе я нажимаю кнопку «X». На Android я смахиваю приложение. Я никогда не использовал Gdx.app.exit()   -  person Greg Peckory    schedule 05.02.2017


Ответы (1)


Screen.dispose() не вызывается автоматически, вы должен вручную вызывать dispose, когда вы выходите из экрана и больше не нуждаетесь в ресурсах. Но, очевидно, когда они вам снова понадобятся, вам нужно снова загрузить их, и для этого вам понадобится new AssetManager. Так что, если ваши активы не будут занимать так много времени, вы должны просто сохранить их в памяти.

Однако при выходе вам нужно избавиться. Game.dispose() вызывается автоматически. Здесь вы должны вызвать getScreen().dispose() и утилизировать все необходимое с помощью dispose() метода эффективного Screen.

Поскольку в настоящее время не похоже, что вы размещаете между экранами, это может быть связано с тем, что у вас есть статический AssetManager, вам следует показать свой класс Assets().

person Madmenyo    schedule 05.02.2017
comment
объект assets уже удален из метода dispose () класса Game, тогда зачем вызывать getScreen (). dispose () для удаления объекта assets. Поскольку данный ссылочный объект Assets создается один раз из метода create () Game, поэтому он не должен удаляться из метода Dispose () Screen. В настоящее время владелец удалил активы из метода dispose () экрана, но не вызвал этот метод. - person Abhishek Aryan; 05.02.2017
comment
@AbhishekAryan SpriteBatch не удаляется. Если у вас там Stage, его не утилизируют. - person Madmenyo; 05.02.2017
comment
Хорошо, я стараюсь не отставать. Во-первых, мой управляющий активами не статичен. Фактически, почти каждая переменная в моей игре является частной. Кроме того, SpriteBatch размещается в классе Game. - person Greg Peckory; 05.02.2017
comment
@Madmenyo Владелец использует SpriteBatch класса Game, который размещается в методе dispose () класса Game. В методе render () владельца экрана упоминается, что он использует только класс SpriteBatch класса Game для рендеринга через комментарий, а там нет Stage. - person Abhishek Aryan; 05.02.2017
comment
Верный. Я не использую сцену. Пакетный объект игры используется для рисования на экране, который передается в конструктор Screen из класса Game. - person Greg Peckory; 05.02.2017
comment
@AbhishekAryan да, действительно, моя ошибка. Но dispose() в GameScreen никогда не вызывается, насколько я понимаю. Если он закрывает игру с помощью X на рабочем столе, и это происходит, AssetManager остается в удаленном состоянии и не получает new AssetManager(), это все, о чем я могу думать. AFAIK это могло произойти только в том случае, если вы создаете статический AssetManager. - person Madmenyo; 05.02.2017
comment
Я отредактировал свой вопрос, чтобы показать Asset Manager. Как видите, это не статично. Есть ли какая-нибудь форма отладки, которую я мог бы использовать для проверки утилизации? - person Greg Peckory; 05.02.2017
comment
Как насчет того, чтобы вызвать finishLoading() метод show. Они, вероятно, не загружены, не знаю почему, но загрузка их в show() гарантирует, что проблема именно в этом. - person Madmenyo; 05.02.2017
comment
Хорошо, я попробую. Вы знаете, следует ли мне вызывать background.dispose() в методе удаления экрана? Поскольку он ссылается на текстуру в Asset Manager, в этом нет необходимости, верно? Идеи у меня заканчиваются. - person Greg Peckory; 05.02.2017
comment
Так и думал. Вызов finishLoading() в show приводит к вылету игры. Я также пробовал переместить load() в show, но не исправил - person Greg Peckory; 05.02.2017
comment
@GregPeckory Ну, ваш AssetManager не переинициализируется должным образом, когда вы выходите и перезагружаете игру. К сожалению, я понятия не имею, почему. - person Madmenyo; 05.02.2017
comment
Ok. Спасибо за помощь !! Если я выясню это, я отправлю ответ здесь. - person Greg Peckory; 05.02.2017
comment
stackoverflow.com/questions/31137930/ вы уверены, что не используете статические данные о своих активах? Когда я начинал с LibGDX, у меня были те же проблемы с черными текстурами. Прочтите документацию AssetManager, сделайте это правильно, и это действительно должно работать. - person Madmenyo; 05.02.2017