Экран загрузки LibGDX во время интенсивной обработки

Длинная история: я пытаюсь сделать загрузочный экран в LibGDX, мне нужно будет не только загружать ресурсы, такие как текстуры и аудио, мне нужно будет создавать объекты мира (более 10 миллионов объектов) - я мог бы захотеть посмотреть на уменьшение количества объектов в будущем, но мой вопрос по-прежнему применим, будь то один объект или триллионы.

Во время инициализации объекта GDX render() метод останавливается, из-за задержки я предполагаю. Это будет отставать от того, что все приложение перейдет в "Не отвечает" на несколько секунд.

Я искал много месяцев без особого труда. 90% тем, которые я нахожу, или людей, которых я спрашиваю, всегда говорят одно и то же; использовать AssetManager. Я пробовал это, но, похоже, поддерживает только ресурсы, а не тяжелые объекты мира обработки. Кто-то сказал мне, что он может поддерживать пользовательские классы, однако я так и не получил это из-за отсутствия документации.

ЛУЧШАЯ тема, которая больше всего похожа на мою, это та, которая дала мне идею использовать Gdx.app.postRunnable() внутри Gdx.app.postRunnable(). Результат был такой:

Gdx.app.postRunnable(new Runnable() {
    @Override
    public void run() {

        // do some heavy processing
        // set loading screen percent to x%

        Gdx.app.postRunnable(new Runnable() {
            @Override
            public void run() {

                // do some more heavy processing
                // set loading screen percent to y%

            }
        });

    }
});

Решение сработало отлично. Он сделал тяжелую обработку, установил процент загрузки экрана и затем нарисовал его. Таким образом, для отображения саке это решение решило мою проблему, когда процент никогда не выводился. Однако это решение по-прежнему превращает приложение в "не отвечающий" между тяжелыми процессами; это замораживает возможное воспроизведение музыки.

Добавляя достаточное количество postRunnables в postRunnables, не будет никакого лага, так как тяжелые процессы больше не существуют - вместо этого он построен на тяжелых процессах, разделенных на мини-, решая состояние "Не отвечает". Хотя такое множество postRunnables не очень практично для "чистого кода", так как для него требуется более 30 postRunnables, а приведенный выше код равен всего 2. Коду очень легко стать безобразным, поэтому я ищу альтернативу.

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

Я достиг этого в Java Swing, имея два потока; один основной и загрузочный экранный поток (LCThread). При входе на экран загрузки LCThread начал рисовать экран загрузки, пока основной поток выполнял тяжелую обработку. Когда закончено, основной поток использовал объекты, которые он ранее обработал. К сожалению, я не могу преобразовать это в LibGDX, поскольку два потока не могут рисовать отдельно.

Короткая история: мне нужно кодировать экран загрузки, который загружает тяжелую фоновую обработку (инициализирует много объектов) во время рисования прогресса (обрабатывается в render() метод) и воспроизведения музыки во время отображения экрана загрузки, и все это без отставания от приложения, которое сильно входит в "Не отвечает".

Есть ли у вас какие-либо рекомендации?

1 ответ

Решение

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

В методе обновления AssetManger ( int millis) он возвращает ЦПУ на указанное количество миллисекунд. Если вы прервете всю обработку и поместите ее в свои собственные AssetLoaders, AssetManager обновится за это время и не заблокирует процессор.

public class GameObjectLoader extends SynchronousAssetLoader<GameObject, GameObjectLoader.GameObjectParameters> {

    public GameObjectLoader( FileHandleResolver resolver ) {

        super( resolver );
    }

    @Override
    public GameObject load( AssetManager assetManager, String fileName, FileHandle file, GameObjectParameters parameter ) {

        TextureAtlas atlas = assetManager.get( parameter.src, TextureAtlas.class );
        ShaderProgram shaderProgram = assetManager.get( parameter.shaderSrc, ShaderProgram.class );
        JsonValue json = assetManager.get( parameter.jsonSrc, JsonValue.class );
        Calculation calculation = assetManager.get( parameter.id, Calculation.class );

        GameObject gameObject = new GameObject(
            atlas.findRegion( parameter.name ),
            shaderProgram,
            json,
            calculation
        );

        assetManager.unload( parameter.id ); // unload it otherwise it stays in memory

        return gameObject;
    }

    @Override
    public Array<AssetDescriptor> getDependencies( String fileName, FileHandle file, GameObjectParameters parameter ) {

        Array<AssetDescriptor> dependencies = new Array<AssetDescriptor>();

        dependencies.add( new AssetDescriptor<TextureAtlas>( parameter.src, TextureAtlas.class ) );
        dependencies.add( new AssetDescriptor<ShaderProgram>( parameter.shaderSrc, ShaderProgram.class, parameter.shaderParameter ) );
        dependencies.add( new AssetDescriptor<JsonValue>( parameter.jsonSrc, JsonValue.class ) );
        dependencies.add( new AssetDescriptor<Calculation>( parameter.id, Calculation.class ) );

        return dependencies;
    }


    public static class GameObjectParameters extends AssetLoaderParameters<GameObject> {

        // maybe you have a lot of game logic and dont need to load everything from disk make a custom loader for that too
        public String id = "";
        public String src = "";
        public String name = "";
        public String jsonSrc = "";
        public String shaderSrc = "";
        public ShaderProgramLoader.ShaderProgramParameter shaderParameter = null;
    }
}

AssetLoaders не нужно иметь файл для работы с ним по-прежнему работает без него.

class CalculationLoader extends SynchronousAssetLoader<Calculation, AssetLoaderParameters<Calculation>> {

    public CalculationLoader( FileHandleResolver resolver ) {

        super( resolver );
    }

    @Override
    public Calculation load( AssetManager assetManager, String fileName, FileHandle file, AssetLoaderParameters<Calculation> parameter ) {

        // this is the heavy processing
        // the AssetManager dictates how many of these per cycle will be calculated
        return new Calculation();
    }

    @Override
    public Array<AssetDescriptor> getDependencies( String fileName, FileHandle file, AssetLoaderParameters<Calculation> parameter ) {

        return null;
    }

    public static class CalculationParameters extends AssetLoaderParameters<Calculation> {


    }
}
Другие вопросы по тегам