java - LibGDX - 每当我的主角接触硬币时,IllegalArgumentException 都会导致我的游戏崩溃

标签 java animation libgdx 2d collision

试图找出为什么每当玩家触摸动画硬币时我的 Android 游戏就会崩溃。我附上了 LogCat 的图像,我的代码如下(注意:![Renderer] 中的所有游戏对象都位于名为 toRender 的数组列表中。2 游戏中的硬币目前位于列表中的第 3 和第 4 位)。分别是 RendererCoin 类:

public class Renderer extends ApplicationAdapter {
    private SpriteBatch batch;
    private Texture background;
    private ArrayList<GameObject> toRender;
    private Timer timer;
    private float delta;
    private Game game;

    public Renderer(ArrayList<GameObject> toRender) {
        batch = new SpriteBatch();
        background = new Texture(Gdx.files.internal("background2.png"));
        this.toRender = toRender;
        timer = Timer.getInstance();
    }

    public void collect() {
        // for every object in toRender (an arraylist of objects)
        for (GameObject o : toRender) {
            // if player collides with/collects an object
            if (Player.getInstance(null).hasCollected(o)) {
                // if its the first coin that he collides with, dispose it
                if (o.equals((Coin) toRender.get(3))) {
                    ((Coin) toRender.get(3)).dispose();
                }
                // if its the second coin that he collides with, dispose it
                if (o.equals((Coin) toRender.get(4))) {
                    ((Coin) toRender.get(4)).dispose();
                }
            }
        }
    }

    public void beginRendering() {
        delta = Timer.getInstance().getTime();
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(background, 0, 0, Gdx.graphics.getWidth(),
                Gdx.graphics.getHeight());
        timer.drawTime(batch);
        for (GameObject object : toRender) {
            object.update();
            boolean objectIsntCoin = !(object.equals(toRender.get(3)) ||
                    object.equals(toRender.get(4))); //the 2 coins are in the 3rd and 4th position in the array list
            // draw every object's sprite apart from coin, since coin should render the animation rather than the sprite
            if (objectIsntCoin) {
                object.draw(batch);
            }
        }
        collect();

        ((Flag) toRender.get(toRender.size() - 1)).drawLevelComplete(batch);
        // if the coin exists (i.e. hasn't been disposed), render the animation
        if (((Coin) toRender.get(3)).checkExists()) {
            ((Coin) toRender.get(3)).render(delta);
        }
        // if the coin exists (i.e. hasn't been disposed), render the animation
        if (((Coin) toRender.get(4)).checkExists()) {
            ((Coin) toRender.get(4)).render(delta);
        }

        batch.end();
    }
}

public class Coin extends GameObject implements Screen {
    private SpriteBatch batch;
    private Animation animation;
    private float time;
    private float xPos;
    private float yPos;
    private Rectangle objectRect;
    private boolean exists;

    public Coin(Sprite spr, float xPos, float yPos, float radius) {
        super(spr, xPos, yPos, radius);
        this.xPos = xPos;
        this.yPos = yPos;
        batch = new SpriteBatch();
        objectRect = new Rectangle(getxPos(), getyPos(), getSprite().getWidth(), getSprite().getHeight());
        exists = true;
        time = 0;
        show();
    }

    public Rectangle getRect() {
        return objectRect;
    }

    public void render(float delta) {
        // TODO Auto-generated method stub
        batch.begin();
        batch.draw(animation.getKeyFrame(time += delta), xPos, yPos);
        batch.end();
    }


    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void show() {
        animation = new Animation(1 / 8f,
                new TextureRegion(new Texture(Gdx.files.internal("coin1.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin2.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin3.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin4.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin5.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin6.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin7.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("coin8.png"))));
        animation.setPlayMode(Animation.PlayMode.LOOP);
    }

    @Override
    public void hide() {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
        batch.dispose();
        exists = false;
    }

    public boolean checkExists() {
        return exists;
    }
}

LogCat:1

enter image description here

LogCat 指向的错误: 1)Coin中的dispose()方法: 批处理.dispose();

2)渲染器中的collect()方法: if(o.equals((Coin) toRender.get(3))) {

3)渲染器中的beginRendering()方法: for (GameObject 对象: toRender) {

有谁知道为什么我的程序崩溃了?我只是希望动画硬币在玩家触摸它时消失。目前,硬币确实消失了,但应用程序只是在之后立即关闭。已经在这个问题上停留了一段时间,所以任何见解都高度值得赞赏。

提前谢谢您。

最佳答案

首先,我想提一下 toRender 中对象的向下转型像你这样既危险又表明你的设计存在缺陷。此外,您会注意到equals(Object)接受一个对象作为参数;您不需要将其转换到 Coin .

无论如何,IllegalArgumentException 消息中解释了程序崩溃的原因,

buffer not allocated with newUnsafeByteBuffer or already disposed.

您正在尝试处置您的 Coin的批处理已经已被处置。

在您的 collect() 中方法,您循环遍历对象,并处理它们的批处理,但是 Coin对象本身永远不会从您的 toRender 中删除列表。那么,下次collect()被调用时,它将循环遍历那些相同的 Coin对象并再次尝试处理它们,并抛出异常。

解决方案是删除 Coin来自您的toRender的对象当它们不再属于您的游戏场景时列出。但是,在迭代列表时无法从列表中删除元素,因为这会破坏循环。相反,像这样删除它们:

public void collect() {
    // Holds the Coins we want to remove from toRender
    final Collection<GameObject> toRemove = new LinkedList<>();

    for (GameObject o : toRender) {
        if (Player.getInstance(null).hasCollected(o)) {
            if (o.equals(toRender.get(3))) {
                final Coin coin = (Coin) toRender.get(3);
                coin.dispose();
                toRemove.add(coin);
            }
            if (o.equals(toRender.get(4))) {
                final Coin coin = (Coin) toRender.get(4);
                coin.dispose();
                toRemove.add(coin);
            }
        }
    }

    // Remove the collected Coins
    toRender.removeAll(toRemove);
}

关于java - LibGDX - 每当我的主角接触硬币时,IllegalArgumentException 都会导致我的游戏崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27515056/

相关文章:

java - Spring - 配置 apache commons 电子邮件

Java HashMap 数组大小

jquery - -webkit-transition/-moz-transition 与 jQuery

css - 通过CSS3 anchor 旋转SVG而不是在中间

android - 如何在 LibGDx 中加载图像作为背景?

opengl - 扩展和性能

java - 纹理未显示在应用程序中

java - 在某些条件下无法打印正确的结果

java - child 的 id 不是在保留时从 parent 分配的

ios - UISnapBehavior 奇怪的摇晃 - swift