Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (741)
Games in Android Showcase (225)
games submitted by our members
Games in WIP (823)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Java2D - SAT Collision only works at the beginning of program  (Read 200 times)
0 Members and 2 Guests are viewing this topic.
Offline elaguy

Junior Newbie





« Posted 2017-08-01 14:26:06 »

Hi, I'm working on a small 2D top down racing game and I'm trying to implement SAT collision into my game to detect collision between cars. So, I made a small little Java2D program to test the algorithm out involving two boxes of different sizes.

As far as I can tell, the collision works just fine when one of the boxes are placed initially (in the constructor of the Renderer class where the Box objects are created) so that it must collide with the other box. (For example placing Box A at (250, 200) with width and height=100 and Box B at (300, 150) with width and height=250).

With this setup the program detects the collision, but when I move Box A out of the collision area to some other area of the screen using the arrow keys, the program still detects a "collision". Similarly, if I place Box A so that it will not collide initially and then move it to the other box so that it should collide, the program does not detect a collision no matter where I move Box A around/inside Box B.

I checked and printed out Box A and Box B's four points and it seems Box A's points are updated correctly as Box A moves, and Box B's points stay the same since it is not moving. Both boxes' axes seem to be correct according to my calculations. As far as I know, the SAT algorithm seems to be working since it works when the two boxes are set up to collide immediately, which leads me to think there is a problem with the updating - but I've checked the movement code and everything seems to update correctly, except the collision of course.

Why does the program only detect collision when the two boxes are initially set up to collide immediately and not when I manually move Box A to Box B?

Here's Renderer.java, where the Box objects are created, the collision method called ( hasOverlap() ), and arrow key input is taken.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
public class Renderer extends JPanel implements ActionListener, KeyListener {

private Frame frame;
private Timer timer;

private Box a;
private Box b;

public Renderer(Frame frame) {
    this.frame = frame;

    a = new Box(250, 200, 100, 100);
    b = new Box(300, 150, 250, 250);

    this.addKeyListener(this);
    this.setFocusable(true);

    timer = new Timer(20, this);
    timer.start();
}

private void update() {
    checkCollisions();
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.translate(0, frame.getHeight());
    g2d.scale(1.0, -1.0);

    b.render(g);
    a.render(g);
}

@Override
public void actionPerformed(ActionEvent e) {
    update();
    repaint();
}

private void checkCollisions() {
    if(a.hasOverlap(b)) {
        System.out.println("Overlap");
        a.setColor(Color.RED);
        b.setColor(Color.RED);
    }

    else {
        System.out.println("Not overlapping");
        a.setColor(Color.GREEN);
        b.setColor(Color.BLACK);
    }
}

@Override
public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_LEFT)
        a.translate(-10, 0);

    if(e.getKeyCode() == KeyEvent.VK_RIGHT)
        a.translate(10, 0);

    if(e.getKeyCode() == KeyEvent.VK_UP)
        a.translate(0, 10);

    if(e.getKeyCode() == KeyEvent.VK_DOWN)
        a.translate(0, -10);
}


Here's Box.java, where hasOverlap() the main collision method is, where the points of the box is defined, the axes, etc.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
public class Box {

public float x;
public float y;
public float w;
public float h;
public Vector2D center;
public Vector2D[] points;
public Vector2D[] axes;
public ArrayList<Projection> proj;
private Color color;

public Box(float x, float y, float w, float h) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.center = new Vector2D(w/2 + x, h/2 + y);
    this.points = new Vector2D[4];
    this.proj = new ArrayList<Projection>();
    this.color = Color.BLACK;

    points[0] = new Vector2D(x, y); // Point A
    points[1] = new Vector2D(x, y+h); // Point B
    points[2] = new Vector2D(x+w, y+h); // point C
    points[3] = new Vector2D(x+w, y); // point D

    this.axes = setAxes(points);
}

public void render(Graphics g) {
    g.setColor(color);
    g.fillRect((int) x, (int) y, (int) w, (int) h);
}

public void translate(float x, float y) {
    for(int i = 0; i < points.length; i++) {
        points[i].x += x;
        points[i].y += y;
    }

    center.x += x;
    center.y += y;

    this.x = points[0].x;
    this.y = points[0].y;

    this.axes = setAxes(points);
}

public boolean hasOverlap(Box box) {
    // project and check on this box's axes
    for(int i = 0; i < axes.length; i++) {
        project(axes[i]);
        box.project(axes[i]);

        if(!getOverlap(proj.get(i), box.proj.get(i)))
            return false;
    }

    for(int j = 0; j < box.axes.length; j++) {
        project(box.axes[j]);
        box.project(box.axes[j]);

        if(!getOverlap(proj.get(j), box.proj.get(j)))
            return false;
    }

    return true;
}

// also normalizes the vectors to produce unit axes
private Vector2D[] setAxes(Vector2D[] points) {
    Vector2D[] axes = new Vector2D[points.length];
    Vector2D edge = new Vector2D(0, 0);

    for(int i = 0; i < points.length; i++) {
        if(i + 1 <= points.length - 1)
            edge = sub(points[i], points[i+1]);
        else
            edge = sub(points[i], points[0]);

        axes[i] = norm(getPerp(edge));
    }

    return axes;
}

// projects this box object onto the given axis, stores min and max as a vector for overlap testing
public void project(Vector2D axis) {
    float min = dotProduct(axis, points[0]);
    float max = min;

    for(int i = 1; i < points.length; i++) {
        float current = dotProduct(axis, points[i]);

        if(current < min)
            min = current;
        else if(current > max)
            max = current;
    }

    proj.add(new Projection(min, max));
}

// returns true if there an overlap on the axis
private boolean getOverlap(Projection a, Projection b) {
    return !(b.max < a.min || a.max < b.min);
}

// subtracts two vectors
private Vector2D sub(Vector2D a, Vector2D b) {
    return new Vector2D(a.x - b.x, a.y - b.y);
}

// gets the perpendicular vector of a vector. (x, y) => (y, -x) (with clockwise ordering of points)
private Vector2D getPerp(Vector2D a) {
    return new Vector2D(a.y, (-1) * a.x);
}

// normalizes vector (scales vector to length of 1, aka unit vector)
private Vector2D norm(Vector2D a) {
    float len = (float) (Math.sqrt(a.x*a.x + a.y*a.y));

    return new Vector2D(a.x / len, a.y / len);
}

private float dotProduct(Vector2D a, Vector2D b) {
    return (float) (a.x * b.x + a.y * b.y);
}


Thanks in advance!
Pages: [1]
  ignore  |  Print  
 
 

 
Ecumene (108 views)
2017-09-30 02:57:34

theagentd (135 views)
2017-09-26 18:23:31

cybrmynd (245 views)
2017-08-02 12:28:51

cybrmynd (240 views)
2017-08-02 12:19:43

cybrmynd (238 views)
2017-08-02 12:18:09

Sralse (252 views)
2017-07-25 17:13:48

Archive (864 views)
2017-04-27 17:45:51

buddyBro (1007 views)
2017-04-05 03:38:00

CopyableCougar4 (1566 views)
2017-03-24 15:39:42

theagentd (1373 views)
2017-03-24 15:32:08
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!