【问题标题】:How to have multiple Textboxes travel in random directions with specific time interval between them?如何让多个文本框以特定时间间隔沿随机方向行进?
【发布时间】:2018-10-18 00:12:52
【问题描述】:

我目前正在使用 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 的文档,但对我没有多大帮助。任何帮助是极大的赞赏。谢谢你:)

【问题讨论】:

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


    【解决方案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();
    }
    

    【讨论】:

    • 嘿@fabian,感谢您的回复。我尝试在我的程序中实现此代码,现在根本没有出现任何文字,我不知道为什么。当我检查代码时,它正在做它应该做的事情,但是当我运行程序并单击“开始”按钮时,没有任何文字从顶部掉下来。有什么想法吗?
    • @mdave1701 不是真的。我对此进行了测试,对我来说它完美无缺。您在调试时没有发现任何问题的事实也不能说明问题。调试handle 方法可能会导致帧之间的延迟很长,并且节点可能会在 2 帧内退出屏幕...
    • 我做了一个新项目,实现了这段代码,效果很好。也许问题在于以某种方式将此方法用作 setOnMouseClicked() 事件处理程序?我有一个名为“开始”的按钮,我将此代码用作该按钮的事件处理程序。所以我的猜测是它可能有问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多