【问题标题】:LibGDX - IllegalArgumentException causes my game to crash whenever my main character touches a CoinLibGDX - IllegalArgumentException 导致我的游戏在我的主角接触硬币时崩溃
【发布时间】:2014-12-16 22:21:55
【问题描述】:

试图找出我的 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

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

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

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

有人知道我的程序为什么会崩溃吗?我只是希望动画硬币在 Player 触摸它时消失。目前硬币确实消失了,但应用程序只是在之后立即关闭。已经坚持了一段时间,因此高度感谢任何见解。

提前谢谢你。

【问题讨论】:

    标签: java animation libgdx 2d collision


    【解决方案1】:

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

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

    缓冲区未分配给 newUnsafeByteBuffer 或已释放。

    当您的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);
    }
    

    【讨论】:

    • 我添加了这个并在代码的其他地方进行了一些更改,现在它可以工作了,谢谢。我决定将 2 个方法 setType(String type) 和 getType() 添加到 GameObject 抽象类,并且在每个对象构造函数(例如 coin)中,我会编写 setType("coin") 或 setType("player") 之类的东西。最后,for 循环要小得多(而且更干净),我用一个来修复 beginRendering 方法中的错误,即使在硬币被移除后,列表的第 3 和第 4 位也始终被视为硬币。再次感谢您的宝贵时间
    • @DeuceDeuce 不要忘记点击接受答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 2016-05-29
    • 2017-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多