当前位置: 首页 > 知识库问答 >
问题:

JavaFX中八边形内圆的碰撞检测

邢凌
2023-03-14

我是JavaFX的新手,在碰撞检测方面遇到了麻烦。我在一个八边形内有一个圆圈,我希望通过从墙壁上反弹来留在八边形内。目前,如果我在尝试移动圆圈时检查按键事件内部的碰撞,它往往会跳来跳去,但是,如果我将碰撞检查放在按键事件之外,则不会发生任何事情。目前,我的代码只检查与左右墙的碰撞。这是我的代码:

import java.util.Vector;
import com.sun.javafx.geom.Vec2f;
import javafx.animation.AnimationTimer;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Shape;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Craft extends Application {
double getX; // I later declare this as circ1.getTranslateX()
double getY; // I later declare this as circ1.getTranslateY()

@Override 
public void start(Stage primaryStage) { 

    Pane pane = new Pane();

    Polygon octagon = new Polygon(500,50, 1200,50, 1600,300, 1600,800,        1200,1000, 500,1000, 100,800, 100,300 );
    octagon.setStroke(Color.BLACK);
    octagon.setFill(Color.TRANSPARENT);

    Circle circ1 = new Circle(500.0f, 500.0f, 25.0f);
    circ1.setFill(Color.BLUE);

    Polygon tri1 = new Polygon(530, 495, 530, 505, 540, 500);
    tri1.setFill(Color.BLUE);
    tri1.translateXProperty().bind(circ1.translateXProperty());
    tri1.translateYProperty().bind(circ1.translateYProperty());

    Rotate rotate = new Rotate();
    rotate.pivotXProperty().bind(circ1.centerXProperty());
    rotate.pivotYProperty().bind(circ1.centerYProperty());
    rotate.angleProperty().bind(circ1.rotateProperty());

    tri1.getTransforms().add(rotate);

    pane.getChildren().addAll(octagon, circ1, tri1);

    getX = circ1.getTranslateX();
    getY = circ1.getTranslateY();

    Bounds bounds = octagon.getBoundsInLocal();
    boolean leftWall = circ1.getTranslateX() <= (bounds.getMinX() +          circ1.getRadius());
    boolean topWall = circ1.getLayoutY() <= (bounds.getMinY() + circ1.getRadius());
    boolean rightWall = circ1.getTranslateX() >= (bounds.getMaxX() + circ1.getRadius());
    boolean bottomWall = circ1.getLayoutY() >= (bounds.getMaxY() + circ1.getRadius());

    circ1.setOnKeyPressed((e) -> {
        if(e.getCode() == KeyCode.UP) {
            DoubleProperty circ1VelX = new SimpleDoubleProperty();
            DoubleProperty circ1VelY = new SimpleDoubleProperty();
            LongProperty lastUpdateTime = new SimpleLongProperty();
            AnimationTimer circ1Animation = new AnimationTimer() {
            @Override
              public void handle(long timestamp) {
                if (lastUpdateTime.get() > 0) {
                  double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
                  double deltaX = elapsedSeconds * circ1VelX.get();
                  double deltaY = elapsedSeconds * circ1VelY.get();
                  double oldX = circ1.getTranslateX();
                  double oldY = circ1.getTranslateY();
                  double newX = oldX + deltaX;
                  double newY = oldY + deltaY;
                  circ1.setTranslateX(newX += 1 * Math.cos(Math.toRadians(circ1.getRotate())) * 0.1);
                  circ1.setTranslateY(newY += 1 * Math.sin(Math.toRadians(circ1.getRotate())) * 0.1);
                }
                lastUpdateTime.set(timestamp);
              }
            };circ1Animation.start();

        }
        else if(e.getCode() == KeyCode.LEFT) {
            circ1.setRotate(circ1.getRotate() - 5);
        }
        else if(e.getCode() == KeyCode.RIGHT) {
            circ1.setRotate(circ1.getRotate() + 5);
        }
        else if(e.getCode() == KeyCode.DOWN) {
            DoubleProperty circ1VelX = new SimpleDoubleProperty();
            DoubleProperty circ1VelY = new SimpleDoubleProperty();
            LongProperty lastUpdateTime = new SimpleLongProperty();
            AnimationTimer circ1Animation = new AnimationTimer() {
            @Override
              public void handle(long timestamp) {
                if (lastUpdateTime.get() > 0) {
                  double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
                  double deltaX = elapsedSeconds * circ1VelX.get();
                  double deltaY = elapsedSeconds * circ1VelY.get();
                  double oldX = circ1.getTranslateX();
                  double oldY = circ1.getTranslateY();
                  double newX = oldX + deltaX;
                  double newY = oldY + deltaY;
                  circ1.setTranslateX(newX -= 1 * Math.cos(Math.toRadians(circ1.getRotate())) * 0.1);
                  circ1.setTranslateY(newY -= 1 * Math.sin(Math.toRadians(circ1.getRotate())) * 0.1);
                }
                lastUpdateTime.set(timestamp);
              }
            };circ1Animation.start();
        }

    });

    circ1.setOnKeyReleased((e) -> {
        if(e.getCode() == KeyCode.UP) {
            DoubleProperty circ1VelX = new SimpleDoubleProperty();
            DoubleProperty circ1VelY = new SimpleDoubleProperty();
            LongProperty lastUpdateTime = new SimpleLongProperty();
            AnimationTimer circ1Animation = new AnimationTimer() {
            @Override
              public void handle(long timestamp) {
                if (lastUpdateTime.get() > 0) {
                  double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
                  double deltaX = elapsedSeconds * circ1VelX.get();
                  double deltaY = elapsedSeconds * circ1VelY.get();
                  double oldX = circ1.getTranslateX();
                  double oldY = circ1.getTranslateY();
                  double newX = oldX + deltaX;
                  double newY = oldY + deltaY;
                  circ1.setTranslateX(newX += 0.5 *      Math.cos(Math.toRadians(circ1.getRotate())));
                  circ1.setTranslateY(newY += 0.5 * Math.sin(Math.toRadians(circ1.getRotate())));
                }
                lastUpdateTime.set(timestamp);
              }
            };circ1Animation.start();
        }
        else if(e.getCode() == KeyCode.DOWN) {
            DoubleProperty circ1VelX = new SimpleDoubleProperty();
            DoubleProperty circ1VelY = new SimpleDoubleProperty();
            LongProperty lastUpdateTime = new SimpleLongProperty();
            AnimationTimer circ1Animation = new AnimationTimer() {
            @Override
              public void handle(long timestamp) {
                if (lastUpdateTime.get() > 0) {
                  double elapsedSeconds = (timestamp - lastUpdateTime.get()) / 1_000_000_000.0 ;
                  double deltaX = elapsedSeconds * circ1VelX.get();
                  double deltaY = elapsedSeconds * circ1VelY.get();
                  double oldX = circ1.getTranslateX();
                  double oldY = circ1.getTranslateY();
                  double newX = oldX + deltaX;
                  double newY = oldY + deltaY;
                  circ1.setTranslateX(newX -= 0.5 * Math.cos(Math.toRadians(circ1.getRotate())));
                  circ1.setTranslateY(newY -= 0.5 *       Math.sin(Math.toRadians(circ1.getRotate())));

                }
                lastUpdateTime.set(timestamp);
              }
            };circ1Animation.start();
        }

    });

    if(leftWall || rightWall) {
          circ1.setTranslateX(getX *= -1);
      }



    Scene scene = new Scene(pane, 1700, 1050);
    scene.getStylesheets().add("custom_craft.css");

    primaryStage.setScene(scene);
    primaryStage.setTitle("Craft");
    primaryStage.show();

    circ1.requestFocus();
}

public static void main(String[] args) {
    launch(args);
}

}

共有2个答案

濮嘉茂
2023-03-14

我当然知道答案...将多边形转换成区域并使用相交方法。

http://docs . Oracle . com/javase/7/docs/API/Java/awt/geom/area . html

您可能需要在八边形周围定义一个厚度为非零的新多边形和(区域)新多边形框架(...)

frame.intersect((Area)circ1).isEmpty()!=true

圆圈和框架发生了碰撞。

编辑:javafx (2d maze)中的碰撞检测器提供了一些关于使用javafxCanvas处理对象碰撞的说明

乔凯康
2023-03-14

你要寻找的是几个问题的答案,例如。我想你的球应该连续移动,移动时不要结巴。此外,球应该一直移动,而不仅仅是在按键时。你对动画计时器的使用是错误的。

关于交叉点:如果你只有一个矩形,那么答案很简单。但你没有。因此,您只能对照八角形或单独的线进行检查。这本身就是非常数学化的。这里已经有几个问题和答案了

这里有一个快速

  • 我将多边形转换为单独的线。
  • 我从圆和每条线中创建一个新的形状,这样可以检查它们是否相交

您可以拖动圆形,并通过更改颜色查看交叉点。

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class CircleLineIntersection extends Application {

    Circle circle;
    List<Line> lines = new ArrayList<>();

    Color defaultStroke = Color.GREEN;
    Color defaultFill = defaultStroke.deriveColor(1, 1, 1, 0.3);

    Color hitStroke = Color.RED;
    Color hitFill = hitStroke.deriveColor(1, 1, 1, 0.3);

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        Group root = new Group();

        circle = new Circle(100, 100, 50);
        circle.setStroke( defaultStroke);
        circle.setFill( defaultFill);

        Polygon octagon = new Polygon(500, 50, 1200, 50, 1600, 300, 1600, 800, 1200, 1000, 500, 1000, 100, 800, 100, 300);

        // create lines out of the octagon
        int size = octagon.getPoints().size();
        for (int i = 0; i < size; i += 2) {

            double startX = octagon.getPoints().get(i);
            double startY = octagon.getPoints().get(i + 1);
            double endX = octagon.getPoints().get((i + 2) % size);
            double endY = octagon.getPoints().get((i + 3) % size);

            Line line = new Line(startX, startY, endX, endY);

            lines.add(line);
        }

        MouseGestures mg = new MouseGestures();
        mg.makeDraggable(circle);

        root.getChildren().addAll(lines);
        root.getChildren().addAll(circle);

        primaryStage.setScene(new Scene(root, 1920, 1080));
        primaryStage.show();
    }


    public class MouseGestures {

        class DragContext {
            double x;
            double y;
        }

        DragContext dragContext = new DragContext();

        public void makeDraggable(Node node) {
            node.setOnMousePressed(onMousePressedEventHandler);
            node.setOnMouseDragged(onMouseDraggedEventHandler);
            node.setOnMouseReleased(onMouseReleasedEventHandler);
        }

        EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                Circle circle = ((Circle) (event.getSource()));

                dragContext.x = circle.getCenterX() - event.getSceneX();
                dragContext.y = circle.getCenterY() - event.getSceneY();

            }
        };

        EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

                Circle circle = ((Circle) (event.getSource()));

                circle.setCenterX(dragContext.x + event.getSceneX());
                circle.setCenterY(dragContext.y + event.getSceneY());

                // check intersection of lines vs circle
                boolean intersects = false;
                for (Line line : lines) {

                    // TODO: this is heavy on performance, better implement your own line <-> circle intersection algorithm
                    Shape shape = Shape.intersect( line, circle);
                    intersects = shape.getBoundsInLocal().getWidth() >= 0 || shape.getBoundsInLocal().getHeight() >= 0;

                    if( intersects) {
                        break;
                    }
                }

                // set color depending on intersection
                if( intersects) {
                    circle.setStroke( hitStroke);
                    circle.setFill( hitFill);
                }  else {
                    circle.setStroke( defaultStroke);
                    circle.setFill( defaultFill);
                }

            }
        };

        EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {

            }
        };

    }

}
 类似资料:
  • 问题内容: Libgdx中是否可以验证多边形和圆之间的碰撞? 我看到了课程,但只发现了Circle和Rectangle的碰撞测试。那其他多边形呢? 如果我需要手动进行操作,那么使用Libgdx的最佳方法是什么? 问题答案: 因此,我设法在Circle和Polygon之间创建了碰撞测试方法。至少,它对我有用。 这是代码:

  • 我正在编写一个游戏,涉及碰撞的一个移动的圆,由用户控制,和一个移动的矩形,由计算机控制。 完整的代码可以在这里找到:游戏 我在圆和矩形之间的碰撞检测方面遇到了麻烦。当矩形是静态的,碰撞检测工作完美。当圆和矩形的边缘在任一边接触时,程序就会按照它应该的方式进行操作。 这是碰撞检测功能。 谢谢。

  • 我花了数小时寻找解决方案:我正在用libgdx开发一个自上而下的小游戏(可能这与我使用的引擎有关)。现在我必须在我的角色(圆形)和墙(矩形)之间实现碰撞检测。如果可以滑动,我希望角色在碰撞时沿着墙滑动。让我解释一下: 如果我向上移动45度,我可能会撞到墙的下面、左边或角落。 如果我与左边相撞,我想停止x运动,只向上移动。如果我离开墙壁,那么我想继续向上移动。与下侧相同(停止y运动) 如果我与角落相

  • 所以我试图用pygame制作一个我们之间的游戏。我刚刚开始,所以我没有太多东西,现在正在制作地图。然而,我正在努力解决的一件事是碰撞逻辑。地图目前有一个细长的八边形形状,但是我想不管是什么形状,我都会使用类似pygame多边形的东西。当我运行我现在的代码时,它会检查我的玩家(pygame矩形)和墙壁(pygame多边形)之间的碰撞,它说: 我发现这是因为pygame多边形返回了一个矩形,但在碰撞检

  • 那么,我如何实现圆弧线的冲突检测呢?我必须使用Box 2d碰撞,还是可以使用矩形之类的其他方法? 顺便说一句,我讨厌box2d,因为我不了解其中的大部分内容,所以如果有一个解决方案排除box2d的话,我会非常感激。 黄色的弧线继续在黑色的圆圈上旋转。我如何在这里实现碰撞检测? 请帮忙!谢谢!

  • 我有一个问题,碰撞检测一个圆和一个矩形。我曾尝试用勾股定理来解决这个问题。但所有查询都不起作用。矩形与圆的矩形包围盒发生碰撞。