Javafx 2 使用JavaFX检查形状冲突
我正在尝试做一些碰撞检测。对于这个测试,我使用简单的矩形Javafx 2 使用JavaFX检查形状冲突,javafx-2,javafx,collision-detection,Javafx 2,Javafx,Collision Detection,我正在尝试做一些碰撞检测。对于这个测试,我使用简单的矩形形状,并检查它们的边界,以判断它们是否发生碰撞。虽然检测没有按预期工作。我尝试过使用不同的方法移动对象(重定位、setLayoutX、Y)以及不同的边界检查(boundsInLocal、BoundsInParent等),但我仍然无法实现这一点。正如您所见,检测仅对一个对象有效,即使有三个对象,也只有一个对象检测碰撞。下面是一些工作代码,演示了该问题: import javafx.application.Application; import
形状
,并检查它们的边界
,以判断它们是否发生碰撞。虽然检测没有按预期工作。我尝试过使用不同的方法移动对象(重定位、setLayoutX、Y)以及不同的边界检查(boundsInLocal、BoundsInParent等),但我仍然无法实现这一点。正如您所见,检测仅对一个对象有效,即使有三个对象,也只有一个对象检测碰撞。下面是一些工作代码,演示了该问题:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
public class CollisionTester extends Application {
private ArrayList<Rectangle> rectangleArrayList;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("The test");
Group root = new Group();
Scene scene = new Scene(root, 400, 400);
rectangleArrayList = new ArrayList<Rectangle>();
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.GREEN));
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.RED));
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.CYAN));
for(Rectangle block : rectangleArrayList){
setDragListeners(block);
}
root.getChildren().addAll(rectangleArrayList);
primaryStage.setScene(scene);
primaryStage.show();
}
public void setDragListeners(final Rectangle block) {
final Delta dragDelta = new Delta();
block.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = block.getTranslateX() - mouseEvent.getSceneX();
dragDelta.y = block.getTranslateY() - mouseEvent.getSceneY();
block.setCursor(Cursor.NONE);
}
});
block.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
block.setCursor(Cursor.HAND);
}
});
block.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
block.setTranslateX(mouseEvent.getSceneX() + dragDelta.x);
block.setTranslateY(mouseEvent.getSceneY() + dragDelta.y);
checkBounds(block);
}
});
}
private void checkBounds(Rectangle block) {
for (Rectangle static_bloc : rectangleArrayList)
if (static_bloc != block) {
if (block.getBoundsInParent().intersects(static_bloc.getBoundsInParent())) {
block.setFill(Color.BLUE); //collision
} else {
block.setFill(Color.GREEN); //no collision
}
} else {
block.setFill(Color.GREEN); //no collision -same block
}
}
class Delta {
double x, y;
}
}
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.scene.Cursor;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.input.MouseEvent;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Rectangle;
导入javafx.stage.stage;
导入java.util.ArrayList;
公共类CollisionTester扩展应用程序{
私有ArrayList矩形ArrayList;
公共静态void main(字符串[]args){
发射(args);
}
公共无效开始(阶段primaryStage){
初级阶段。设置标题(“测试”);
组根=新组();
场景=新场景(根,400400);
矩形ArrayList=新ArrayList();
添加(新矩形(30.0,30.0,Color.GREEN));
添加(新矩形(30.0,30.0,Color.RED));
添加(新矩形(30.0,30.0,Color.CYAN));
用于(矩形块:矩形ArrayList){
集光器(块);
}
root.getChildren().addAll(矩形数组列表);
初级阶段。场景(场景);
primaryStage.show();
}
公共空白设置矩形块(最终矩形块){
最终增量dragDelta=新增量();
setOnMousePressed(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent MouseEvent){
//记录拖放操作的增量距离。
dragDelta.x=block.getTranslateX()-mouseEvent.getSceneX();
dragDelta.y=block.getTranslateY()-mouseEvent.getSceneY();
block.setCursor(Cursor.NONE);
}
});
setOnMouseReleased(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent MouseEvent){
block.setCursor(Cursor.HAND);
}
});
setOnMouseDrawed(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent MouseEvent){
setTranslateX(mouseEvent.getSceneX()+dragDelta.x);
block.setTranslateY(mouseEvent.getSceneY()+dragDelta.y);
检查边界(块);
}
});
}
专用无效检查边界(矩形块){
for(矩形静态组:矩形阵列列表)
if(静态组!=块){
if(block.getBoundsInParent()相交(static_bloc.getBoundsInParent()){
block.setFill(Color.BLUE);//冲突
}否则{
block.setFill(Color.GREEN);//无冲突
}
}否则{
block.setFill(Color.GREEN);//无冲突-同一块
}
}
类三角洲{
双x,y;
}
}
您的checkBounds例程中似乎有一个轻微的逻辑错误-您正确地检测到了碰撞(基于边界),但在同一例程中执行后续碰撞检查时覆盖了块的填充
尝试以下操作-它添加了一个标志,以便例程不会“忘记”检测到碰撞:
private void checkBounds(Shape block) {
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
static_bloc.setFill(Color.GREEN);
if (block.getBoundsInParent().intersects(static_bloc.getBoundsInParent())) {
collisionDetected = true;
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.GREEN);
}
}
请注意,您正在执行的检查(基于父组中的边界)将报告包含同一父组中可见节点边界的矩形的交点
替代实施
如果需要,我更新了原始示例,以便它能够基于节点的可视形状而不是可视形状的边界框进行检查。这使您能够准确检测非矩形形状(如圆)的碰撞。关键是方法
注意:如果有许多形状正在设置动画,则在一个节点内每帧检查一次碰撞将比在任何节点移动时运行碰撞检查更有效(如上面的boundsInParentProperty更改侦听器中所做的).试着用我写的这个来演示JavaFX中各种边界类型的交集关系。好的,我现在感兴趣的似乎都是该文件中的第一个类。我学到的一件重要的事情是检查冲突的changeListener。在检查(?)上也使用LayoutBounds。我应该为矩形使用setLayoutX还是translateX?我知道你在使用setX,但这是私有的,我猜在文档中不清楚哪一个是更改相同属性的公共方法。更新了答案以解决其他问题。非常感谢你的帮助,它确实澄清了一些概念。仍在处理此项目,我面临另一个问题。为了创建类似于Scratch blocks或google Blocky的块,您能提出比在scenebuilder中组合多个形状更好的方法吗?问题在于转换块以适应内部其他块。形状组合是一个与原始问题不同的问题,形状组合问题也不是很清楚,我建议提出一个新问题,提供更多描述和清晰的示例图像,准确演示您需要的一些形状和形状组合。您好,即使圆已设置动画,相交是否仍有效?我的意思是不用鼠标拖动圆圈,如果我让它们随机移动会发生什么。这种情况下颜色也会改变吗?
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.ArrayList;
import javafx.scene.shape.*;
public class CircleCollisionTester extends Application {
private ArrayList<Shape> nodes;
public static void main(String[] args) { launch(args); }
@Override public void start(Stage primaryStage) {
primaryStage.setTitle("Drag circles around to see collisions");
Group root = new Group();
Scene scene = new Scene(root, 400, 400);
nodes = new ArrayList<>();
nodes.add(new Circle(15, 15, 30));
nodes.add(new Circle(90, 60, 30));
nodes.add(new Circle(40, 200, 30));
for (Shape block : nodes) {
setDragListeners(block);
}
root.getChildren().addAll(nodes);
checkShapeIntersection(nodes.get(nodes.size() - 1));
primaryStage.setScene(scene);
primaryStage.show();
}
public void setDragListeners(final Shape block) {
final Delta dragDelta = new Delta();
block.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = block.getLayoutX() - mouseEvent.getSceneX();
dragDelta.y = block.getLayoutY() - mouseEvent.getSceneY();
block.setCursor(Cursor.NONE);
}
});
block.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
block.setCursor(Cursor.HAND);
}
});
block.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
block.setLayoutX(mouseEvent.getSceneX() + dragDelta.x);
block.setLayoutY(mouseEvent.getSceneY() + dragDelta.y);
checkShapeIntersection(block);
}
});
}
private void checkShapeIntersection(Shape block) {
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
static_bloc.setFill(Color.GREEN);
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.GREEN);
}
}
class Delta { double x, y; }
}
block.boundsInParentProperty().addListener((observable, oldValue, newValue) ->
checkShapeIntersection(block)
);