【问题标题】:Constantly checking if a bullet has touched a node不断检查子弹是否触及节点
【发布时间】:2022-01-21 11:42:12
【问题描述】:

我有一个非常简单的程序,您可以在其中使用您的 WASDspace 键进行射击。所有的射击和移动动画都有效,但我不确定如何实现一个系统,在该系统中程序会不断检查子弹是否接触到一个节点,例如一个圆圈。

我在想我可以有一个ArrayList 来存储所有的子弹,然后使用TimerTask 来检查子弹是否接触到一个节点;但我觉得这会减慢程序的速度,而且子弹可能会在TimerTask 等待再次运行时通过它们。

任何建议都会有所帮助。

代码:Pastebin

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.animation.*;
import javafx.util.Duration;
public class functionalShooter extends Application {
    private String currentDirection = "W";
    public static void main(String[] args){ launch(args);   }
    @Override public void start(Stage stage) throws Exception{
        Pane root = new Pane();
        Scene scene = new Scene(root, 600, 400);
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();

        Circle player = new Circle(10);
        player.setLayoutX(300);
        player.setLayoutY(200);

        Circle other = new Circle(100, 100, 10);

        root.getChildren().addAll(player, other);

        //key events
        scene.setOnKeyPressed(event -> {
            switch(event.getCode()){
                case A:
                    player.setLayoutX(player.getLayoutX()-10);
                    currentDirection = "A";
                    break;
                case D:
                    player.setLayoutX(player.getLayoutX()+10);
                    currentDirection = "D";
                    break;
                case W:
                    player.setLayoutY(player.getLayoutY()-10);
                    currentDirection = "W";
                    break;
                case S:
                    player.setLayoutY(player.getLayoutY()+10);
                    currentDirection = "S";
                    break;
                case SPACE:
                    if (currentDirection.equals("D")){
                        Circle newCircle = new Circle(player.getLayoutX()+10, player.getLayoutY(), 5);
                        root.getChildren().add(newCircle);
                        shoot(newCircle);
                    }
                    else if (currentDirection.equals("A")){
                        Circle newCircle = new Circle(player.getLayoutX()-10, player.getLayoutY(), 5);
                        root.getChildren().add(newCircle);
                        shoot(newCircle);
                    }
                    else if (currentDirection.equals("S")){
                        Circle newCircle = new Circle(player.getLayoutX(), player.getLayoutY()+10, 5);
                        root.getChildren().add(newCircle);
                        shoot(newCircle);
                    }
                    else {
                        Circle newCircle = new Circle(player.getLayoutX(), player.getLayoutY()-10, 5);
                        root.getChildren().add(newCircle);
                        shoot(newCircle);
                    }
                    break;
            }
        });
    }

    private void shoot(Circle bullet){
        Timeline timeline = new Timeline();
        if (currentDirection.equals("D")){
            KeyValue start = new KeyValue(bullet.translateXProperty(), 0);
            KeyValue end = new KeyValue(bullet.translateXProperty(), 800);
            KeyFrame startF = new KeyFrame(Duration.ZERO, start);
            KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
            timeline.getKeyFrames().addAll(startF, endF);
        }
        else if (currentDirection.equals("A")){
            KeyValue start = new KeyValue(bullet.translateXProperty(), 0);
            KeyValue end = new KeyValue(bullet.translateXProperty(), -800);
            KeyFrame startF = new KeyFrame(Duration.ZERO, start);
            KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
            timeline.getKeyFrames().addAll(startF, endF);
        }
        else if (currentDirection.equals("S")){
            KeyValue start = new KeyValue(bullet.translateYProperty(), 0);
            KeyValue end = new KeyValue(bullet.translateYProperty(), 800);
            KeyFrame startF = new KeyFrame(Duration.ZERO, start);
            KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
            timeline.getKeyFrames().addAll(startF, endF);
        }
        else{
            KeyValue start = new KeyValue(bullet.translateYProperty(), 0);
            KeyValue end = new KeyValue(bullet.translateYProperty(), -800);
            KeyFrame startF = new KeyFrame(Duration.ZERO, start);
            KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
            timeline.getKeyFrames().addAll(startF, endF);
        }
        timeline.setAutoReverse(false);
        timeline.setCycleCount(1);
        timeline.play();
    }
}

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    您可以在提供给每个相关KeyValue 的自定义Interpolator 中使用Shape.intersect() 检查bullet 是否与other 相交。下面的片段将Interpolator 添加到shoot(),但每个方向都需要一个相同的片段。该实现是线性的,简单地返回 t 不变,但您也可以查看 this 抛物线插值器。我还将other 设为类变量,shoot() 可以访问。我毫不迟疑地向空中发射了十几颗子弹。请注意,您不需要 start 值:“一个将是 synthesized 使用当时当前的目标值”播放动画。

    private Circle other = new Circle(100, 100, 10);
    …
    else {
        KeyValue end = new KeyValue(bullet.translateYProperty(), -800, new Interpolator() {
            @Override
            protected double curve(double t) {
                if (!Shape.intersect(bullet, other).getBoundsInLocal().isEmpty()) {
                    System.out.println("Intersection");
                }
                return t;
            }
        });
        KeyFrame endF = new KeyFrame(Duration.seconds(10), end);
        timeline.getKeyFrames().addAll(endF);
    }
    

    【讨论】:

      【解决方案2】:

      您需要的是每次在游戏中绘制帧时都会检查碰撞的东西。计时器将在可以工作的单独线程中运行,但与游戏同步会困难得多。

      【讨论】:

      • 您可以使用AnimationTimer 在每一帧上执行代码,因为每帧只调用一次handle() 方法。
      • 类似Timeline,自定义Interpolator会被周期性调用,如图here
      【解决方案3】:

      一般来说,当您必须“不断观察”OO 语言中的某些内容时,最好的解决方案是使用Observer pattern

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-30
        • 1970-01-01
        • 2011-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        相关资源
        最近更新 更多