【问题标题】:Java libGDX Array corruptionJava libGDX 数组损坏
【发布时间】:2020-06-26 01:51:39
【问题描述】:

我正在尝试制作一个精美的新 ui 小部件,一个可以在演员之间滚动的边缘轮播:

在上图中,它应该从左边数到 99,然后从 0 开始向右移动。相反,我得到了一些明显的数组损坏。

代码跟踪哪个索引应该在显示中位于前面的中心 (getIndexOfFocus())。由于渲染顺序的挑战,我首先在一个循环中遍历该元素上方的所有元素,然后从数组的开头开始第二个循环,直到并包括中心元素(在所示的示例图片中,中心元素是 6):

    SnapshotArray<Actor> children = getChildren();
    children.end();

    int n = children.size;
    for (int i = getIndexOfFocus() + 1; i < n; i++) {
        actorSubProcessing(children, i, rowHeight, startY, x);
    }
    
    for (int f = 0; f<= getIndexOfFocus(); f++) {
        actorSubProcessing(children, f, rowHeight, startY, x);
        //children.get(i).toFront();
    }

如果我注释掉第一个循环,元素 0-6 会正确显示,而不是 56-50 和 6 在角落弹出。在 actorSubProcessing 方法中,我做了三件事来直接影响 children 数组的元素:

    child.setScaleX(child.getScaleX() * scalingAgent); 
    child.setScaleY(child.getScaleY() * scalingAgent);  

    if (round)
        child.setBounds(Math.round(x), Math.round(y), Math.round(width), Math.round(height));
    else
        child.setBounds(x, y, width, height);

    if (offset > 0)
        child.toBack();

我知道 libGDX 数组的特殊之处在于它们会限制垃圾回收,但为什么要在数组的后期处理元素会在数组的早期更改元素呢?顺便说一句,getChildren() 来自 ui.Horizo​​ntalDisplay,我在修改为这个新小部件之前对其进行了镜像

我在解决方案中的一个尝试是弄清楚如何克隆数组,但即使我可以想象小部件确定要呈现的内容也会很混乱。我也一直在通过API。我希望能够重新排列我的数组元素的顺序;我认为将显示在中心的元素作为数组中的最后一个元素会有一定的优雅。然后我可以在数组中做一个循环,从开始到数组。我看到您可以使用“比较器”对数组进行排序,但不理解我在那里阅读的内容,不知道这是否是重新排列数组顺序的途径。

【问题讨论】:

    标签: java arrays libgdx


    【解决方案1】:

    当您对孩子调用 toBack() 时,它正在重新排序 Group 的孩子数组。如果您在迭代孩子时这样做,这可能会变得混乱。 SnapshotArray 的设计目的是让您可以使用阵列的临时副本,该副本不受对 SnapshotArray 的修改的影响。完成后,临时副本会返回到池中,以便最大限度地减少分配/解除分配。

    我不确定你的代码的上下文是什么,因为你在使用它之前就在上面调用children.end() 很奇怪。

    你应该像这样使用 SnapshotArray:

    Actor[] children = getChildren().begin();
    
    int n = children.size;
    for (int i = getIndexOfFocus() + 1; i < n; i++) {
        actorSubProcessing(children, i, rowHeight, startY, x);
    }
    
    for (int f = 0; f<= getIndexOfFocus(); f++) {
        actorSubProcessing(children, f, rowHeight, startY, x);
        //children.get(i).toFront();
    }
    
    children.end();
    

    您的actorSubProcessing 需要修改以使用Actor[] 而不是SnapshotArray&lt;Actor&gt;。

    您可能遇到问题的另一个方面是您正在使用的索引。如果您只是使用孩子数组中每个孩子的索引,那么随着您移动他们的 Z 顺序,这将不断变化。你需要给他们每个人一个永久的标识符。在您添加完所有索引后,您的父母可以将他们的索引分配给他们的 userObject 属性:

    for (int i=0; i<getChildren().size; i++)
        getChildren().get(i).setUserObject((Integer)i);
    

    然后像这样检索它们:

    int originalIndex = (Integer)child.getUserObject();
    

    我建议一种更简单的算法,您可以按最接近的方式对子项进行排序,并在一次操作中将它们全部填充回子项 SnapshotArray。然后就不必对它们每个都调用toBack(),这真的很昂贵,因为你要为每个孩子重新排序一次数组。

    Actor[] children = getChildren().begin();
    
    // Iterate all children to scale and position them here like you were doing with 
    // your actorSubProcessing method, but don't call toBack() on them.
    
    Arrays.sort(children, comparator); 
    // where comparator compares -abs(originalIndex - indexOfFocus) (psuedo code)
    // This will sort them from farthest to nearest.
    
    getChildren().clear();
    getChildren().addAll(children); // adding back the same ones, but in sorted order
    getChildren().end();
    

    【讨论】:

    • 谢谢你,我从你的回答中学到了很多。虽然没有完全实现您的解决方案,因为我现在坚持 setUserValue(Integer) 设置一个空值。我为这个难题提出了一个新问题:stackoverflow.com/questions/62598312/…
    猜你喜欢
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多