title: Collision detection for a circle inside an octagon in JavaFX
body: <p>I am new to JavaFX and am having trouble with the collision detection. I have a circle inside an octagon that I wish to stay inside the octagon by bouncing off the walls. Currently, if I check for collisions inside the key pressed event whenever I try to move the circle it tends to hop around but, if I place the collision check outside the key pressed event nothing happens. At this moment my code only checks for collisions against the left and right wall. Here is my code:</p>
  
  <pre><code>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() &lt;= (bounds.getMinX() +          circ1.getRadius());
      boolean topWall = circ1.getLayoutY() &lt;= (bounds.getMinY() + circ1.getRadius());
      boolean rightWall = circ1.getTranslateX() &gt;= (bounds.getMaxX() + circ1.getRadius());
      boolean bottomWall = circ1.getLayoutY() &gt;= (bounds.getMaxY() + circ1.getRadius());
  
      circ1.setOnKeyPressed((e) -&gt; {
          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() &gt; 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() &gt; 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) -&gt; {
          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() &gt; 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() &gt; 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);
  }
  
  }
  </code></pre>