Search code examples
javadrawingcollision

Java Collision Detection


I am attempting to detect collisions between two shapes using intersects, however, the detection is not working.

Printing out the Circle objects reveal the x and y positions are set as 0. I suspected that maybe the position getter and setter methods were not working correctly, however, printing out this information reveals non-zero values.

Why is the detection not working?

Thank you.

Edit: The below code is now working. See comments for detail of the issue / solution.

Main Class

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main extends JPanel {

    public static List<Circle> circleList = new ArrayList<>();
    private static Random random = new Random();    

    public Main() {
        for (int i = 0; i < 2; i++) {
            circleList.add(new Circle(random.nextInt(500), random.nextInt(500)));
        }       
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);   
        for (Circle CircleShape : circleList) {
            CircleShape.collision();
            CircleShape.drawCircle(g);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setResizable(true);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new Main());
    }

}

Circle Class

import java.awt.Graphics;

public class Circle extends Shape {

    public Circle(int x, int y) {
        super(x, y); 
        super.setSize(200, 200);
    }

    public void drawCircle(Graphics g) {
        g.setColor(colour);
        g.fillOval(x, y, 200, 200);
    }

    public void collision() {   
        for (Circle CircleShape : Main.circleList) {
            System.out.println(CircleShape);
            System.out.println(CircleShape.getxPos());

            if (this.intersects(CircleShape)) {
                System.out.println("collision detected");
             } else {
                System.out.println("no collision detected");
            }

         }  
    }

}

Shape Class

import java.awt.Color;
import java.awt.Rectangle;

public class Shape extends Rectangle {

    //int x, y;
    Color colour;

    public Shape(int x, int y) {
        //this.setxPos(x);
        //this.setyPos(y);
        this.setPos(x, y);
    }
/*
    public int getxPos() {
        return this.x;
    }

    public void setxPos(int x) {
        this.x = x;
    }

    public int getyPos() {
        return this.y;
    }

    public void setyPos(int y) {
        this.y = y;
    }
*/

    public void setPos(int x, int y) {
        super.setLocation(x, y);
    }

    public Point getPos() {
        return new Point(x, y);
    }

}

Solution

  • The intersects method expect x, y, width and height properties to be correctly set, because they are used to detect if an object collides with another.

    So, in your setter methods you need to invoke super.setLocation(newX, newY), and you should provide a valid width and height too.

    So, it should be:

    public void setxPos(int x) {
        this.x = x;
        super.setLocation(x, y);
    }
    
    public void setyPos(int y) {
        this.y = y;
        super.setLocation(x, y);
    }
    

    and

    public Circle(int x, int y) {
        super(x, y); 
        super.setSize(200, 200);
    }
    

    Or, you could just use the already provided methods from class Rectangle:

    public Circle(int x, int y, int width, int height) {
        super(x, y, width, height);
    }
    

    And also use setLocation instead of setxPos and setyPos.

    The complete code would become like this:

    Shape class

    import java.awt.Color;
    import java.awt.Rectangle;
    
    public class Shape extends Rectangle {
    
        Color colour;
    
        public Shape(int x, int y, int width, int height) {
            // provided by the Rectangle class. Needed for proper collision detection
            super(x, y, width, height);
        }
    }
    

    Circle class:

    import java.awt.Graphics;
    
    public class Circle extends Shape {
    
        public Circle(int x, int y, int width, int height) {
            super(x, y, width, height);
        }
    
        public void drawCircle(Graphics g) {
            g.setColor(super.colour);
            // instead of writing values here, we get them from width and height fields
            g.fillOval(x, y, (int) getWidth(), (int) getHeight());
        }
    
        public void collision() {
            for (Circle CircleShape : Main.circleList) {
                System.out.println(CircleShape);
                System.out.println(CircleShape.getLocation().x);
    
                if (this.intersects(CircleShape)) {
                    System.out.println("collision detected");
                } else {
                    System.out.println("no collision detected");
                }
    
            }
        }
    }
    

    Main class:

    import java.awt.Graphics;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Main extends JPanel {
    
        public static List<Circle> circleList = new ArrayList<>();
        private static Random random = new Random();
    
        public Main() {
            for (int i = 0; i < 2; i++) {
                // width and height are specified here instead of inside the Circle.drawCircle method.
                circleList.add(new Circle(random.nextInt(500), random.nextInt(500), 200, 200));
            }
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Circle CircleShape : circleList) {
                CircleShape.collision();
                CircleShape.drawCircle(g);
            }
        }
    
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            frame.setSize(500, 500);
            frame.setResizable(true);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(new Main());
        }
    
    }