【问题标题】:Access of a gdx.utils.Array launches a ClassCastException访问 gdx.utils.Array 会启动 ClassCastException
【发布时间】:2016-08-30 01:04:25
【问题描述】:

我正在尝试从包含我的渲染方法中的所有游戏对象的数组中选择某些对象。因为它在我的渲染方法中,所以我试图通过只使用成员变量来避免垃圾收集器。我的目标是放入作为 Renderable 实例的 tmpRenderArray 游戏对象。然后我需要对这些对象进行排序并渲染它们。

这是我的代码:

private Array<GameObject> gameObjects = new Array<>();
private Array<Renderable> tmpRenderArray = new Array<>();

//...

@Override
public void render(float delta)
{
    Gdx.gl.glClearColor(1f, 0.7f, 0.7f, 1f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    batch.setProjectionMatrix(camera.combined);
    batch.begin();

    int i = 0;
    for(GameObject object : gameObjects)
        if(object instanceof Renderable)
            tmpRenderArray.set(i++, (Renderable)object);

    tmpRenderArray.sort(Renderable.PRIORITY_COMPARATOR); 
    //PRIORITY_COMPARATOR = (a, b) -> Float.compare(a.getPriority(), b.getPriority());

    for(; i-- > 0; )
        tmpRenderArray.items[i].render(); //<-- That line

    batch.end();

    //...
}

之前,我已将 tmpRenderArray 大小设置为 gameObjects 大小,以确保有足够的空间。 tmpRenderArray.setSize(gameObjects.size); tmpRenderArray 和 gameObjects 都是使用默认构造函数创建的普通 Array 对象 (com.badlogic.gdx.utils.Array)。没有对这些数组进行指定以外的其他操作。 (调用add方法创建GameObjects除外)

由于我正在向后循环进行渲染,因此不可能渲染空对象。但是,我在指定的行上遇到了 Class Cast 异常,在我看来这“为时已晚”。 Exception in thread "LWJGL Application" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lme.winter.project2d.Renderable;

如果我是对的,[L 表示数组,但我没有强制转换数组。 items 是一个成员变量,因此没有任何操作可以访问它。如何通过访问数组来启动异常?

编辑

感谢 Tenfour04 修复了一个小错误(索引错误),但主要问题仍然存在。我也会考虑使用 Array 对象的 clear 和 add 方法,但现在我想修复这个 bug,或者至少理解它。我已经用那个小修复更新了下面的代码。我并不是说这种渲染方法是最好的,或者它比 Tenfour04 给出的更好。我只是想了解发生了什么。

我使用调试器查看发生了什么:

正如我们所看到的,当 i = 1 时,tmpRenderArray.items[i] 返回一个 Car(它是一个 Renderable),但是当我介入时,我在 catch 子句中被重定向到 LwjglApplication::initialize 并且我获取原始异常。问题仍然是一样的,我的数组在访问它时是如何转换的?我正在访问的数组是纯 java,它是 Array 对象内的成员变量,所以没有我或 LibGDX 运行的任何其他代码。

【问题讨论】:

    标签: java arrays generics intellij-idea libgdx


    【解决方案1】:

    它在documentation of Array 中声明,如果您没有使用明确指定类的 Array 构造函数,则无法访问 items。这是因为泛型类型在运行时被 Java 剥离,因此数组不知道您从 items 访问的对象的类型。 LibGDX Array 提供了对引擎盖下的东西的访问,你很容易误用,我想这样你就可以在需要时高度优化代码。

    替换

    tmpRenderArray.items[i].render();
    

    tmpRenderArray.get(i).render();
    

    它应该可以正常工作,除了 i 的第一个元素上的 IndexOutOfBoundsException 太高(见下文)。


    原始答案——这些错误不是 CCE 的来源

    您的错误是您没有清除临时数组,并且您的 i 比它应该大一,这是由于上部 for 循环中的 i++ 造成的。这个对象不是空的,而是前一帧的一些遗留对象。您需要从-1 开始i 并使用++i 而不是i++。或者在第二个循环之前减 1。

    也就是说,您的某些代码有点复杂。你可以这样简化:

    Gdx.gl.glClearColor(1f, 0.7f, 0.7f, 1f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
    batch.setProjectionMatrix(camera.combined);
    batch.begin();
    
    tmpRenderArray.clear();
    for(Renderable object : gameObjects)
        tmpRenderArray.add(object);
    
    tmpRenderArray.sort(Renderable.PRIORITY_COMPARATOR); //invert this comparator
    //PRIORITY_COMPARATOR = (b, a) -> Float.compare(b.getPriority(), a.getPriority());
    
    for(Renderable renderable : tmpRenderArray)
        renderable.render();
    
    batch.end();
    
    //...
    

    【讨论】:

    • 我想避免清除数组(将数组大小调整为 0)并每次都添加项目(这也会调整数组大小),因为它会在我的笔记本电脑上造成巨大的 fps 下降。从我的角度来看,索引位置错误非常愚蠢。当我明天可以测试时,我会接受你的回答。你知道为什么我得到一个 ClassCastException 而不是 NullPointerException 吗?在我的游戏对象和 tmpRenderArray 中,我只有 Renderables*(或空元素)。 *仅在我的测试用例中,以后会有其他的东西。
    • 如果您还没有引入非 Renderables,我会期待一个 NPE,所以我不确定。这个数组有多大?很难想象游戏中有一个足够大,以至于清除它会对笔记本电脑产生影响。请注意,当您清除 LibGDX 数组类时,它只会将多余的元素清空——它实际上并没有释放底层 Java 数组。
    • FPS 下降是因为我没有清除它。您的解决方案可能对我来说是最好的,主要问题仍未得到解答。我真的很感激,但如果您能够回答主要问题,我只会接受您的回答。
    • 更新了我的答案。 @Winter
    猜你喜欢
    • 2012-04-17
    • 1970-01-01
    • 2018-06-27
    • 2019-12-29
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多