【问题标题】:JavaFX Animation - Specifics Re. How To ImplementJavaFX 动画 - 细节重新。如何实施
【发布时间】:2015-05-03 17:19:41
【问题描述】:

我有一些代码可以自动避免随机游走:

package event_handling;

import java.util.ArrayList;
import java.util.Random;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class SelfAvoidingRandomWalk extends Application {

int latticeSize;
int scale;
double initialX, initialY;
double currentX, currentY;
ArrayList<Line> lines;
ArrayList<String> moveDirections;
String chosenDirection;
Pane pane;

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

@Override
public void start(Stage primaryStage) throws Exception {

    Random random = new Random();
    pane = new Pane();
    Button start = new Button("Start");

    latticeSize = 16;
    scale = 30;

    initialX = latticeSize * scale / 2;
    initialY = latticeSize * scale / 2;

    currentX = initialX;
    currentY = initialY;

    lines = new ArrayList<>();
    moveDirections = new ArrayList<>();

    chosenDirection = "";

    Line[] horizontalGridLines = new Line[latticeSize + 1];
    Line[] verticalGridLines = new Line[latticeSize + 1];

    //Draw gridlines
    for (int a = 0; a < latticeSize + 1; a++) {
        Line l = new Line(0, a * scale, latticeSize * scale, a * scale);
        l.setStroke(Color.LIGHTGRAY);
        horizontalGridLines[a] = l;
    }

    for (int a = 0; a < latticeSize + 1; a++) {
        Line l =  new Line(a * scale, 0, a * scale, latticeSize * scale);
        l.setStroke(Color.LIGHTGRAY);
        verticalGridLines[a] = l;
    }

    pane.getChildren().addAll(horizontalGridLines);
    pane.getChildren().addAll(verticalGridLines);

    BorderPane bPane = new BorderPane();

    bPane.setCenter(pane);
    bPane.setBottom(start);

    BorderPane.setAlignment(start, Pos.CENTER);

    start.setOnMouseClicked(e -> {

        pane.getChildren().removeAll(lines);
        lines.clear();
        initialX = latticeSize * scale / 2;
        initialY = latticeSize * scale / 2;

        currentX = initialX;
        currentY = initialY;

        while (noNodeTouchesBorders() && validMoveExists()) {

            //Check which directions are empty
            buildValidMovesList();

            //Choose from the available directions
            chosenDirection = moveDirections.get(random.nextInt(moveDirections.size()));

            //Make the move
            makeMove();

            //Reset list of possible moves
            moveDirections = new ArrayList<>();

        }

        System.out.println("Finished walk.");

        if (noNodeTouchesBorders()) {
            System.out.println("Dead end.");
        } else {
            System.out.println("Reached exit.");
        }
    });

    Scene scene = new Scene(bPane, latticeSize * scale, latticeSize * scale + 30);

    primaryStage.setTitle("Self-avoiding Random Walk");
    primaryStage.setScene(scene);
    primaryStage.show();

}

private boolean noNodeTouchesBorders() {

    if (currentX == 0 || currentY == 0 || currentX == latticeSize * scale || currentY == latticeSize * scale) {
        return false;
    }

    return true;

}

private boolean validMoveExists() {

    //We have coordinates, and need to check if there are existing lines in the relevant ArrayList with the same endpoint/startpoint.

    boolean blocksUp = false;
    boolean blocksDown = false;
    boolean blocksLeft = false;
    boolean blocksRight = false;

    //For each line,
    for (Line l : lines) {

        //Check if this line blocks in some direction
        if (blocksUp(l)) {
            blocksUp = true;
        }

        if (blocksDown(l)) {
            blocksDown = true;
        }

        if (blocksLeft(l)) {
            blocksLeft = true;
        }

        if (blocksRight(l)) {
            blocksRight = true;
        }

    }

    if (blocksUp && blocksDown && blocksLeft && blocksRight) {
        return false;
    }

    return true;

}

private boolean blocksUp(Line l) {

    if ((l.getStartX() == currentX && l.getStartY() == currentY - scale) || (l.getEndX() == currentX && l.getEndY() == currentY - scale)) {
        return true;
    }

    return false;

}

private boolean blocksDown(Line l) {

    if ((l.getStartX() == currentX && l.getStartY() == currentY + scale) || (l.getEndX() == currentX && l.getEndY() == currentY + scale)) {
        return true;
    }

    return false;

}

private boolean blocksLeft(Line l) {

    if ((l.getStartX() == currentX - scale && l.getStartY() == currentY) || (l.getEndX() == currentX - scale && l.getEndY() == currentY)) {
        return true;
    }

    return false;

}

private boolean blocksRight(Line l) {

    if ((l.getStartX() == currentX + scale && l.getStartY() == currentY) || (l.getEndX() == currentX + scale && l.getEndY() == currentY)) {
        return true;
    }

    return false;

}

private void buildValidMovesList() {

    moveDirections.add("Up");
    moveDirections.add("Down");
    moveDirections.add("Left");
    moveDirections.add("Right");

    for (Line l : lines) {
        if (blocksUp(l)) {
            moveDirections.remove("Up");
        }

        if (blocksDown(l)) {
            moveDirections.remove("Down");
        }

        if (blocksLeft(l)) {
            moveDirections.remove("Left");
        }

        if (blocksRight(l)) {
            moveDirections.remove("Right");
        }
    }

}

private void makeMove() {

    switch (chosenDirection) {
        case "Up" :     moveUp();       break;
        case "Down" :   moveDown();     break;
        case "Left" :   moveLeft();     break;
        case "Right" :  moveRight();    break;
    }

}

private void moveUp() {

    //Create new line
    Line l = new Line(currentX, currentY, currentX, currentY - scale);

    //Add a new line to the lines ArrayList
    lines.add(l);

    //Add the new line to the pane
    pane.getChildren().add(l);

    //Set new currentY
    currentY = currentY - scale;

    System.out.println("Went up.");

}

private void moveDown() {

    //Create new line
    Line l = new Line(currentX, currentY, currentX, currentY + scale);

    //Add a new line to the lines ArrayList
    lines.add(l);

    //Add the new line to the pane
    pane.getChildren().add(l);

    //Set new currentY
    currentY = currentY + scale;

    System.out.println("Went down.");

}

private void moveLeft() {

    //Create new line
    Line l = new Line(currentX, currentY, currentX - scale, currentY);

    //Add a new line to the lines ArrayList
    lines.add(l);

    //Add the new line to the pane
    pane.getChildren().add(l);

    //Set new currentX
    currentX = currentX - scale;

    System.out.println("Went left.");

}

private void moveRight() {

    //Create new line
    Line l = new Line(currentX, currentY, currentX + scale, currentY);

    //Add a new line to the lines ArrayList
    lines.add(l);

    //Add the new line to the pane
    pane.getChildren().add(l);

    //Set new currentX
    currentX = currentX + scale;

    System.out.println("Went right.");

}

}

目前,每次单击“开始”按钮时,都会完成一次模拟。可以说是程序的完整运行。

我的任务是为这个程序制作动画。所以我想在自己的框架中显示每条绘制的线。

我不知道该怎么做。我尝试并弄乱了代码。我知道我可能应该使用 KeyFrames 和事件处理程序......不知何故。 (我之前做过简单的动画,但代码没有这么复杂。不需要步进,或者我使用的是现有的过渡。)

我觉得我的代码有点弱,因为逻辑都与 UI 在一起。不确定这在实现动画时是否重要。

你能指导我如何去做吗?

【问题讨论】:

    标签: java animation javafx


    【解决方案1】:

    您可以像这样将您的 while 循环包装在 AnimationTimer 中:

    start.setOnMouseClicked(e -> {
    
        pane.getChildren().removeAll(lines);
        lines.clear();
        initialX = latticeSize * scale / 2;
        initialY = latticeSize * scale / 2;
    
        currentX = initialX;
        currentY = initialY;
    
        AnimationTimer timer = new AnimationTimer() {
    
            long prevTime = 0;
    
            @Override
            public void handle(long now) {
    
                // some delay
                if ((now - prevTime) < 50_000_000) {
                    return;
                }
    
                prevTime = now;
    
                if (noNodeTouchesBorders() && validMoveExists()) {
    
                    // Check which directions are empty
                    buildValidMovesList();
    
                    // Choose from the available directions
                    chosenDirection = moveDirections.get(random.nextInt(moveDirections.size()));
    
                    // Make the move
                    makeMove();
    
                    // Reset list of possible moves
                    moveDirections = new ArrayList<>();
    
                } else {
    
                    stop();
    
                    System.out.println("Finished walk.");
    
                    if (noNodeTouchesBorders()) {
                        System.out.println("Dead end.");
                    } else {
                        System.out.println("Reached exit.");
                    }
                }
    
            }
        };
    
        timer.start();
    
    });
    

    【讨论】:

    • 谢谢罗兰!我最终用Thread.sleep(50) 代替了延迟,否则你的建议正是我想要的。
    • 在这种情况下重要吗?我不需要在这个应用程序运行时与用户界面交互......
    • 阻止用户界面是非常糟糕的做法,一般情况下应该避免它。如果添加 e。 G。动画的取消按钮,那么你会遇到麻烦。
    猜你喜欢
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2017-01-04
    • 2019-05-22
    相关资源
    最近更新 更多