不断检查子弹是不是触及节点

Posted

技术标签:

【中文标题】不断检查子弹是不是触及节点【英文标题】: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();
    

【问题讨论】:

【参考方案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。

【讨论】:

以上是关于不断检查子弹是不是触及节点的主要内容,如果未能解决你的问题,请参考以下文章

检查是不是存在节点并检查其属性值

我需要知道如何让 python 不断检查它是不是连接到互联网 [重复]

使用 XSLT 检查节点是不是存在

检查给定 UUID 的节点是不是存在

VB.NET - 检查子节点是不是在 TreeView 中选中

Firebase 实时规则如何检查具有 AutoID 的节点是不是包含正确的数据