检测可旋转的两个精灵的碰撞

时间:2014-01-04 21:51:04

标签: java sprite collision bounding-box

我在2D Java游戏中遇到碰撞检测问题。

通常,我要做的是为可能与其他对象冲突的对象创建一个getBounds()方法。此方法将返回new Rectangle(x,y,width,height),其中xy是精灵左上角的坐标,widthheight是精灵的宽度和高度。

但是在我正在进行的游戏中,有一个由用户控制的“坦克”。只要玩家持有左箭头或右箭头按钮之一,该坦克的精灵就会旋转。换句话说,它可以旋转到任何角度。坦克的精灵是一个矩形。

所以我不能简单地做我在这种情况下经常做的事情。

如何检测与此类精灵的碰撞? 感谢

3 个答案:

答案 0 :(得分:4)

很多将取决于您如何管理对象,但......

Rotate....

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class RotateTest {

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

    public RotateTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Rectangle rect01;
        private Rectangle rect02;

        private int angle = 0;

        public TestPane() {

            rect01 = new Rectangle(0, 0, 100, 100);
            rect02 = new Rectangle(0, 0, 100, 100);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle++;
                    repaint();
                }
            });
            timer.start();

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(250, 250);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int width = getWidth();
            int height = getHeight();

            AffineTransform at = new AffineTransform();

            int center = width / 2;

            int x = center + (center - rect01.width) / 2;
            int y = (height - rect01.height) / 2;
            at.translate(x, y);
            at.rotate(Math.toRadians(angle), rect01.width / 2, rect01.height / 2);
            GeneralPath path1 = new GeneralPath();
            path1.append(rect01.getPathIterator(at), true);
            g2d.fill(path1);

            g2d.setColor(Color.BLUE);
            g2d.draw(path1.getBounds());

            at = new AffineTransform();
            x = (center - rect02.width) / 2;
            y = (height - rect02.height) / 2;
            at.translate(x, y);
            at.rotate(Math.toRadians(-angle), rect02.width / 2, rect02.height / 2);
            GeneralPath path2 = new GeneralPath();
            path2.append(rect01.getPathIterator(at), true);
            g2d.fill(path2);

            g2d.setColor(Color.BLUE);
            g2d.draw(path2.getBounds());

            Area a1 = new Area(path1);
            Area a2 = new Area(path2);
            a2.intersect(a1);
            if (!a2.isEmpty()) {
                g2d.setColor(Color.RED);
                g2d.fill(a2);
            }

            g2d.dispose();
        }

    }

}

基本上,它的作用是,它会创建PathIterator的{​​{1}},这样我就可以在不影响原始形状的情况下将Rectangle应用于形状...不要知道这是否重要,但这就是我做的方式......

然后我创建了一个AffineTransformation,它允许我绘制GeneralPath

现在,时髦的位......

我创建两个PathIterator,每个Area一个代表我要检查的每个对象。然后我使用GeneralPath的{​​{1}}方法生成Area,表示两个对象的交点,然后检查此结果是否为空。

如果它是空的,它不相交,如果它不是(空的),它们会触摸。

玩得很开心;)

答案 1 :(得分:0)

如果保留坦克可以在ArrayList中运行的所有对象,并且只是在一个单独的线程中的循环中使用for语句来确定坦克是否击中了什么,该怎么办?例如,为每个对象创建一个类,比如类Wall(),并保持x,y变量可用。将Wall()放入ArrayList,在本例中为tank。然后在for循环中,在while循环中:EC

while(true) {
    for(int i = 0; i < tanks.size(); i++) {
         //Do the code to determine if the tank has hit something.
         if(tanks.get(i).x => tank.x) //Do whatever
    }
}

当然要根据你的需要进行调整,但想法是一样的。如果物体与水箱相交,反之亦然,那就做你想做的事。总结一下,只需检查油箱占用的区域,看看该区域是否与另一个物体相交。

实际上,甚至更好:

我假设你使用paint()方法?每当你更新组件时,只需添加一些基本上与我刚才所说的相同的代码,检查该区域是否与if()语句相交。 EC:

 if(tanks.get(i).x => tank.x || tanks.get(i).y => tank.y) DO SOMETHING

当然,再次调整if()以满足您的需求

答案 2 :(得分:0)

您可以使用多边形而不是矩形。

http://docs.oracle.com/javase/7/docs/api/java/awt/Polygon.html

然而,这将手动计算(x,y)角。有可能通过旋转Rectangle来构造一个形状,但这至少可以起作用。它有一个getBounds()方法。