【问题标题】:Collision Detection between two images in JavaJava中两个图像之间的碰撞检测
【发布时间】:2008-12-02 21:53:15
【问题描述】:

我正在编写的游戏中有两个角色,玩家和敌人。定义如下:

public void player(Graphics g) {
    g.drawImage(plimg, x, y, this);
}

public void enemy(Graphics g) {
    g.drawImage(enemy, 200, 200, this);
}

然后调用:

player(g);
enemy(g);

我可以用键盘移动 player(),但是当我试图检测两者之间的碰撞时我不知所措。很多人都说要使用矩形,但作为一个初学者,我看不出如何将它链接到我现有的代码中。谁能给我一些建议?

【问题讨论】:

    标签: java collision-detection


    【解决方案1】:

    我认为你的问题是你没有为你的玩家和敌人使用好的 OO 设计。创建两个类:

    public class Player
    {
        int X;
        int Y;
        int Width;
        int Height;
    
        // Getters and Setters
    }
    
    public class Enemy
    {
        int X;
        int Y;
        int Width;
        int Height;
    
        // Getters and Setters
    }
    

    您的播放器应该有 X、Y、Width 和 Height 变量。

    你的敌人也应该如此。

    在您的游戏循环中,执行以下操作 (C#):

    foreach (Enemy e in EnemyCollection)
    {
        Rectangle r = new Rectangle(e.X,e.Y,e.Width,e.Height);
        Rectangle p = new Rectangle(player.X,player.Y,player.Width,player.Height);
    
        // Assuming there is an intersect method, otherwise just handcompare the values
        if (r.Intersects(p))
        {
           // A Collision!
           // we know which enemy (e), so we can call e.DoCollision();
           e.DoCollision();
        }
    }
    

    为了加快速度,不要费心检查敌人的坐标是否在屏幕外。

    【讨论】:

    • 正确。我的 OO 技能很糟糕,我的大部分游戏都存在于一个文件中。您的方法有效,但我在尝试将这个文件分成其各自的类方面做了很多工作。
    • 哦,因为...把 Rectangles 放到 Player 和 Enemy 类中。 r = e.getRectangle(); 更快,更舒适。
    【解决方案2】:

    首先,使用Jonathan Holland 描述的边界框来确定是否可能发生碰撞。

    从(多色)精灵创建黑白版本。如果你的精灵是透明的,你可能已经有了这些(即边界框内有一些地方,但你仍然可以看到背景)。这些是“面具”。

    在蒙版上使用Image.getRGB() 来获取像素。对于每个不透明的像素,在一个整数数组中设置一个位(playerArrayenemyArray 下面)。如果width <= 32 像素,则数组的大小为height,否则为(width+31)/32*height。以下代码用于width <= 32

    如果边界框发生碰撞,请执行以下操作:

    // Find the first line where the two sprites might overlap
    int linePlayer, lineEnemy;
    if (player.y <= enemy.y) {
        linePlayer = enemy.y - player.y;
        lineEnemy = 0;
    } else {
        linePlayer = 0;
        lineEnemy = player.y - enemy.y;
    }
    int line = Math.max(linePlayer, lineEnemy);
    
    // Get the shift between the two
    x = player.x - enemy.x;
    int maxLines = Math.max(player.height, enemy.height);
    for ( line < maxLines; line ++) {
        // if width > 32, then you need a second loop here
        long playerMask = playerArray[linePlayer];
        long enemyMask = enemyArray[lineEnemy];
        // Reproduce the shift between the two sprites
        if (x < 0) playerMask << (-x);
        else enemyMask << x;
        // If the two masks have common bits, binary AND will return != 0
        if ((playerMask & enemyMask) != 0) {
            // Contact!
        }
    
    }
    

    链接:JGameFramework for Small Java Games

    【讨论】:

      【解决方案3】:

      您不希望在绘画代码中包含碰撞检查代码。绘画需要快速。碰撞可以进入游戏循环。因此,您需要独立于其精灵的对象的内部表示。

      【讨论】:

        【解决方案4】:

        这是我的碰撞检测程序中的主要类。
        你可以看到它运行在:http://www.youtube.com/watch?v=JIXhCvXgjsQ

        /**
         *
         * @author Tyler Griffin
         */
        import java.awt.*;
        import javax.swing.*;
        import java.awt.event.*;
        import java.awt.GraphicsDevice.*;
        import java.util.ArrayList;
        import java.awt.Graphics;
        import java.awt.geom.Line2D;
        
        
        public class collision extends JFrame implements KeyListener, MouseMotionListener, MouseListener
        {
            ArrayList everything=new ArrayList<tile>();
        
            int time=0, x, y, width, height, up=0, down=0, left=0, right=0, mouse1=0, mouse2=0;
            int mouseX, mouseY;
        
            GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice screen = environment.getDefaultScreenDevice();
            DisplayMode displayMode = screen.getDisplayMode();
        
            //private BufferStrategy strategy;
        
            JLayeredPane pane = new JLayeredPane();
        
             tile Tile;
             circle Circle;
             rectangle Rectangle;
        
                 textPane text;
        
            public collision()
            {
                setUndecorated(screen.isFullScreenSupported());
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setVisible(true);
                setLayout(null);
                setResizable(false);
                screen.setFullScreenWindow(this);
        
        
                width=displayMode.getWidth();
                height=displayMode.getHeight();
        
        
                  Circle=new circle(-(int)Math.round((double)height/7*2),-(int)Math.round((double)height/7*2),(int)Math.round((double)height/7*.85),this);
                  Rectangle=new rectangle(-(int)Math.round((double)height/7*1.5),-(int)Math.round((double)height/7*1.5),(int)Math.round((double)height/7*1.5),(int)Math.round((double)height/7*1.5),this);
                  Tile=Circle;
                  Tile.move(mouseX-Tile.width/2, mouseY-Tile.height/2);
                          text=new textPane(0,0,width,height,this);
        
                  everything.add(new circle((int)Math.round((double)width/100*75),(int)Math.round((double)height/100*15),(int)Math.round((double)width/100*10),this));
                          everything.add(new rectangle((int)Math.round((double)width/100*70),(int)Math.round((double)height/100*60),(int)Math.round((double)width/100*20),(int)Math.round((double)height/100*20),this));
                          //everything.add(new line(750,250,750,750,this));
                          /*everything.add(new line(width/700*419,height/700*68,width/700*495,height/700*345,this));
                          everything.add(new line(width/700*495,height/700*345,width/700*749,height/700*350,this));
                          everything.add(new line(width/700*749,height/700*350,width/700*549,height/700*519,this));
                          everything.add(new line(width/700*549,height/700*519,width/700*624,height/700*800,this));
                          everything.add(new line(width/700*624,height/700*800,width/700*419,height/700*638,this));
                          everything.add(new line(width/700*419,height/700*638,width/700*203,height/700*800,this));
                          everything.add(new line(width/700*203,height/700*800,width/700*279,height/700*519,this));
                          everything.add(new line(width/700*279,height/700*519,width/700*76,height/700*350,this));
                          everything.add(new line(width/700*76,height/700*350,width/700*333,height/700*345,this));
                          everything.add(new line(width/700*333,height/700*345,width/700*419,height/700*68,this));
        
                          everything.add(new line(width/950*419,height/700*68,width/950*624,height/700*800,this));
                          everything.add(new line(width/950*419,height/700*68,width/950*203,height/700*800,this));
                          everything.add(new line(width/950*76,height/700*350,width/950*624,height/700*800,this));
                          everything.add(new line(width/950*203,height/700*800,width/950*749,height/700*350,this));
                          everything.add(new rectangle(width/950*76,height/700*350,width/950*673,1,this));*/
        
                          everything.add(new line((int)Math.round((double)width/1350*419),(int)Math.round((double)height/1000*68),(int)Math.round((double)width/1350*624),(int)Math.round((double)height/1000*800),this));
                          everything.add(new line((int)Math.round((double)width/1350*419),(int)Math.round((double)height/1000*68),(int)Math.round((double)width/1350*203),(int)Math.round((double)height/1000*800),this));
                          everything.add(new line((int)Math.round((double)width/1350*76),(int)Math.round((double)height/1000*350),(int)Math.round((double)width/1350*624),(int)Math.round((double)height/1000*800),this));
                          everything.add(new line((int)Math.round((double)width/1350*203),(int)Math.round((double)height/1000*800),(int)Math.round((double)width/1350*749),(int)Math.round((double)height/1000*350),this));
                          everything.add(new rectangle((int)Math.round((double)width/1350*76),(int)Math.round((double)height/1000*350),(int)Math.round((double)width/1350*673),1,this));
        
        
                addKeyListener(this);
                addMouseMotionListener(this);
                addMouseListener(this);
            }
        
            public void keyReleased(KeyEvent e)
            {
                Object source=e.getSource();
        
                int released=e.getKeyCode();
        
                if (released==KeyEvent.VK_A){left=0;}
                if (released==KeyEvent.VK_W){up=0;}
                if (released==KeyEvent.VK_D){right=0;}
                if (released==KeyEvent.VK_S){down=0;}
            }//end keyReleased
        
        
            public void keyPressed(KeyEvent e)
            {
                Object source=e.getSource();
        
                int pressed=e.getKeyCode();
        
                if (pressed==KeyEvent.VK_A){left=1;}
                if (pressed==KeyEvent.VK_W){up=1;}
                if (pressed==KeyEvent.VK_D){right=1;}
                if (pressed==KeyEvent.VK_S){down=1;}
        
                if (pressed==KeyEvent.VK_PAUSE&&pressed==KeyEvent.VK_P)
                {
                    //if (paused==0){paused=1;}
                    //else paused=0;
                }
            }//end keyPressed
        
            public void keyTyped(KeyEvent e){}
        
        //***********************************************************************************************
        
            public void mouseDragged(MouseEvent e)
            {
                mouseX=(e.getX());
                mouseY=(e.getY());
        
                  //run();
            }
        
            public void mouseMoved(MouseEvent e)
            {
                mouseX=(e.getX());
                mouseY=(e.getY());
        
                  //run();
            }
        
        //***********************************************************************************************
        
            public void mousePressed(MouseEvent e)
            {
                if(e.getX()==0 && e.getY()==0){System.exit(0);}
        
            mouseX=(e.getX()+x);
                mouseY=(e.getY()+y);
        
                if(Tile instanceof circle)
                {
                        Circle.move(0-Circle.width, 0-Circle.height);
                        Circle.setBounds(Circle.x, Circle.y, Circle.width, Circle.height);
                        Tile=Rectangle;
                }
                else
                {
                        Rectangle.move(0-Rectangle.width, 0-Rectangle.height);
                        Rectangle.setBounds(Rectangle.x, Rectangle.y, Rectangle.width, Rectangle.height);
                        Tile=Circle;
                }
        
                Tile.move(mouseX-Tile.width/2, mouseY-Tile.height/2);
            }
        
            public void mouseReleased(MouseEvent e)
            {
                 //run();
            }
        
            public void mouseEntered(MouseEvent e){}
            public void mouseExited(MouseEvent e){}
        
            public void mouseClicked(MouseEvent e){}
        
        //***********************************************************************************************
        
            public void run()//run collision detection
            {
                while (this == this)
                {
                    Tile.move(Tile.x + ((mouseX - (Tile.x + (Tile.width / 2))) / 10), Tile.y + ((mouseY - (Tile.y + (Tile.height / 2))) / 10));
                    //Tile.move((mouseX - Tile.width / 2), mouseY - (Tile.height / 2));
        
                    for (int i = 0; i < everything.size(); i++)
                    {
                        tile Temp = (tile) everything.get(i);
        
                        if (Temp.x < (Tile.x + Tile.width) && (Temp.x + Temp.width) > Tile.x && Temp.y < (Tile.y + Tile.height) && (Temp.y + Temp.height) > Tile.y)//rectangles collided
                        {
                            if (Temp instanceof rectangle)
                            {
                                if (Tile instanceof rectangle){rectangleRectangle(Temp);}
                                else {circleRectangle(Temp);}//Tile instanceof circle
                            }
                            else
                            {
                                if (Temp instanceof circle)
                                {
                                    if (Tile instanceof rectangle) {rectangleCircle(Temp);}
                                    else {circleCircle(Temp);}
                                }
                                else//line
                                {
                                    if (Tile instanceof rectangle){rectangleLine(Temp);}
                                    else{circleLine(Temp);}
                                }
                            }
                        }//end if
                    }//end for
        
                    try {Thread.sleep(16L);}
                    catch (Exception e) {}
        
                    Tile.setBounds(Tile.x, Tile.y, Tile.width, Tile.height);
                    //Rectangle.setBounds(x, y, width, height);
                    //Circle.setBounds(x, y, width, height);
                    repaint();
        
                    text.out=" ";
                }//end while loop
            }//end run
        
        //***************************************special collision detection/handling functions************************************************
        
            void rectangleRectangle(tile Temp)
            {
                int lapTop, lapBot, lapLeft, lapRight, small, scootX=0, scootY=0;
        
                lapTop=(Temp.y+Temp.height)-Tile.y;
                lapBot=(Tile.y+Tile.height)-Temp.y;
                lapLeft=(Temp.x+Temp.width)-Tile.x;
                lapRight=(Tile.x+Tile.width)-Temp.x;
        
                small=999999999;
        
                if (lapTop<small){small=lapTop; scootX=0; scootY=lapTop;}
                if (lapBot<small){small=lapBot; scootX=0; scootY=lapBot*-1;}
                        if (lapLeft<small){small=lapLeft; scootX=lapLeft; scootY=0;}
                        if (lapRight<small){small=lapRight; scootX=lapRight*-1; scootY=0;}
        
                Tile.move(Tile.x+scootX, Tile.y+scootY);text.out="collision detected!";
            }
        
        
        
            void circleRectangle(tile Temp)
            {
                if((Tile.x+Tile.width/2<=Temp.x+Temp.width && Tile.x+Tile.width/2>=Temp.x)||(Tile.y+Tile.height/2>=Temp.y && Tile.y+Tile.height/2<=Temp.y+Temp.height))
                {
                    rectangleRectangle(Temp);
                }
                else//push from nearest corner
                {
                    int x,y;
                    if(Tile.x+Tile.width/2>Temp.x+Temp.width && Tile.y+Tile.height/2<Temp.y){x=Temp.x+Temp.width; y=Temp.y;}
                    else if(Tile.x+Tile.width/2<Temp.x && Tile.y+Tile.height/2<Temp.y){x=Temp.x; y=Temp.y;}
                    else if(Tile.x+Tile.width/2>Temp.x+Temp.width && Tile.y+Tile.height/2>Temp.y+Temp.height){x=Temp.x+Temp.width; y=Temp.y+Temp.height;}
                    else {x=Temp.x; y=Temp.y+Temp.height;}
        
                    double distance = Math.sqrt(Math.pow(Tile.x+(Tile.width/2) - x, 2) + Math.pow(Tile.y+(Tile.height/2) - y, 2));
        
                    if((int)Math.round(distance)<Tile.height/2)
                    {
                                     double normY = ((Tile.y+(Tile.height/2) - y) / distance);
                                     double normX = ((Tile.x+(Tile.width/2) - x) / distance);
        
                                    Tile.move(x-Tile.width/2+(int)Math.round(normX*((Tile.width/2))) , y-Tile.height/2+(int)Math.round(normY*((Tile.height/2))));text.out="collision detected!";
                    }
                }
            }
        
        
        
            void rectangleCircle(tile Temp)
            {
                if((Temp.x+Temp.width/2<=Tile.x+Tile.width && Temp.x+Temp.width/2>=Tile.x)||(Temp.y+Temp.height/2>=Tile.y && Temp.y+Temp.height/2<=Tile.y+Tile.height))
                {
                    rectangleRectangle(Temp);
                }
                else//push from nearest corner
                {
                    int x,y;
                    if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2<Tile.y){x=Tile.x+Tile.width; y=Tile.y;}
                    else if(Temp.x+Temp.width/2<Tile.x && Temp.y+Temp.height/2<Tile.y){x=Tile.x; y=Tile.y;}
                    else if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2>Tile.y+Tile.height){x=Tile.x+Tile.width; y=Tile.y+Tile.height;}
                    else {x=Tile.x; y=Tile.y+Tile.height;}
        
                    double distance = Math.sqrt(Math.pow(Temp.x+(Temp.width/2) - x, 2) + Math.pow(Temp.y+(Temp.height/2) - y, 2));
        
                    if((int)Math.round(distance)<Temp.height/2)
                    {
                     double normY = ((Temp.y+(Temp.height/2) - y) / distance);
                     double normX = ((Temp.x+(Temp.width/2) - x) / distance);
        
                     if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2<Tile.y){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2)))-Tile.width,(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2))));text.out="collision detected!";}
                        else if(Temp.x+Temp.width/2<Tile.x && Temp.y+Temp.height/2<Tile.y){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2))),(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2))));text.out="collision detected!";}
                        else if(Temp.x+Temp.width/2>Tile.x+Tile.width && Temp.y+Temp.height/2>Tile.y+Tile.height){Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2)))-Tile.width,(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2)))-Tile.height);text.out="collision detected!";}
                        else {Tile.move((Temp.x+Temp.width/2)-(int)Math.round(normX*((Temp.width/2))),(Temp.y+Temp.height/2)-(int)Math.round(normY*((Temp.height/2)))-Tile.height);text.out="collision detected!";}
                    }
                }
            }
        
        
        
        
            void circleCircle(tile Temp)
            {
                double distance = Math.sqrt(Math.pow((Tile.x+(Tile.width/2)) - (Temp.x+(Temp.width/2)),2) + Math.pow((Tile.y+(Tile.height/2)) - (Temp.y+(Temp.height/2)), 2));
        
                if((int)distance<(Tile.width/2+Temp.width/2))
                {
                                double normX = ((Tile.x+(Tile.width/2)) - (Temp.x+(Temp.width/2))) / distance;
                                double normY = ((Tile.y+(Tile.height/2)) - (Temp.y+(Temp.height/2))) / distance;
        
                    Tile.move((Temp.x+(Temp.width/2))+(int)Math.round(normX*(Tile.width/2+Temp.width/2))-(Tile.width/2) , (Temp.y+(Temp.height/2))+(int)Math.round(normY*(Tile.height/2+Temp.height/2))-(Tile.height/2));text.out="collision detected!";
                }
            }
        
        
        
            void circleLine(tile Temp)
            {
                    line Line=(line)Temp;
        
                    if (Line.x1 < (Tile.x + Tile.width) && (Line.x1) > Tile.x && Line.y1 < (Tile.y + Tile.height) && Line.y1 > Tile.y)//circle may be hitting one of the end points
                    {
                        rectangle rec=new rectangle(Line.x1, Line.y1, 1, 1, this);
                        circleRectangle(rec);
                        remove(rec);
                    }
        
                    if (Line.x2 < (Tile.x + Tile.width) && (Line.x2) > Tile.x && Line.y2 < (Tile.y + Tile.height) && Line.y2 > Tile.y)//circle may be hitting one of the end points
                    {
                        rectangle rec=new rectangle(Line.x2, Line.y2, 1, 1, this);
                        circleRectangle(rec);
                        remove(rec);
                    }
        
        
                    int x1=0, y1=0, x2=Tile.x+(Tile.width/2), y2=Tile.y+(Tile.height/2);
        
                    x1=Tile.x+(Tile.width/2)-Line.height;//(int)Math.round(Line.xNorm*1000);
                    x2=Tile.x+(Tile.width/2)+Line.height;
                    if(Line.posSlope)
                    {
                        y1=Tile.y+(Tile.height/2)-Line.width;
                        y2=Tile.y+(Tile.height/2)+Line.width;
                    }
                    else
                    {
                        y1=Tile.y+(Tile.height/2)+Line.width;
                        y2=Tile.y+(Tile.height/2)-Line.width;
                    }
        
                    Point point=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
        
                    if (point.x < (Line.x + Line.width) && point.x > Line.x && point.y < (Line.y + Line.height) && point.y > Line.y)//line intersects within line segment
                    {
                        //if(point!=null){System.out.println(point.x+","+point.y);}
                        double distance = Math.sqrt(Math.pow((Tile.x+(Tile.width/2)) - point.x,2) + Math.pow((Tile.y+(Tile.width/2)) - point.y, 2));
        
                        if((int)distance<Tile.width/2)
                        {
                            //System.out.println("hit");
                            double normX = ((Tile.x+(Tile.width/2)) - point.x) / distance;
                            double normY = ((Tile.y+(Tile.height/2)) - point.y) / distance;
        
                            Tile.move((point.x)+(int)Math.round(normX*(Tile.width/2))-(Tile.width/2) , (point.y)+(int)Math.round(normY*(Tile.height/2))-(Tile.height/2));text.out="collision detected!";
                            //System.out.println(point.x+","+point.y);
                        }
                    }
        
                    //new bullet(this, (int)Math.round(tryX), (int)Math.round(tryY));
            }
        
                void rectangleLine(tile Temp)
            {
                    line Line=(line)Temp;
                    if(new Line2D.Double(Line.x1,Line.y1,Line.x2,Line.y2).intersects(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height)))
                    {
                        if (Line.x1 < (Tile.x + Tile.width) && (Line.x1) > Tile.x && Line.y1 < (Tile.y + Tile.height) && Line.y1 > Tile.y)//circle may be hitting one of the end points
                        {
                            rectangle rec=new rectangle(Line.x1, Line.y1, 1, 1, this);
                            rectangleRectangle(rec);
                            remove(rec);
                        }
        
                        if (Line.x2 < (Tile.x + Tile.width) && (Line.x2) > Tile.x && Line.y2 < (Tile.y + Tile.height) && Line.y2 > Tile.y)//circle may be hitting one of the end points
                        {
                            rectangle rec=new rectangle(Line.x2, Line.y2, 1, 1, this);
                            rectangleRectangle(rec);
                            remove(rec);
                        }
        
                        if(Line.posSlope)//positive sloped line
                        {
                            //first we'll do the top left corner
                            int x1=Tile.x-Line.height;
                            int x2=Tile.x+Line.height;
                            int y1=Tile.y-Line.width;
                            int y2=Tile.y+Line.width;
                            Point topPoint=new Point(-99,-99), botPoint=new Point(-99,-99);
                            double topDistance=0, botDistance=0;
        
                            topPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
        
                            topDistance = Math.sqrt(Math.pow(Tile.x - topPoint.x,2) + Math.pow(Tile.y - topPoint.y, 2));
        
                            //new let's do the bottom right corner
                            x1=Tile.x+Tile.width-Line.height;
                            x2=Tile.x+Tile.width+Line.height;
                            y1=Tile.y+Tile.height-Line.width;
                            y2=Tile.y+Tile.height+Line.width;
        
                            botPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
        
                            botDistance = Math.sqrt(Math.pow((Tile.x+Tile.width) - botPoint.x,2) + Math.pow((Tile.y+Tile.height) - botPoint.y, 2));
        
        
                            if(topDistance<botDistance)
                            {
                                if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(topPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(topPoint))
                                {
                                    Tile.move(topPoint.x,topPoint.y);text.out="collision detected!";
                                }
                            }
                            else
                            {
                                if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(botPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(botPoint))
                                {
                                    Tile.move(botPoint.x-Tile.width,botPoint.y-Tile.height);text.out="collision detected!";
                                }
                            }
                        }
                        else//negative sloped lne
                        {
                            //first we'll do the top right corner
                            int x1=Tile.x+Tile.width-Line.height;
                            int x2=Tile.x+Tile.width+Line.height;
                            int y1=Tile.y+Line.width;
                            int y2=Tile.y-Line.width;
                            Point topPoint=new Point(-99,-99), botPoint=new Point(-99,-99);
                            double topDistance=0, botDistance=0;
        
                            topPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
        
                            topDistance = Math.sqrt(Math.pow(Tile.x + Tile.width - topPoint.x,2) + Math.pow(Tile.y - topPoint.y, 2));
        
                            //new let's do the bottom left corner
                            x1=Tile.x-Line.height;
                            x2=Tile.x+Line.height;
                            y1=Tile.y+Tile.height+Line.width;
                            y2=Tile.y+Tile.height-Line.width;
        
                            botPoint=intersection((double)x1,(double)y1,(double)x2,(double)y2,(double)Line.x1,(double)Line.y1,(double)Line.x2,(double)Line.y2);//find intersection
        
                            botDistance = Math.sqrt(Math.pow(Tile.x - botPoint.x,2) + Math.pow((Tile.y+Tile.height) - botPoint.y, 2));
        
        
                            if(topDistance<botDistance)
                            {
                                if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(topPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(topPoint))
                                {
                                    Tile.move(topPoint.x-Tile.width,topPoint.y);text.out="collision detected!";
                                }
                            }
                            else
                            {
                                if(new Rectangle(Tile.x,Tile.y,Tile.width,Tile.height).contains(botPoint) && new Rectangle(Line.x,Line.y,Line.width,Line.height).contains(botPoint))
                                {
                                    Tile.move(botPoint.x,botPoint.y-Tile.height);text.out="collision detected!";
                                }
                            }
                        }
                    }
            }
        
               public Point intersection(double x1, double y1, double x2, double y2,double x3, double y3, double x4, double y4)//I didn't write this. got it from http://www.ahristov.com/tutorial/geometry-games/intersection-lines.html (I altered it)
               {
                    double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
        
                    double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
                    double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
        
                    int x=(int)Math.round(xi);
                    int y=(int)Math.round(yi);
        
                    return new Point(x, y);
                }
        
        //***************************************************************************************
        
            public static void main(String[] args)
            {
                final collision Collision=new collision();
                  Collision.run();
            }//end main
        }//end class
        

        【讨论】:

          【解决方案5】:

          由于 Java 没有 intersect 函数(真的!?),您可以通过简单地比较每个可能发生碰撞的对象的边界框(矩形)的 X 和 Y、宽度和高度值来进行碰撞检测.

          所以...在每个碰撞对象的基础对象中...即,如果您的玩家和敌人有一个共同的基础,您可以放置​​一个简单的 Rectangle 对象,称为 BoundingBox。如果公共基础是内置 Java 类,那么您需要创建一个扩展内置类的类,并让玩家和敌人对象扩展您的新类或者是该类的实例。

          在创建时(以及每次更新或更新),您需要为您的玩家和敌人设置 BoundingBox 参数。我面前没有 Rectangle 类,但它很可能是 X、Y、Width 和最后的 Height。 X 和 Y 是游戏世界中的对象位置。我认为宽度和高度是不言自明的。它们很可能会从玩家位置的右侧出现,因此,如果 X 和 Y 都为 0 并且您的宽度和高度都为 256,您将看不到任何东西,因为角色将位于左上角在屏幕之外。

          无论如何...要检测碰撞,您需要比较玩家和敌人边界框的属性。所以像这样......

           if( Player.BoundingBox.X = Enemy.BoundingBox.X && If( Player.BoundingBox.Y = Enemy.BoundingBox.Y )
           {
                //Oh noes!  The enemy and player are on top of eachother.
           }
          

          逻辑可能有点复杂,但您需要比较每个 BoundingBox 之间的距离并比较位置。

          【讨论】:

          【解决方案6】:

          这是一个使用大量碰撞的开源游戏的有用之处:http://robocode.sourceforge.net/

          您可以查看代码并补充此处编写的答案。

          【讨论】:

            【解决方案7】:

            是否有问题:

            Rectangle box1 = new Rectangle(100,100,100,100);
            Rectangle box2 = new Rectangle(200,200,100,100);
            
            // what this means is if any pixel in box2 enters (hits) box1
            if (box1.contains(box2)) 
            {
                 // collision occurred
            }
            
            // your code for moving the boxes 
            


            这也可以应用于圆圈:

            Ellipse2D.Double ball1 = new Ellipse2D.Double(100,100,200,200);
            Ellipse2D.Double ball2 = new Ellipse2D.Double(400,100,200,200);
            
            // what this means is if any pixel on the circumference in ball2 touches (hits)
            // ball1
                if (ball1.contains(ball2)) 
                {
                     // collision occurred
                }
            
                // your code for moving the balls
            



            要检查您是否碰到了屏幕边缘,您可以使用以下命令:

            Rectangle screenBounds = jpanel.getBounds();
            Ellipse2D.Double ball = new Ellipse2D.Double(100,100,200,200);  // diameter 200
            Rectangle ballBounds = ball.getBounds();
            
            if (!screenBounds.contains(ballBounds))
            {
            // the ball touched the edge of the screen
            }
            

            【讨论】:

              【解决方案8】:

              使用一个矩形来包围每个玩家和敌人,矩形的高度和宽度应该与你周围的物体相对应,想象它在一个足够大的盒子里。

              现在,您可以像移动对象一样移动这些矩形,因此它们有一个“边界框”

              我不确定 Java 是否有此功能,但它可能在矩形对象上有一个名为 .intersects() 的方法,因此您可以执行 if(rectangle1.intersectS(rectangle2) 来检查对象是否发生碰撞和另一个。

              否则,您可以获取框的 x 和 y 坐标,并使用它们的高度/宽度来检测它们是否与您自己相交。

              无论如何,您可以使用它在交叉路口执行事件(使一个爆炸或其他)或阻止绘制运动。 (恢复到以前的坐标)

              编辑:我们开始

              布尔值

              相交(矩形 r) 确定此 Rectangle 是否与指定的 矩形相交。

              所以我会做(并且不要粘贴这段代码,它很可能不会工作,很长时间没有做过java并且我使用它时没有做图形。)

              Rectangle rect1 = new Rectangle(player.x, player.y, player.width, player.height);
              
              Rectangle rect2 = new Rectangle(enemy.x, enemy.y, enemy.width, enemy.height);
              
              //detects when the two rectangles hit
              if(rect1.intersects(rect2))
              {
              
              System.out.println("game over, g");
              }
              

              显然你需要把它放在某个地方。

              【讨论】:

              • 这就是我的意思。 Java 确实有相交,但我正在努力将它应用到我已经拥有的代码中。我必须在 player() 和enemy() 中定义矩形吗?
              • No.. 我以前没有在 java 中使用过绘画的东西,但你肯定应该有一个像“Creature”这样的对象,然后创建 Creature 的实例,即玩家/敌人或使它们成为子类您创建的实例。创建对象应包含更新/绘制 NoCharsLeft 所需的所有内容
              【解决方案9】:

              无需使用矩形...不断比较两个玩家的坐标。

              喜欢 if(x1===x&amp;&amp;y1==y) 比较时记得增加x的范围。

              如果你的矩形宽度为 30,则取为 if (x1&gt;x&amp;&amp;x2&gt;x+30)..同样是 y

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-03-19
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多