Javafx 为什么在使用peek()操作时,流中只有一个元素接收EventHandler?

Javafx 为什么在使用peek()操作时,流中只有一个元素接收EventHandler?,javafx,concurrency,java-stream,keylistener,observer-pattern,Javafx,Concurrency,Java Stream,Keylistener,Observer Pattern,我正在写一个蛇的游戏,并试图实现蛇的运动。目前,蛇的头部根据箭头板输入完美移动,但它独立于蛇的其余部分移动。对我来说,这似乎是因为控制蛇运动的关键帧对象的实例化和通过(在peek()操作中执行)只对蛇的头部发生一次,而不是对每个片段 snake片段是矩形类的扩展,称为Segment 下面是我创建所有关键帧并将其传递给分段的代码: public class Snake extends Group { private static final Duration STA

我正在写一个蛇的游戏,并试图实现蛇的运动。目前,蛇的头部根据箭头板输入完美移动,但它独立于蛇的其余部分移动。对我来说,这似乎是因为控制蛇运动的关键帧对象的实例化和通过(在peek()操作中执行)只对蛇的头部发生一次,而不是对每个片段

snake片段是矩形类的扩展,称为Segment

下面是我创建所有关键帧并将其传递给分段的代码:

    public class Snake extends Group
    {
        private static final Duration STANDARD_DURATION = Duration.millis(150);
        private final Timeline timeline = new Timeline();

        private final Segment[] snakeFrame =
                {
                        new Segment( new Rectangle(250, 250, 25, 25) ),
                        new Segment( new Rectangle(225, 250, 25, 25) ),
                        new Segment( new Rectangle(200, 250, 25, 25) ),
                        new Segment( new Rectangle(175, 250, 25, 25) ),
                        new Segment( new Rectangle(150, 250, 25, 25) ),
                };



        public Snake()
        {
            timeline.setCycleCount(Animation.INDEFINITE);

            getChildren().addAll(FXCollections.observableList
                    (
                    Arrays.stream(snakeFrame)
                            .peek(Segment ->
                            {
                                Segment.setFill(Color.DARKBLUE);
                                Segment.setStroke(Color.ORANGE);
                                Segment.setFrame(new KeyFrame(STANDARD_DURATION,
                                        event ->
                                        {
                                            getScene().setOnKeyPressed(keyEvent -> Segment.changeDirection(keyEvent.getCode()));
                                            Segment.move();
                                        }));
                                timeline.getKeyFrames().add(Segment.getFrame());
                            })
                            .collect(Collectors.toList())
                    )
            );
        }

      public void play()
      {
          timeline.play();
      }
    }

为什么这只会将关键帧附加到列表的头部部分而不是每个部分?

来自Malte Hartwig的上述评论:


“我看到您通过调用
getScene().setOnKeyPressed()来设置侦听器
。如果这遵循常见的Java命名约定,那么对于每个后续段,您将替换为上一段附加的侦听器。这将解释为什么最后只有一段侦听按键笔划。相反,您可以尝试放置
getScene().setOnKeyPressed(e->snakeFrame.forEach)(s->s.changeDirection(e.getCode()))
在流之外,为整个蛇提供一个侦听器。”


一旦我按照这些说明进行操作,每个片段都会对键盘输入做出响应。认真地说,我不知道你在做什么。为什么要在每一帧上设置一个新的关键点事件?最重要的是,你有一个
时间线
,每个
片段
对象都有一个
关键帧这意味着
时间线
将每隔
标准持续时间
移动一个
。当我运行我的程序时,蛇的所有5段都移动,但只有一段改变方向。我一直无法让任何段接收方向输入,所以这对我来说有点像是一个中断。我看到你设置了l通过调用
getScene().setOnKeyPressed()
来侦听。如果这遵循常见的Java命名约定,那么对于每个后续段,您将替换为上一段附加的侦听器。这将解释为什么最后只有一段侦听按键笔划。相反,您可以尝试放置
getScene().setOnKeyPressed(e->snakeFrame.forEach(s->s.changeDirection(e.getCode()))
在流外部为整个蛇设置一个侦听器。为什么在这里滥用
peek
?它既不会使代码更简单,也不会提高效率。您可以使用
数组.asList(snakeFrame)
获取
列表
,无需任何复制开销。然后,只需迭代列表并执行您的操作。如果您想不惜一切代价引入lambda,您可以使用
forEach
(仍然不需要流API)。操作保持不变,所有用于不必要嵌套的括号的多余线条都消失了…@MalteHartwig,现在我读到了,这很有意义。现场只有一个setOnKeyPressed方法。谢谢!