有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何正确删除JavaFX中动画的图像

我试图创建一个简单的太空入侵者游戏。这是我第一次参加比赛,所以我有一些问题。入侵者是一个矩形的物体,上面有一个老式入侵者的图像。在每一帧中,我将这些框向右绘制15个像素,然后使用root。getChildren()。remove(),以删除每个帧中的精灵。但它会导致一些奇怪的行为。它看起来好像没有足够快地被移除,所以就在我启动应用程序的时候,它有点爆炸,之后似乎有一点延迟,导致两个图像不断显示

我想这可能会帮助你看到它自己,所以我会张贴我的所有文件在这里

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Space invaders");
        primaryStage.setResizable(false);
        Group root = new Group();
        Scene game = new Scene(root, Color.BLACK);
        primaryStage.setFullScreen(true);

        Images images = new Images();

        // Make canvas and add it to primaryStage
        Canvas canvas = new Canvas(1280,720);
        root.getChildren().add(canvas);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        new AnimationTimer() {

            int move = 0;
            private long lastUpdate = 0;
            ArrayList<Sprite> enemies = new ArrayList<>();

            @Override
            public void handle(long now) {

                if (now - lastUpdate >= 150_000_000) {

                    int spacing = 0;

                    try {
                        for (int i = 0; i < enemies.size(); i++) {
                            root.getChildren().remove(enemies.get(i));
                            enemies.remove(i);
                        }
                    } catch (IndexOutOfBoundsException ioobe) {
                        System.out.println(ioobe.toString());
                    }

                    for (int i = 0; i < 12; i++) {
                        for (int j = 0; j < 6; j++) {
                            Sprite enemy = new Sprite(60 * i + spacing + move, 43 * j, 60, 43, "enemy", true, images.getEnemy1());
                            enemies.add(enemy);
                            root.getChildren().add(enemy);
                        }
                        spacing += 15;
                    }
                    move += 5;

                    lastUpdate = now;

                }
            }
        }.start();

        primaryStage.setScene(game);
        primaryStage.show();
    }
}

如果您想自己运行该程序,则她是Sprite类:

public class Sprite extends Rectangle {

    private String type;
    private Boolean alive;

    public Sprite(int x, int y, int w, int h, String type, boolean alive, Image image) {
        this.setTranslateX(x);
        this.setTranslateY(y);
        this.setWidth(w);
        this.setHeight(h);
        this.type = type;
        this.alive = alive;
        this.setFill(new ImagePattern(image));
    }

    public String getType() {
        return type;
    }

    public Boolean getAlive() {
        return alive;
    }
}

共 (2) 个答案

  1. # 1 楼答案

    try {
        for (int i = 0; i < enemies.size(); i++) {
            root.getChildren().remove(enemies.get(i));
            enemies.remove(i);
        }
    } catch (IndexOutOfBoundsException ioobe) {
        System.out.println(ioobe.toString());
    }
    

    正确的实现不需要捕获IndexOutOfBoundsException。我不知道为什么会抛出这样的异常,因为检查i < enemies.size()应该确保索引是有效的

    但是请注意,这会跳过其他每个列表元素:

    首先,从两个列表中删除enemies的第一个元素(索引0处的元素)。这将导致enemies列表中剩余的所有元素向左移动,即删除之前位于索引1的元素现在位于索引0。由于在每次循环迭代后增加索引,因此将跳过奇数索引处的所有元素

    顺便说一句,有一种更简单的实现方法:

    root.getChildren().removeAll(enemies);
    enemies.clear();
    

    应该避免在每个帧中重新创建精灵。如果可以避免的话,Node的内存需求不会使它们成为您应该扔掉的对象。否则,垃圾收集器最多只能忙于清理您“扔掉”的对象,最坏的情况是发生OutOfMemoryException
    重新使用精灵并修改属性

    我还建议使用ImageView而不是用ImagePattern填充的Rectangle。您可以使用fitWidthfitHeight属性调整大小

  2. # 2 楼答案

    这不是场景图应该使用的方式。为什么你总是移除并重新添加你的精灵?你为什么不通过你已经在使用的setTranslateX/Y更新他们的位置呢