JavaFX

2013-02-21 24 views
12

के साथ आकारों की टक्कर की जांच करना मैं कुछ टकराव का पता लगाने की कोशिश कर रहा हूं। इस परीक्षण के लिए मैं सरल आयताकार Shape का उपयोग कर रहा हूं, और यह पता लगाने के लिए कि वे टकराव कर रहे हैं, उनके Bound की जांच कर रहे हैं। हालांकि पहचान अपेक्षित के रूप में काम नहीं करती है। मैंने ऑब्जेक्ट को स्थानांतरित करने के लिए विभिन्न तरीकों का उपयोग करने की कोशिश की है (स्थानांतरित करें, सेटलेआउटएक्स, वाई) और विभिन्न बाध्य चेक (सीमाएं, लोकल, सीमाएं इत्यादि) लेकिन मैं अभी भी इसे काम पर नहीं ला सकता हूं। जैसा कि आप देख सकते हैं कि पहचान केवल एक ऑब्जेक्ट के लिए काम करती है, भले ही आपके पास तीन ऑब्जेक्ट हों, केवल टकराव का पता लगाता है। यह कुछ काम कर कोड समस्या का प्रदर्शन है:JavaFX

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; 
    } 
} 
+2

इस [चौराहे डेमो एप्लिकेशन] (https://gist.github.com/jewelsea/1441960) के साथ खेलने का प्रयास करें जिसे मैंने JavaFX में विभिन्न सीमा प्रकारों के छेड़छाड़ संबंधों को प्रदर्शित करने के लिए लिखा था। – jewelsea

+0

ठीक है ऐसा लगता है कि मुझे अभी भी जो कुछ भी दिलचस्पी है उस फ़ाइल में पहली कक्षा में है। एक महत्वपूर्ण बात जो मैं उठाता हूं वह टकराव पर जांच के लिए बदल जाता है। चेक (??) पर लेआउटबाउंड का भी उपयोग करें। क्या मुझे आयत के लिए setLayoutX या translateX का उपयोग करना चाहिए? मुझे लगता है कि आप सेटएक्स का उपयोग कर रहे हैं, लेकिन यह निजी है जो मुझे लगता है और डॉक्टर पर यह स्पष्ट नहीं है कि सार्वजनिक विधि कौन सा विशेषता बदल रही है। – Giannis

+0

अतिरिक्त प्रश्नों के समाधान के लिए अद्यतन उत्तर। – jewelsea

उत्तर

23

लगता है आप अपने 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); 
    } 
} 

ध्यान दें कि चेक आप कर रहे हैं (मूल में सीमा के आधार पर) होगा एक ही पैरेंट समूह के भीतर नोड्स की दृश्य सीमाओं को संलग्न आयत के चौराहे की रिपोर्ट करें।

वैकल्पिक कार्यान्वयन

मामले आपको इसकी आवश्यकता में, मैं अपने मूल नमूना अद्यतन इतना है कि यह दृश्य के बजाय दृश्य आकार का सीमांकन बॉक्स नोड के आकार के आधार पर जांच करने के लिए सक्षम है। यह आपको मंडलियों जैसे गैर-आयताकार आकारों के लिए टकराव का सटीक रूप से पता लगाने देता है। इसके लिए कुंजी Shape.intersects(shape1, shape2) विधि है।

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; } 
} 

नमूना प्रोग्राम आउटपुट। नमूने में सर्किलों को चारों ओर खींच लिया गया है और उपयोगकर्ता वर्तमान में एक सर्कल खींच रहा है जिसे किसी अन्य सर्कल (इसे नीले रंग से चित्रित करके) के साथ टकराने के रूप में चिह्नित किया गया है - प्रदर्शन उद्देश्यों के लिए केवल वर्तमान में खींचा जाने वाला सर्कल यह टकराव रंग है।

collisions

टिप्पणियां अतिरिक्त प्रश्न

लिंक मैं एक पूर्व टिप्पणी में एक intersection demo application पर पोस्ट किए गए के आधार पर नहीं बल्कि टक्कर पता लगाने नमूना की एक विशिष्ट प्रकार के रूप में की तुलना में विभिन्न सीमा प्रकार के उपयोग के उदाहरण देकर स्पष्ट करने के लिए था । आपके उपयोग के मामले में, आपको परिवर्तन श्रोता की अतिरिक्त जटिलता और विभिन्न प्रकार के सीमा प्रकारों की जांच करने की आवश्यकता नहीं है - बस एक प्रकार पर बसने के लिए पर्याप्त होगा। अधिकांश टकराव का पता लगाने के लिए केवल अन्य जावाएफएक्स सीमा प्रकारों जैसे कि लेआउट सीमा या नोड की स्थानीय सीमाओं के बजाय दृश्य सीमाओं के छेड़छाड़ में दिलचस्पी होगी। तो अगर आप कर सकते हैं: getBoundsInParent के चौराहे (यदि आप अपने मूल प्रश्न में किया था के रूप में) जो छोटी से छोटी आयताकार बॉक्स जो नोड के दृश्य हाथ पैरों या

  • उपयोग Shape.intersect(shape1, shape2) दिनचर्या अगर शामिल होगा पर काम करता है के लिए

    1. चेक आपको दृश्य आकार के बाध्यकारी बॉक्स की बजाय नोड के दृश्य आकार के आधार पर जांचना होगा।

    मैं आयत

    layoutX और layoutY गुण स्थिति या नोड्स बिछाने के लिए हैं के लिए setLayoutX या translateX प्रयोग करना चाहिए। translateX और अनुवाद वाई गुण नोड के दृश्य स्थान पर अस्थायी परिवर्तनों के लिए हैं (उदाहरण के लिए जब नोड एनीमेशन से गुजर रहा है)। आपके उदाहरण के लिए, यद्यपि कोई भी संपत्ति काम करेगी, फिर भी अनुवादकों की तुलना में लेआउट गुणों का उपयोग करने के लिए शायद यह बेहतर रूप है, इस तरह यदि आप नोड्स पर TranslateTransition जैसे कुछ चलाने के लिए चाहते हैं, तो यह और अधिक स्पष्ट होगा कि शुरुआत और अंतिम अनुवाद मान होना चाहिए क्योंकि वे मान मूल समूह की स्थिति के बजाय नोड की वर्तमान लेआउट स्थिति के सापेक्ष होंगे।

    एक और तरीका है कि आप इन लेआउट का उपयोग कर सकते हैं और अपने नमूने में टंडेम में समन्वय का अनुवाद कर सकते हैं यदि आपके पास ड्रैग ऑपरेशन के दौरान रद्द करने के लिए ईएससी की तरह कुछ था। आप लेआउटएक्स, वाई को अपने नोड के शुरुआती स्थान पर सेट कर सकते हैं, एक ड्रैग ऑपरेशन शुरू करें जो अनुवादेटएक्स, वाई मान सेट करता है और यदि उपयोगकर्ता ईएससी दबाता है, तो अनुवादेटएक्स सेट करें, वाई को 0 पर ड्रैग ऑपरेशन रद्द करने के लिए या यदि उपयोगकर्ता माउस को रिलीज़ करता है लेआउटएक्स सेट करें, वाई लेआउटएक्स, वाई + ट्रांसलेटएक्स, वाई और अनुवाद अनुवादएक्स, वाई को वापस 0 पर सेट करें। विचार यह है कि अनुवाद का मान नोड के दृश्य समन्वय के अस्थायी संशोधन के लिए मूल लेआउट स्थिति से अस्थायी संशोधन के लिए किया जाता है।

    सर्किल एनिमेटेड होने के बावजूद काम छेड़छाड़ करेगा? मेरा मतलब माउस द्वारा सर्कल खींचने के बिना, अगर मैं उन्हें यादृच्छिक रूप से घूमने के लिए बनाया तो क्या होगा। क्या इस मामले में रंग भी बदल जाएगा?

    ऐसा करने के लिए, टकराव का पता लगाने के कार्य को कहां बुलाया जाता है और टक्कर हैंडलर को बुलाया जाता है। माउस ड्रैग इवेंट (ऊपर दिए गए उदाहरण की तरह) के आधार पर छेड़छाड़ की जांच करने के बजाय, प्रत्येक नोड के boundsInParentProperty() पर एक परिवर्तन श्रोता के भीतर टकराव की जांच करें।

    block.boundsInParentProperty().addListener((observable, oldValue, newValue) -> 
         checkShapeIntersection(block) 
    ); 
    

    नोट: यदि आप आकार के पास बहुत एनिमेटेड किया जा रहा है, तो एक game loop भीतर एक बार फ्रेम प्रति टकराव के लिए जाँच एक टक्कर की जांच चलाने की तुलना में अधिक कुशल हो जाएगा जब भी कोई नोड चाल (के रूप में boundsInParentProperty परिवर्तन श्रोता में किया जाता है ऊपर)।

  • +0

    आपकी मदद के लिए बहुत बहुत धन्यवाद यह वास्तव में कुछ अवधारणाओं को मंजूरी दे दी है। – Giannis

    +0

    अभी भी इस परियोजना पर काम कर रहा है और मुझे एक और समस्या का सामना करना पड़ रहा है। क्या आप ब्लॉकबिल्डर में कई आकारों के संयोजन से बेहतर तरीके से सुझाव दे सकते हैं, ताकि ब्लॉक बनाने के लिए स्क्रैच ब्लॉक या Google Blocky के समान उपयोग किया जा सके? समस्या दूसरों के अंदर फिट करने के लिए ब्लॉक बदलने के साथ है। – Giannis

    +0

    आकार संयोजन मूल से एक अलग प्रश्न है और आकार संयोजन प्रश्न सभी स्पष्ट नहीं है, मैं सलाह देता हूं कि एक नया प्रश्न पूछने के लिए और अधिक विवरण और स्पष्ट नमूना छवियां प्रदान करें जो आपको आवश्यक आकारों और संयोजनों के संयोजन का प्रदर्शन करती हैं। – jewelsea