【JavaFX】当たり判定
本稿はJavaFXで当たり判定に使えそうなメソッドを紹介します。
目当ての判定ができそうにない場合は、swingで紹介したほうを使うのもいいかもしれません。
処理速度を考慮すると、矩形同士の判定か円同士の判定をオススメします。他の判定はどうしても実装したいときに利用しましょう。矩形同士の当たり判定はJavaFXでもメソッドは用意されています。
矩形同士の当たり判定
全てのNodeオブジェクトは矩形同士の当たり判定を実装できます。
Nodeオブジェクトのintersectsメソッドを呼び出します。引数BoundsはNodeオブジェクトのgetBoundsInLocalメソッドで取得できます。
※2018/01/18追記
tranlateX等の変換系の処理を考慮した判定をする場合はgetBoundsInParentを使用してください。
画像だろうが円だろうが、テキストだろうが矩形として判定します。
- import javafx.application.Application;
- import javafx.scene.Group;
- import javafx.scene.Scene;
- import javafx.scene.paint.Color;
- import javafx.scene.shape.Rectangle;
- import javafx.scene.text.Font;
- import javafx.scene.text.Text;
- import javafx.stage.Stage;
- public class Test extends Application{
- @Override
- public void start(Stage primaryStage) throws Exception {
- View v = new View();
- Scene scene = new Scene(v, 400, 300);
- primaryStage.setScene(scene);
- primaryStage.show();
- }
- }
- class View extends Group{
- public View() {
- Rectangle rect1 = new Rectangle(100, 120, 100, 100);
- Rectangle rect2 = new Rectangle(70, 140, 100, 100);
- rect1.setStroke(Color.RED);
- rect1.setFill(null);
- rect2.setStroke(Color.BLUE);
- rect2.setFill(null);
- getChildren().add(rect1);
- getChildren().add(rect2);
- Text text = new Text("当たっていません。");
- text.setFont(new Font(20));
- //矩形同士の当たり判定
- if ( rect1.intersects(rect2.getBoundsInLocal()) ) {
- text.setText("当たっています。");
- text.setFill(Color.RED);
- }
- text.setY(100);
- text.setX(200 - text.getBoundsInLocal().getWidth() / 2);
- getChildren().add(text);
- }
- }
点とオブジェクトの不透明部分との当たり判定
NodeオブジェクトのcontainsメソッドはNodeの不透明部分を感知して点と当たり判定できます。
例えば画像の不透明部分をクリック判定として使用できます。
- import java.io.File;
- import javafx.application.Application;
- import javafx.scene.Group;
- import javafx.scene.Scene;
- import javafx.scene.image.ImageView;
- import javafx.scene.input.MouseButton;
- import javafx.scene.input.MouseEvent;
- import javafx.scene.paint.Color;
- import javafx.scene.text.Font;
- import javafx.scene.text.Text;
- import javafx.stage.Stage;
- public class Test extends Application{
- @Override
- public void start(Stage primaryStage) throws Exception {
- View v = new View();
- Scene scene = new Scene(v, 400, 300);
- primaryStage.setScene(scene);
- primaryStage.show();
- scene.setOnMouseClicked(e -> v.mouseClicked(e));
- }
- }
- class View extends Group{
- Text text = new Text(0, 100, "");
- ImageView img = new ImageView(new File("img.png").toURI().toString());
- public View() {
- img.setX(160);
- img.setY(130);
- text.setFont(new Font(20));
- text.setFill(Color.RED);
- text.setStroke(Color.RED);
- getChildren().add(text);
- getChildren().add(img);
- }
- //クリック判定処理
- public void mouseClicked(MouseEvent e) {
- if ( e.getButton() == MouseButton.PRIMARY ) {
- if ( img.contains(e.getX(), e.getY()) ) {
- text.setText("画像がクリックされました。");
- text.setX(200 - text.getBoundsInLocal().getWidth() / 2);
- } else {
- text.setText("");
- }
- }
- }
- }
図形と図形の当たり判定
いいメソッドは用意されていなかったのですが、Shapeクラスのintersectメソッドで代用できそうです。
このメソッドであれば、Rectangle、Ellipse、Pathなどとの当たり判定が実装できます。
ただし、処理速度が心配なので、どうしてもというときのみに使用するようにし、基本的には使用しないほうがいいでしょう。
Shapeクラスのintersectメソッドは、二つの図形の共通部分を取得しますが、共通部分が取得できない場合は横幅や縦幅が-1になります。(Java9の時点で)それを判断基準にすればよさそうです。注意点は、不透明部分の共通領域を返すため、fillプロパティの指定は必須となります。デフォルトで黒が指定されているオブジェクトもある為、その場合は指定しなくても良い。
それではサンプルをご覧ください。
- import javafx.application.Application;
- import javafx.scene.Group;
- import javafx.scene.Scene;
- import javafx.scene.paint.Color;
- import javafx.scene.shape.ClosePath;
- import javafx.scene.shape.Ellipse;
- import javafx.scene.shape.LineTo;
- import javafx.scene.shape.MoveTo;
- import javafx.scene.shape.Path;
- import javafx.scene.shape.QuadCurveTo;
- import javafx.scene.shape.Shape;
- import javafx.scene.text.Font;
- import javafx.scene.text.Text;
- import javafx.stage.Stage;
- public class Test extends Application{
- @Override
- public void start(Stage primaryStage) throws Exception {
- View v = new View();
- Scene scene = new Scene(v, 400, 300);
- primaryStage.setScene(scene);
- primaryStage.show();
- }
- }
- class View extends Group{
- public View() {
- Path shape1 = new Path();
- Ellipse shape2 = new Ellipse(240, 200, 100, 80);
- shape1.setStroke(Color.RED);
- shape2.setStroke(Color.BLUE);
- shape1.setFill(new Color(0,0,0,0.1));
- shape2.setFill(new Color(0,0,0,0.1));
- getChildren().add(shape1);
- getChildren().add(shape2);
- Text text = new Text("当たっていません。");
- text.setFont(new Font(20));
- //パスの描画
- shape1.getElements().add(new MoveTo(150,120));
- shape1.getElements().add(new LineTo(170,130));
- shape1.getElements().add(new QuadCurveTo(100, 300, 50, 80));
- shape1.getElements().add(new ClosePath());
- //図形同士の当たり判定
- if ( Shape.intersect(shape1, shape2).getBoundsInLocal().getWidth() != -1 ) {
- text.setText("当たっています。");
- text.setFill(Color.RED);
- }
- text.setY(100);
- text.setX(200 - text.getBoundsInLocal().getWidth() / 2);
- getChildren().add(text);
- }
- }
ディスカッション
コメント一覧
まだ、コメントがありません