长话短说:我正在尝试在LibGDX中制作一个加载屏幕,我不仅需要加载纹理和音频等资产,还需要创建世界对象(超过1000万个对象)-我可能想研究未来对象数量的减少,但我的问题仍然适用,是一个对象还是数万亿个对象。
在对象初始化期间,GDXrender()
方法会停止,我认为这是由于滞后。它将滞后于整个应用程序进入"无响应"状态几秒钟。
我已经研究了好几个月了,没有什么可找的。我找到的话题或我问的人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中添加足够的postRunnable,将不会出现滞后,因为重进程不再存在——相反,它是建立在拆分为小进程的重进程之上的,从而解决了"未响应"状态。尽管如此,这么多postRunnables对于"干净的代码"来说并不是很实用,因为它需要30多个postRunnable,而上面的代码只有2个。代码很容易变得丑陋,因此我寻求一种替代方案。
这篇帖子也很有趣,解释了我面临的完全相同的问题,但结果并不成功。
我在JavaSwing中通过两个线程实现了这一点;一个主线程和一个加载屏幕线程(LCThread)。当进入loadingScreen时,LCThread开始绘制loadingScreen,而主线程进行繁重的处理。完成后,主线程将使用以前处理过的对象。遗憾的是,我无法将其转换为LibGDX,因为两个线程无法分开绘制。
短篇小说:我需要编写一个加载屏幕,它加载繁重的背景处理(初始化许多对象),同时绘制进度(用render()
方法处理),并在显示加载屏幕时播放音乐,所有这些都不会滞后于应用程序进入"无响应"的时间。
你有什么建议吗?
你可以分解你的GameObject,这样它就可以释放处理器。希望这可以分块加载,并保持渲染循环可以自由播放音乐。基本上,所有加载和创建资产都要经过AssetManager,在渲染循环中,它会检查游戏处于什么状态,并采取相应的行动。自定义游戏对象加载程序。GameObject只是一个通用类,将其应用于您的项目规范。
在AssetManger update(int millis)方法中,它将CPU生成指定的毫秒数。如果你分解所有的处理并将其放入他们自己的AssetLoader中,AssetManager会在这段时间内更新,并且不会阻塞cpu。
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;
}
}
AssetLoader不需要有文件就可以使用,它仍然可以使用外文件。
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> {
}
}