Экран загрузки 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> {
}
}