【问题标题】:Detecting collision of two sprites that can rotate [duplicate]检测两个可以旋转的精灵的碰撞[重复]
【发布时间】:2014-01-22 12:17:52
【问题描述】:

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

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

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

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

如何检测与这种精灵的碰撞? 谢谢

【问题讨论】:

  • 哪些物体可以与坦克相撞?也只有矩形?
  • 是的,只有矩形。

标签: java sprite collision bounding-box


【解决方案1】:

如果您将坦克可能遇到的所有对象都保存在一个 ArrayList 中,然后在单独的线程中的循环中使用 for 语句来确定坦克是否撞到了什么东西,那会怎样。例如,为每个对象创建一个类,例如类 Wall(),并保持 x、y 变量可用。将 Wall() 放入 ArrayList,在本例中为坦克。然后在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() 语句相交。欧共体:

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

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

【讨论】:

  • 这是我的问题。我不知道水箱填充的区域是什么,因为它可以旋转到任何角度,因此填充的区域会发生变化。
  • 啊,我明白了.. 好吧,如果你的坦克 x 是 0,你的坦克宽度是 5,那么你的坦克是 5 长。如果你的身高是 10,那么你的坦克的面积是 50。这永远是正确的。要在实际绘制的表面上找到线本身,请使用斜率截距形式。 y=mx+b。或者如果你有两个点,(y2-y1)/(x2-x1)。 x1 或 x2 是坦克无关紧要,与 y 相同。这将找到您的线的斜率,在平面(比赛表面)上,斜率 1 表示在图表上,从原点上升一个单位,右一个单位
  • 基本上,线性代数的良好知识将帮助您检测旋转碰撞
  • 是的,谢谢,我想这就是我想说的一句话,哈哈。
【解决方案2】:

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

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

但是,这将手动计算 (x,y) 角。可能有某种方法可以通过旋转矩形来构造形状,但这至少可以工作。它有一个getBounds() 方法。

【讨论】:

    【解决方案3】:

    很大程度上取决于您管理对象的方式,但是...

    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();
            }
    
        }
    
    }
    

    基本上,这是做什么的,它会创建RectanglePathIterator,它允许我将AffineTransformation 应用于形状而不影响原始形状...不知道这是否重要与否,但我就是这样做的......

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

    现在,时髦一点...

    我创建了两个Areas,每个GeneralPath 一个代表我要检查的每个对象。然后我使用Areaintersect方法,生成一个Area,表示两个对象的交点,然后检查这个结果是否为空。

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

    玩得开心;)

    【讨论】:

    • 忘记吧。我只是看着看着它很开心! :)
    • @peeskillet 鉴于我做过的其他一些碰撞检测工作(不是很多),这绝对是最简单的;)
    • 我还没有真正接触到碰撞检测,所以我仍然惊叹不已!我没有意识到涉及的代码如此之少。
    • @peeskillet 这取决于你有什么可用的。 Graphics2D API 非常强大。我还做了thisthisthis 的例子,它们具有不同程度的复杂性——这是最简单的;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2019-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多