Skip to content

Commit cef898c

Browse files
authored
Image collision detection (#18514)
1 parent 6373ae4 commit cef898c

File tree

4 files changed

+211
-0
lines changed

4 files changed

+211
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package com.baeldung.imagecollision;
2+
3+
import javax.imageio.ImageIO;
4+
import javax.swing.*;
5+
import java.awt.*;
6+
import java.awt.geom.Area;
7+
import java.awt.geom.Ellipse2D;
8+
import java.awt.image.BufferedImage;
9+
import java.io.File;
10+
import java.io.IOException;
11+
12+
public class Game extends JPanel implements Runnable {
13+
GameObject vader, luke;
14+
BufferedImage vaderImage, lukeImage;
15+
Thread gameThread;
16+
17+
boolean collided = false;
18+
19+
enum CollisionType {
20+
BOUNDING_BOX,
21+
AREA_CIRCLE,
22+
CIRCLE_DISTANCE,
23+
POLYGON,
24+
PIXEL_PERFECT
25+
}
26+
27+
CollisionType collisionType = CollisionType.PIXEL_PERFECT;
28+
29+
public Game() {
30+
try {
31+
vaderImage = ImageIO.read(new File("src/main/resources/images/vader.png"));
32+
lukeImage = ImageIO.read(new File("src/main/resources/images/luke.png"));
33+
34+
vader = new GameObject(170, 370, vaderImage);
35+
luke = new GameObject(1600, 370, lukeImage);
36+
37+
} catch (IOException e) {
38+
System.err.println("Error loading images");
39+
e.printStackTrace();
40+
}
41+
42+
setBackground(Color.white);
43+
gameThread = new Thread(this);
44+
gameThread.start();
45+
}
46+
47+
public void run() {
48+
while (!collided) {
49+
vader.move(2, 0);
50+
luke.move(-2, 0);
51+
52+
switch (collisionType) {
53+
case BOUNDING_BOX:
54+
if (vader.getRectangleBounds().intersects(luke.getRectangleBounds())) {
55+
collided = true;
56+
}
57+
break;
58+
59+
case AREA_CIRCLE:
60+
Area ellipseAreaVader = vader.getEllipseAreaBounds();
61+
Area ellipseAreaLuke = luke.getEllipseAreaBounds();
62+
ellipseAreaVader.intersect(ellipseAreaLuke);
63+
64+
if (!ellipseAreaVader.isEmpty()) {
65+
collided = true;
66+
}
67+
break;
68+
69+
case CIRCLE_DISTANCE:
70+
Ellipse2D circleVader = vader.getCircleBounds();
71+
Ellipse2D circleLuke = luke.getCircleBounds();
72+
double dx = circleVader.getCenterX() - circleLuke.getCenterX();
73+
double dy = circleVader.getCenterY() - circleLuke.getCenterY();
74+
double distance = Math.sqrt(dx * dx + dy * dy);
75+
double radiusVader = circleVader.getWidth() / 2.0;
76+
double radiusLuke = circleLuke.getWidth() / 2.0;
77+
78+
if (distance < radiusVader + radiusLuke) {
79+
collided = true;
80+
}
81+
break;
82+
83+
case POLYGON:
84+
Area polygonAreaVader = vader.getPolygonBounds();
85+
Area polygonAreaLuke = luke.getPolygonBounds();
86+
polygonAreaVader.intersect(polygonAreaLuke);
87+
88+
if (!polygonAreaVader.isEmpty()) {
89+
collided = true;
90+
}
91+
break;
92+
93+
case PIXEL_PERFECT:
94+
if (vader.collidesWith(luke)) {
95+
collided = true;
96+
}
97+
break;
98+
}
99+
100+
repaint();
101+
102+
try {
103+
Thread.sleep(16);
104+
} catch (InterruptedException e) {
105+
throw new RuntimeException(e);
106+
}
107+
}
108+
}
109+
110+
protected void paintComponent(Graphics g) {
111+
super.paintComponent(g);
112+
vader.draw(g);
113+
luke.draw(g);
114+
115+
if (collided) {
116+
g.setColor(Color.RED);
117+
g.setFont(new Font("SansSerif", Font.BOLD, 50));
118+
g.drawString("COLLISION!", getWidth() / 2 - 100, getHeight() / 2);
119+
}
120+
}
121+
122+
public static void main(String[] args) {
123+
SwingUtilities.invokeLater(() -> {
124+
JFrame frame = new JFrame("Epic Duel");
125+
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
126+
frame.setSize(1920, 1080);
127+
frame.add(new Game());
128+
frame.setVisible(true);
129+
});
130+
}
131+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.baeldung.imagecollision;
2+
3+
import java.awt.*;
4+
import java.awt.geom.Area;
5+
import java.awt.geom.Ellipse2D;
6+
import java.awt.image.BufferedImage;
7+
8+
public class GameObject {
9+
public int x, y;
10+
public int width, height;
11+
public BufferedImage image;
12+
13+
int[] xPoints = new int[4];
14+
int[] yPoints = new int[4];
15+
16+
int[] xOffsets = {100, 200, 100, 0};
17+
int[] yOffsets = {0, 170, 340, 170};
18+
19+
public GameObject(int x, int y, BufferedImage image) {
20+
this.x = x;
21+
this.y = y;
22+
this.image = image;
23+
this.width = image.getWidth();
24+
this.height = image.getHeight();
25+
}
26+
27+
public void move(int dx, int dy) {
28+
x += dx;
29+
y += dy;
30+
}
31+
32+
public void draw(Graphics g) {
33+
g.drawImage(image, x, y, null);
34+
}
35+
36+
public Rectangle getRectangleBounds() {
37+
return new Rectangle(x, y, width, height);
38+
}
39+
40+
public Area getEllipseAreaBounds() {
41+
Ellipse2D.Double coll = new Ellipse2D.Double(x, y, width, height);
42+
return new Area(coll);
43+
}
44+
45+
public Ellipse2D getCircleBounds() {
46+
return new Ellipse2D.Double(x, y, 200, 200);
47+
}
48+
49+
public Area getPolygonBounds() {
50+
for (int i = 0; i < xOffsets.length; i++) {
51+
this.xPoints[i] = x + xOffsets[i];
52+
this.yPoints[i] = y + yOffsets[i];
53+
}
54+
Polygon p = new Polygon(xPoints, yPoints, xOffsets.length);
55+
56+
return new Area(p);
57+
}
58+
59+
public boolean collidesWith(GameObject other) {
60+
int top = Math.max(y, other.y);
61+
int bottom = Math.min(y + height, other.y + other.height);
62+
int left = Math.max(x, other.x);
63+
int right = Math.min(x + width, other.x + other.height);
64+
65+
if (right <= left || bottom <= top) return false;
66+
67+
for (int i = top; i < bottom; i++) {
68+
for (int j = left; j < right; j++) {
69+
int pixel1 = image.getRGB(j - x, i - y);
70+
int pixel2 = other.image.getRGB(j - other.x, i - other.y);
71+
72+
if (((pixel1 >> 24) & 0xff) > 0 && ((pixel2 >> 24) & 0xff) > 0) {
73+
return true;
74+
}
75+
}
76+
}
77+
return false;
78+
}
79+
}
80+
40.9 KB
Loading
58.6 KB
Loading

0 commit comments

Comments
 (0)