【问题标题】:Delay function does not work properly?延时功能不能正常工作?
【发布时间】:2016-06-28 21:50:55
【问题描述】:

我是这个社区的新手,我遇到了一个我自己似乎无法解决的问题,即使在搜索谷歌和向朋友寻求答案时也是如此。

我正在制作一个小型模式记忆游戏,它围绕按特定顺序单击按钮展开,每次成功都会变得越来越难,直到失败。设置是通过 javafx GUI 进行的,IDE 是 NetBeans 8.1。

现在,例如,当通过按钮发光向玩家显示序列时,需要在序列中的每个按钮和下一个按钮之间存在延迟,以便玩家知道他们点击的顺序按钮。 我尝试了三个延迟函数,但都产生相同的结果,它们是 Thread.sleep 、 Timelines 和 Transitions。

如上图所示,此 for 循环随机选择游戏中的 5 个按钮之一,并使其发光,以便玩家知道这是序列中的下一个按钮。所有这些都发生在循环的每次迭代中创建的新时间轴内,因此每次选择和显示按钮时都会发生延迟。

但是,当我执行这部分代码时,我看到的情况很奇怪。 for 循环存在于按钮事件处理程序中。当我单击此按钮时,我确实看到了延迟,但不是在序列中的每个按钮和下一个按钮之间,而是在单击按钮和同时显示整个序列之间的延迟。

那么我该如何让这个延迟按预期工作呢?据我所知,Timeline 是实现延迟的最佳方法之一,而不是不可靠的 Thread.sleep 方法,后者在您执行代码时会大大降低您的设备速度。

作为参考,第一、第二、第三、第四和第五是按钮的名称。 storebutton 函数存储当前按钮的位置,供以后在游戏中参考(可以忽略那句话,它不影响延迟的实现),borderglow 是按钮发光效果,generator 是来自 Random 类的对象生成一个介于 0 和 5 之间的随机整数。

请花点时间考虑这个问题,这很令人困惑,我无法解决这个问题。在你的 IDE 中尝试这个想法,甚至可以更好地理解问题。任何帮助将不胜感激。提前致谢:)

【问题讨论】:

  • 我是这个社区的新手。欢迎。请不要发布代码图片。贴出实际代码。另外,请阅读minimal reproducible example

标签: java for-loop javafx delay timeline


【解决方案1】:

PauseTransition 可用于此目的。如有必要,您可以使用 onFinished 事件处理程序来更新 UI 并重播过渡:

List<Button> buttons = ...

// list of glowing indices
List<Integer> indices = Arrays.asList(0, 3, 2, 1, 3, 1);

PauseTransition transition = new PauseTransition(Duration.seconds(1));

EventHandler<ActionEvent> handler = new EventHandler<ActionEvent>() {

    private int currentIndex = 0;
    private final Iterator<Integer> iterator = indices.iterator();
    private final Effect effect = new Glow(200);

    @Override
    public void handle(ActionEvent event) {
        buttons.get(currentIndex).setEffect(null);
        if (iterator.hasNext()) {
            currentIndex  = iterator.next();
            buttons.get(currentIndex).setEffect(effect);
            transition.play();
        }
    }

};

transition.setOnFinished(handler);

// activate first button & start animation
handler.handle(null);

【讨论】:

    【解决方案2】:

    调用Timeline#play 会运行Timeline,但会立即返回。您正在有效地创建多个单独的时间线,并且几乎同时运行它们。

    要达到预期的效果,您有几个选择:

    1. 创建一个单独的时间线,将KeyFrames 添加到它,每个时间线都有更高的时间目标:

      Timeline timeline = new Timeline();
      for (int i=0; i<buttoncount; i++) {
          timeline.getKeyFrames().add(new KeyFrame(Duration.millis((i+1)*1000), e -> {
              // Change highlighted button
          });
      } 
      timeline.play();
      

    这将创建一个TimelineKeyFrames,目标时间为 1000、2000、3000 ... 毫秒。

    1. 用一个固定时间的KeyFrame创建一个时间线,并多次运行:

      Timeline timeline = new Timeline(new KeyFrame(Duration.millis(1000), e -> {
          // This will be called multiple times, each time reset the highlighted button and select a new one to highlight
      }));
      timeline.setCycleCount(buttoncount);
      timeline.play();
      

    【讨论】:

    • 我对这些建议表示最诚挚的感谢,我尝试了 sillyfly 的第二个选项,它神奇地修复了它。我猜你是对的,所有正在创建的时间线几乎都是立即运行的。谢谢你,保持真棒! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 2017-09-23
    相关资源
    最近更新 更多