从Libgdx表中删除行时出错

时间:2015-10-11 19:21:39

标签: java arrays libgdx row

我想使用LibGDX编写一个棋盘游戏,在游戏中我希望能够在该棋盘上添加或删除行/列。首先,我做了一些测试,为此做好准备。这是代码:

public class Test extends Game {

    Skin skin;
    Stage stage;
    Texture texture1;
    static int columns = 7;
    static int rows = 12;
    Window window2;
    Table table2;
    ArrayList<ArrayList<TextButton>> buttons;

    @Override
    public void create () {

        skin = new Skin(Gdx.files.internal("data/uiskin.json"));
        buttons = new ArrayList<ArrayList<TextButton>>();

        for(int i = 0 ; i< rows; ++i)
        {
            buttons.add(new ArrayList<TextButton>());
            for( int k = 0; k < columns; ++k)
            {
                buttons.get(i).add(new TextButton(("ASD" + i + k), skin));
            }
        }

        texture1 = new Texture(Gdx.files.internal("data/badlogicsmall.jpg"));
        TextureRegion image = new TextureRegion(texture1);
        stage = new Stage(new ScreenViewport());
        Gdx.input.setInputProcessor(stage);

        ImageButtonStyle style = new ImageButtonStyle(skin.get(ButtonStyle.class));
        style.imageUp = new TextureRegionDrawable(image);
        ImageButton iconButton = new ImageButton(style);



        window2 = new Window("Dialog2", skin);
        window2.getTitleTable().add(new TextButton("X", skin)).height(window2.getPadTop());
        window2.setSize(300, 400);

        table2 = new Table();

        for(int i = 0 ; i< rows; ++i)
        {
            for( int k = 0; k < columns; ++k)
            {
                table2.add(buttons.get(i).get(k));
            }
            table2.row();
        }

        ScrollPane pane= new ScrollPane(table2,skin);
        pane.setScrollbarsOnTop(false);
        pane.setFadeScrollBars(false);

        window2.add(iconButton).row();
        window2.add(pane);
        stage.addActor(window2);

        iconButton.addListener(new ChangeListener() {
            public void changed (ChangeEvent event, Actor actor) {
                new Dialog("Some Dialog", skin, "dialog") {
                    protected void result (Object object) {
                        System.out.println("Chosen: " + object);
                        if((Boolean) object )
                        {
                            for(int i = 0 ; i <columns; ++i){
                                table2.getCells().removeIndex(0).getActor().remove();}  
                        }
                    }
                }.text("Are you enjoying this demo?").button("Yes", true).button("No", false).key(Keys.ENTER, true)
                    .key(Keys.ESCAPE, false).show(stage);
            }
        });

    }




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

        stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));

        stage.draw();
    }

正如您在此处所见,我创建了一个独立按钮和一个表格,并用按钮填充它。然后在单击按钮后,我想删除该表的第一行,并将其余行向上移动。它只能工作一次(第一行),然后(第二次点击)我得到了这个例外:

Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: index can't be >= size: 70 >= 70

不知道该怎么做以及如何解决它。希望你能帮助我。

更新

感谢您的回复;我的代码现在看起来像这样:

  // initialization 
    for(int i = 0 ; i< rows; ++i)
    {
        for( int k = 0; k < columns; ++k)
        {
            table2.add(new TextButton(("ASD" + i + k), skin));
        }
        table2.row();
    }

   // sample operation - remove left column
       for(int i = 0 ; i <rows; ++i){
            table2.removeActor( table2.getChildren().get(i*columns-i) );
        }   
    columns--;

另外,我在逻辑模型中得到了类似的Array,并希望根据该数组更改UI表的状态。那么这种方法是正确的还是应该改变一些东西?

2 个答案:

答案 0 :(得分:0)

以这种方式使用桌子有点麻烦,至少我不知道更好。您的代码的快速修复将是:

// Global field
int removedRows = 0;

// In your listener
System.out.println("Chosen: " + object);
if ((Boolean) object)
{
    for (int i = 0; i < columns; ++i)
    {
        table2.getCells().get(i + columns * removedRows).clearActor();
    }

    removedRows++;
}

但是如果你想删除完整的行,我会使用VerticalGroup并在那里添加每一行,这样你就可以直接访问一行并从VerticalGroup中删除它。如果按钮使用固定尺寸,那么它也会正确对齐。

table2.getCells()

返回一个数组,这意味着我们现在对该数组进行操作而不再对table2进行操作!

这意味着如果执行此操作:     table2.getCells()removeIndex(0)。 它只会从数组中删除该单元格。这不会将table2更新为完整对象,只更新该表的单元格数组(因为没有返回该数组的副本)

换句话说,你这样做:

Array<Cell> table2Cells = table2.getCells();

Cell tableCell = table2Cells.removeIndex(0);

tableCell.clearActor();

因此,您从table2单元格数组中删除单元格,然后清除单元格内容(在本例中为actor)。但是你没有更新表来反映删除的单元格的变化,table2仍然&#34;认为&#34;单元格在那里,但你删除了它。

因此你得到索引错误,因为舞台绘制了表格,而表格想要绘制一个不再存在的单元格。

因此,如果您想为游戏创建某种类型的棋盘,最好的方法是编写您自己的类,提供您想要的功能。

解决方法是重置表格并重新填写:

int table2Rows = table2.getRows();

table2.reset();

// Omit the first row
for (int i = rows - table2Rows + 1; i < rows; ++i)
{
    for (int k = 0; k < columns; ++k)
    {
        table2.add(buttons.get(i).get(k));
    }
    table2.row();
}

table2.layout();

因此第一个单元格将包含第一个按钮,依此类推,因为表格内部值已正确更新。

答案 1 :(得分:0)

问题是关于你正在使用的 row() - 在第一行之前没有行单元格(用row()方法标记),这就是它的原因不会导致错误,但在删除第二个时会发生错误。

table2 比较,没有任何行进行测试:

    for(int i = 0 ; i< rows; ++i)
    {
        for( int k = 0; k < columns; ++k)
        {
            table2.add(buttons.get(i).get(k));
        }
        //table2.row(); - we don't want any rows!
    }

好的,我们知道问题在哪里,但它不是解决方案(好吧可能是一些解决方案:))。您应该使用以下代码操作表的Actors,而不是硬删除表格单元格的索引

    for(int i = 0 ; i <columns; ++i){
        table2.removeActor( table2.getChildren().first() );
    }