问题描述
我正在用Java创建游戏,并且正在使用BufferedImages在屏幕上显示项目.这些图像的边界上具有透明像素,因此对象不是正方形,而是独特的形状.此外,对象可能会在屏幕上旋转.如何检测两个图像之间的碰撞?
I am creating a game in Java, and I am using BufferedImages to show items on the screen. These images have transparent pixels on their borders, so the objects are not squares but unique shapes. Additionally, the objects may rotate on screen. How can I detect collisions between two images?
我的第一个想法是生成每个图像中像素所有位置的列表,然后检测两个图像是否共享像素的任何位置.但是,此方法效率低下,我不确定如何生成这些列表.你有什么主意吗?
My first thought was to generate a list of all of the locations of the pixels in each image, and then detect if any of the locations of the pixels are shared by the two images. However, this method seems inefficient, and I am not sure how to generate these lists. Do you have any ideas?
推荐答案
基本方法是首先确定图像边界是否存在冲突.
The basic approach would be to first determine if there is collision of the image boundaries.
如果两个图像重叠,则需要确定图像中是否有任何非透明像素重叠/碰撞.
If the two images overlap, you will need to determine if any of non-transparent pixels in the image overlap/collide.
这可以通过使用 BufferedImage#getRGB
作为示例,请查看回答
已更新示例
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentImageCollision {
public static void main(String[] args) {
new TransparentImageCollision();
}
public TransparentImageCollision() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage fly;
private BufferedImage spider;
private Rectangle spiderBounds;
private Rectangle flyBounds;
private Point spiderDelta;
private Point flyDelta;
private Rectangle collision;
public TestPane() {
try {
fly = ImageIO.read(getClass().getResource("/fly.png"));
spider = ImageIO.read(getClass().getResource("/spider.png"));
Dimension size = getPreferredSize();
int width = size.width;
int height = size.height;
spiderBounds = new Rectangle();
spiderBounds.setSize(spider.getWidth(), spider.getHeight());
spiderBounds.setLocation(0, (height - spider.getHeight()) / 2);
flyBounds = new Rectangle();
flyBounds.setSize(fly.getWidth(), fly.getHeight());
flyBounds.setLocation(width - fly.getWidth(), (height - fly.getHeight()) / 2);
spiderDelta = new Point(1, 0);
flyDelta = new Point(-1, 0);
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update(spiderBounds, spiderDelta);
update(flyBounds, flyDelta);
detectCollision();
repaint();
}
});
timer.start();
} catch (IOException exp) {
exp.printStackTrace();
}
}
protected void update(Rectangle bounds, Point delta) {
bounds.x += delta.x;
bounds.y += delta.y;
if (bounds.x < 0) {
bounds.x = 0;
delta.x *= -1;
}
if (bounds.x + bounds.width > getWidth()) {
bounds.x = getWidth() - bounds.width;
delta.x *= -1;
}
if (bounds.y < 0) {
bounds.y = 0;
delta.y *= -1;
}
if (bounds.y + bounds.height > getHeight()) {
bounds.y = getHeight() - bounds.height;
delta.y *= -1;
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(spider, spiderBounds.x, spiderBounds.y, this);
g2d.drawImage(fly, flyBounds.x, flyBounds.y, this);
if (collision != null) {
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fill(collision);
}
g2d.dispose();
}
/**
* Used to detect the collision between non-alpha portions of the two
* images
*/
protected void detectCollision() {
collision = null;
// Check if the boundires intersect
if (spiderBounds.intersects(flyBounds)) {
// Calculate the collision overlay
Rectangle bounds = getCollision(spiderBounds, flyBounds);
if (!bounds.isEmpty()) {
// Check all the pixels in the collision overlay to determine
// if there are any non-alpha pixel collisions...
for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
if (collision(x, y)) {
collision = bounds;
break;
}
}
}
}
}
}
protected Rectangle getCollision(Rectangle rect1, Rectangle rect2) {
Area a1 = new Area(rect1);
Area a2 = new Area(rect2);
a1.intersect(a2);
return a1.getBounds();
}
/**
* Test if a given x/y position of the images contains transparent
* pixels or not...
* @param x
* @param y
* @return
*/
protected boolean collision(int x, int y) {
boolean collision = false;
int spiderPixel = spider.getRGB(x - spiderBounds.x, y - spiderBounds.y);
int flyPixel = fly.getRGB(x - flyBounds.x, y - flyBounds.y);
// 255 is completely transparent, you might consider using something
// a little less absolute, like 225, to give you a sligtly
// higher hit right, for example...
if (((spiderPixel >> 24) & 0xFF) < 255 && ((flyPixel >> 24) & 0xFF) < 255) {
collision = true;
}
return collision;
}
}
}
这篇关于如何检测两个图像是否在Java中发生冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!