如何让多个文本框在随机方向上传播,它们之间有特定的时间间隔?

时间:2018-05-08 06:04:48

标签: java animation javafx javafx-8 game-development

我目前正在使用JavaFX进行类型速度游戏,其中单词应该从顶部开始下降,用户必须在降到最低点之前尽可能快地键入它们。我准备好了游戏的基本设置。我唯一要努力的是如何让单词从顶部掉落并向下移动(目前它们从下到上)。而且我希望在它们之间的特定时间间隔(例如30毫秒)从顶部的随机位置(不是同一个原点)落下多个单词。我到目前为止的代码:

public void showWords() throws InterruptedException
    {
        int missedWords = 0;        // number of words the user failed to type
        while (missedWords != 10)   
        {
            dequedWord = queue.dequeue();           // the word that the Text object will contain
            Text runWord = new Text(dequedWord);

            wordsPane.getChildren().add(runWord);   // the canvas in which the words will travel from top to bottom
            double PaneHeight = wordsPane.getHeight();
            //double PaneWidth = wordsPane.getWidth();
            double runWordWidth = runWord.getLayoutBounds().getWidth();

            KeyValue initKeyValue = new KeyValue(runWord.translateYProperty(), PaneHeight);
            KeyFrame initFrame = new KeyFrame(Duration.ZERO, initKeyValue);

            KeyValue endKeyValue = new KeyValue(runWord.translateYProperty(), -1.0 * runWordWidth);
            KeyFrame endFrame = new KeyFrame(Duration.seconds(12), endKeyValue);

            Timeline timeline = new Timeline(initFrame, endFrame);

            timeline.setCycleCount(1);
            timeline.play();

            // add code to check whether user typed the word in the Text object

            missedWords++;
        }
    }

我是动画新手,所以我对Timeline,KeyValue和KeyFrame类知之甚少。我尝试阅读API的文档,但对我没什么帮助。任何帮助是极大的赞赏。谢谢:))

1 个答案:

答案 0 :(得分:1)

坐标系的y轴指向向下(这在计算机图形学中很常见)。这就是您的节点向错误方向移动的原因。此外,Timeline似乎并不适合这里,因为您需要为每个单词运行Timeline而另一个Timeline用于添加新单词。

我建议使用AnimationTimer,其中包含为每个帧调用的方法,它允许您更新位置,删除旧单词并根据时间添加新单词。

示例:

@Override
public void start(Stage primaryStage) {
    final Queue<String> words = new LinkedList<>(Arrays.asList(
            "Hello",
            "World",
            "foo",
            "bar"
    ));
    final Pane wordsPane = new Pane();
    wordsPane.setPrefSize(800, 400);
    final long wordDelay = 500_000_000L; // 500 ms
    final long fallDuration = 12_000_000_000L; // 12 s

    AnimationTimer animation = new AnimationTimer() {

        private long lastWordAdd = Long.MIN_VALUE; // never added a word before
        private final Map<Text, Long> nodes = new LinkedHashMap<>();

        private double nextX = 0;

        private void assignXPosition(Text text) {
            text.setTranslateX(nextX);
            nextX += text.getBoundsInLocal().getWidth();
        }

        @Override
        public void handle(long now) {
            // updates & cleanup
            long deletionLimit = now - fallDuration;
            for (Iterator<Map.Entry<Text, Long>> iter = nodes.entrySet().iterator(); iter.hasNext();) {
                Map.Entry<Text, Long> entry = iter.next();
                final Text text = entry.getKey();
                final long startTime = entry.getValue();
                if (startTime < deletionLimit) {
                    // delete old word
                    iter.remove();
                    wordsPane.getChildren().remove(text);
                } else {
                    // update existing word
                    double factor = ((double) (now - startTime)) / fallDuration;
                    Bounds bounds = text.getBoundsInLocal();
                    text.setTranslateY((wordsPane.getHeight() + bounds.getHeight()) * factor - bounds.getMaxY());
                }
            }

            if (words.isEmpty()) {
                if (nodes.isEmpty()) {
                    stop(); // end animation since there are no more words
                }
            } else if (lastWordAdd + wordDelay <= now) {
                lastWordAdd = now;
                // add new word
                Text text = new Text(words.remove());
                wordsPane.getChildren().add(text);
                assignXPosition(text);
                text.setTranslateY(-text.getBoundsInLocal().getMaxY());
                nodes.put(text, now);
            }

        }
    };
    animation.start();

    Scene scene = new Scene(wordsPane);

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