0
\$\begingroup\$

This is a bouncing ball program. There is 1 dynamic circle and 3 static ones. The static ones are obstacles for the dynamic circle, and the dynamic circle is supposed to bounce off of the static circles.

So I have an ArrayList of static circles:

public static List<Circle> circles_Static = new ArrayList<Circle>();

Something is wrong with my method for checking if the dynamic circle collides with any of the static ones. Currently, the dynamic circle starts bouncing all over the canvas extremely quickly and even disappears. So, if I don't use this method and call each static circle separately and see if it collides with the dynamic one, it's working perfecly. There's definitely something wrong with how the method is working and I really can't see what it may be.

Here's the method:

    public void collision() {
        for (int i = 0; i < circles_Static.size(); i++) {
            double dx = circles_Static.get(i).getLayoutX() - circle1.getLayoutX();
            double dy = circles_Static.get(i).getLayoutY() - circle1.getLayoutY();
            double minDistance = circles_Static.get(i).getRadius() + circle1.getRadius();
            double distance = (dx * dx) + (dy * dy);

            if (distance < minDistance * minDistance) {
                double angle = Math.atan2(dy, dx);
                double targetX = circle1.getLayoutX() + Math.cos(angle) * minDistance;
                double targetY = circle1.getLayoutX() + Math.sin(angle) * minDistance;
                double ax = (targetX - circles_Static.get(i).getLayoutX()) * spring;
                double ay = (targetY - circles_Static.get(i).getLayoutY()) * spring;
                c1SpeedX -= ax;
                c1SpeedY -= ay;
                return;

            } 
        }
    }

You can find the full source code below:

public class VideoGame1 extends Application {

    public static List<Circle> circles_Static = new ArrayList<Circle>(); 
    public static Circle circle1;
    public static Circle c1_Static;
    public static Circle c2_Static; 
    public static Circle c3_Static; 
    public static Pane canvas;
    double spring = 1;
    private long counter = 0;
    double c1SpeedX = 1;
    double c1SpeedY = 1;

    @Override
    public void start(Stage primaryStage) {

        canvas = new Pane();
        Scene scene = new Scene(canvas, 800, 600);

        primaryStage.setTitle("Ball Game");
        primaryStage.setScene(scene);
        primaryStage.show();

        c1_Static = new Circle(100, Color.BLACK);
        c1_Static.relocate(300, 200);
        circles_Static.add(c1_Static);

        c2_Static = new Circle(20, Color.CORNFLOWERBLUE);
        c2_Static.relocate(550, 250);
        circles_Static.add(c2_Static);

        c3_Static = new Circle(40, Color.CORAL);
        c3_Static.relocate(500, 500);
        circles_Static.add(c3_Static);

        canvas.getChildren().addAll(circles_Static);

        circle1 = new Circle(30, Color.BLUE);
        circle1.relocate(100, 60);

        canvas.getChildren().addAll(circle1);


        Timeline loop;
        loop = new Timeline(new KeyFrame(Duration.millis(1), new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent t) {
                if (counter++ % 2 == 0) {
                    // Moves the ball
                    circle1.setLayoutX(circle1.getLayoutX() + c1SpeedX);
                    circle1.setLayoutY(circle1.getLayoutY() + c1SpeedY);

// Dynamic ball bounces off the walls
                    final Bounds bounds = canvas.getBoundsInLocal();
                    boolean leftWall = circle1.getLayoutX() <= (bounds.getMinX() + circle1.getRadius());
                    boolean topWall = circle1.getLayoutY() <= (bounds.getMinY() + circle1.getRadius());
                    boolean rightWall = circle1.getLayoutX() >= (bounds.getMaxX() - circle1.getRadius());
                    boolean bottomWall = circle1.getLayoutY() >= (bounds.getMaxY() - circle1.getRadius());

      //Check if dynamic ball collides with any of the static balls

                    collision(); ////// HERE ////////

      // So the issue has gotta be on the line above. The collision() method.


                    // If the bottom or top wall has been touched, the ball reverses direction.
                    if (bottomWall || topWall) {

                        c1SpeedY = c1SpeedY * -1;                     

                    }
                    // If the left or right wall has been touched, the ball reverses direction.
                    if (leftWall || rightWall) {
                        c1SpeedX = c1SpeedX * -1;
                    }
                }

            }

            public void collision() {
                for (int i = 0; i < circles_Static.size(); i++) {
                    double dx = circles_Static.get(i).getLayoutX() - circle1.getLayoutX();
                    double dy = circles_Static.get(i).getLayoutY() - circle1.getLayoutY();
                    double minDistance = circles_Static.get(i).getRadius() + circle1.getRadius();
                    double distance = (dx * dx) + (dy * dy);

                    if (distance < minDistance * minDistance) {
                        double angle = Math.atan2(dy, dx);
                        double targetX = circle1.getLayoutX() + Math.cos(angle) * minDistance;
                        double targetY = circle1.getLayoutX() + Math.sin(angle) * minDistance;
                        double ax = (targetX - circles_Static.get(i).getLayoutX()) * spring;
                        double ay = (targetY - circles_Static.get(i).getLayoutY()) * spring;
                        c1SpeedX -= ax;
                        c1SpeedY -= ay;
                        return;

                    } else {
                        break;
                    }

                }
            }

        }));

        loop.setCycleCount(Timeline.INDEFINITE);
        loop.play();
    }

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

}
\$\endgroup\$
  • \$\begingroup\$ P.S. The algorithm in the method itself is working perfectly, because I've already tested it a dozen times by comparing each circle separately. I think the problem is the ArrayList of static circles. \$\endgroup\$ – Gregg1989 Nov 24 '13 at 1:03
3
\$\begingroup\$

In this line:

double targetY = circle1.getLayoutX() + Math.sin(angle) * minDistance;

Certainly you meant getLayoutY.

As a side note, it is useless to compute angle = atan2(y,x) if the only thing you are doing afterwards is cos(angle) or sin(angle). The cosine and sine of the angle are simply x/sqrt(x²+y²) and y/sqrt(x²+y²), which is also a lot faster to compute.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That was an obvious one, damn. Coding at 3AM doesn't help I guess! Thanks a lot Sam! \$\endgroup\$ – Gregg1989 Nov 24 '13 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.