0

长话短说: 我正在尝试在 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 中添加足够的 postRunnables,不会有延迟,因为繁重的进程不再存在 - 相反,它建立在繁重的进程拆分为迷你进程的基础上,从而解决了“无响应”状态。虽然这么多postRunnables对于“干净的代码”来说不是很实用,因为它需要30多个postRunnables,而上面的代码只有2个。代码很容易变丑,所以我寻求替代方案。

这篇文章也很有趣,解释了我面临的完全相同的问题,但是结果没有成功。

我在 Java Swing 中通过两个线程实现了这一点;一个主线程和一个 loadingScreen 线程 (LCThread)。进入 loadingScreen 时,LCThread 开始绘制 loadingScreen,而主线程进行繁重的处理。完成后,主线程使用它之前处理的对象。可悲的是,我无法将其转换为 LibGDX,因为两个线程无法单独绘制。

短篇小说:我需要编写一个加载屏幕,它在绘制进度(在render()方法中处理)时加载繁重的后台处理(初始化大量对象)并在显示加载屏幕时播放音乐,所有这些都不会滞后于应用程序进入“没反应”。

你有什么建议吗?

4

1 回答 1

0

您可以分解您的游戏对象,以便释放处理器。希望这会分块加载并保持渲染循环自由播放音乐。基本上所有加载和创建资产都通过 AssetManager 并在渲染循环中检查以查看游戏处于什么状态并相应地采取行动。自定义游戏对象加载器。GameObject 只是一个通用类,将其应用于您的项目规范。

在 AssetManger update( int millis ) 方法中,它使 CPU 产生指定的毫秒数。如果您分解所有处理并将其放入自己的 AssetLoaders 中,则 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;
    }
}

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> {


    }
}
于 2017-10-13T11:35:26.717 回答