【问题标题】:bullet trajectory子弹轨迹
【发布时间】:2016-07-01 02:26:33
【问题描述】:

首先,我想用大炮射击飞机。 我已经为轨迹设置了这个时间线,但我没有在我的场景中看到子弹。我的轨迹代码很可能不正确。我试图在网上查找projectile motion 的公式,但我对物理一无所知;

import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Game_1 extends Application {

    private final double gravity = 9.81;
    private Timeline timeline;
    private ImageView plane;
    private Circle circle;
    private AnchorPane ap;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Test");
        Group group = new Group();
        Scene scene = new Scene(group, 600, 350);
        scene.setFill(Color.BLACK);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void shoot() {
        double x = 65.0f;
        double y = 408;
        double speed = 200;
        double t = 2;
        double angle = -45;
        double dx = Math.cos(angle) * speed;
        double dy = Math.sin(angle) * speed;
        circle = new Circle(x, y, 5, Color.BLACK);
        double x2 = x + dx * t;
        double y2 = (Math.tan(angle) * y - (gravity / (2 * Math.pow(speed, 2) * Math.cos(angle))) * Math.pow(x, 2));
        timeline = new Timeline();
        KeyValue xKV = new KeyValue(circle.centerXProperty(), x2);
        KeyValue yKV = new KeyValue(circle.centerYProperty(), y2, new Interpolator() {
            @Override
            protected double curve(double t) {
                return y + dy * t - 0.5 * gravity * t * t;
            }
        });
        KeyFrame xKF = new KeyFrame(Duration.seconds(t), xKV);
        KeyFrame yKF = new KeyFrame(Duration.seconds(t), yKV);
        timeline.getKeyFrames().addAll(xKF, yKF);
        ap.getChildren().add(circle);
        timeline.play();
        collision();
    }

    private void collision() {
        circle.boundsInParentProperty().addListener((ObservableValue<? extends Bounds> arg0, Bounds oldValue2, Bounds newValue2) -> {
            if (circle.getBoundsInParent().intersects(plane.getBoundsInParent())) {
                timeline.stop();
                ap.getChildren().remove(circle);
            }
        });
    }
}

【问题讨论】:

  • 请发MCVE,重点关注完成
  • 我已经添加了碰撞的方法。你对我的问题还有其他问题吗?告诉我,我会再次更新,但我认为现在一切都结束了
  • 这不是完整的
  • 完成意味着有人可以复制和粘贴它,然后编译并运行它而不进行更改以复制您的问题。它也应该是最小的,以便它只复制问题而没有其他内容。另外,最好每个问题只问一个问题。
  • 不,不是。 shoot() 永远不会被调用。

标签: java javafx


【解决方案1】:

The curve method 应该映射到区间 [0, 1]。但是,您的方法映射到更高的值。给定起始值val0 和结束值val1 的插值器it0t1 的动画在时间t 的值val 计算如下:

val = val0 + (val1 - val0) * i.curve((t - t0) / (t1 - t0))

curve方法的参数是时间间隔内的相对位置(0=动画开始;1=动画结束)。该方法的结果用于确定该值与结束值的接近程度(0 = 仍处于起始值;1 = 处于结束值)。

因此,您可能应该计算炮弹曲线中的顶点hMax(如所述,例如here on Wikipedia)并使用不同的插值器:

Interpolator interpolator = new Interpolator() {
    @Override
    protected double curve(double t) {
        // parabola with zeros at t=0 and t=1 and a maximum of 1 at t=0.5
        return 4 * t * (1 - t);
    }
};

KeyValue yKV = new KeyValue(circle.centerYProperty(), hMax, interpolator);

请注意,向上移动意味着 减小 UI 的 y 坐标,因此在这种情况下,hMax 应该小于开始时的 y 值.


除此之外,您的 shoot 方法永远不会被调用,并且某些字段未初始化,这将导致 NPE,以防它被调用。此外,如果这两个问题得到解决,黑色背景上的黑色圆圈将很难看到......

示例

请注意,这不是使用任何物理公式,而是使用我选择的一些值:

@Override
public void start(Stage primaryStage) {
    Circle circle = new Circle(10);
    circle.setManaged(false);
    Pane pane = new Pane(circle);

    circle.setCenterX(20);
    circle.setCenterY(800);

    Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO,
            new KeyValue(circle.centerXProperty(), 20),
            new KeyValue(circle.centerYProperty(), 800)
        ), new KeyFrame(Duration.seconds(3),
            new KeyValue(circle.centerXProperty(), 380),
            new KeyValue(circle.centerYProperty(), 10, new Interpolator() {
                @Override
                protected double curve(double t) {
                    // parabola with zeros at t=0 and t=1 and a maximum of 1 at t=0.5
                    return 4 * t * (1 - t);
                }
            })
        )
    );

    Scene scene = new Scene(pane, 400, 800);
    scene.setOnMouseClicked(evt -> timeline.playFromStart());
    primaryStage.setScene(scene);
    primaryStage.show();
}

请注意,Interpolator.curve 应该为参数 0 返回 0,为参数 1 返回 1。如果属性被进一步设置动画,其他任何事情都可能导致跳转。如果你想在动画完成后移动球,也许两部分的 y 运动会更合适。

插值器 1: t * (2 - t)
插值器 2: t * t

使用时间间隔的一半,分别使用曲线的顶部和开始 y 坐标的结束值。

【讨论】:

  • @Bruno:请注意,上面curve() 的实现在代数上等同于here:fabian 的实现更简单;我的使顶点显式。还可以考虑PathTransition 和合适的Path
  • 我多次编辑帖子,因为@Roland不喜欢它并且我在修改后忘记调用我的拍摄方法。无论如何,非常感谢,我现在会努力正确地射出我的子弹。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-05
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
相关资源
最近更新 更多