Java libGDX 数组损坏

Java libGDX Array corruption

我正在尝试制作一个精美的新 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 方法中,我做了三件事来直接影响子数组的元素:

    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.HorizontalDisplay,我在修改为这个新小部件之前对其进行了镜像

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

当您在 child 上调用 toBack() 时,它正在重新排序组的 children 数组。如果您在迭代 children 时这样做,这可能会变得混乱。 SnapshotArray 旨在让您可以使用数组的临时副本,该副本不会对 SnapshotArray 进行修改。临时副本在您完成后返回到池中,因此它最小化 allocations/deallocations.

我不确定你的代码的上下文是什么,因为你在使用它之前调用 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<Actor>

您可能遇到问题的另一个方面是您正在使用的索引。如果您只是简单地使用 children 数组中每个 child 的索引,那么随着您移动它们的 Z 顺序,它会不断变化。您需要给他们每个人一个永久标识符。您的 parent 可以在您添加所有索引后立即将它们的索引分配给它们的 userObject 属性:

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

并像这样检索它们:

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

我建议使用一种更简单的算法,您可以根据最接近的内容对 children 进行排序,并在一个操作中将它们全部填回 children SnapshotArray。然后它就不必在每个 toBack() 上调用,这真的很昂贵,因为您要为每个 child.

重新排序一次数组
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();