使用intersects方法实现的矩形碰撞测试

       为什么会想做一个碰撞测试呢?这其实是一个很懊恼很无奈的决定,这个想法最初源于暑假做的一个小游戏。小游戏中有很多个独立线程的个体,这些个体的行为控制并不难,但把这些个体联系起来,做到运动中不相互重叠在当时的我看来相当有难度,开始的想法直接在类的run()方法里直接用if语句判断。

这种方法最难的是判断方法的推理找寻,特别是坐标间的关系。

下面是我的推算过程。

如图所示的两个矩形,方别是黑矩形和红矩形,我们用p1.x代表p1点的x坐标,p1.y代表p2点的y坐标(诸如此类)。

图中的两个矩形关系是相交,为了便于推理,我们先假定这两个矩形是不相交的,通过观察,我们可以得出一个关系式:

A:(p2.y≤p3.y)∨(p1.y≥p4.y)∨(p2.x≤p3.x)∨(p1.x≥p4.x)

当A==true的时候,两个矩形是不相交的,而只要使用一次德摩根律就可以得到我们想要的相交式B。

B=﹁A=﹁[(p2.y≤p3.y)∨(p1.y≥p4.y)∨(p2.x≤p3.x)∨(p1.x≥p4.x)]=(p2.y>p3.y)∧(p1.y<p4.y)∧(p2.x>p3.x)∧(p1.x<p4.x)

看似简单的式子在实际编程的过程中,用的却不省心,因为游戏中的对象具有上下左右的方向,为了不使停止一刻显得过于突兀

我们还得为上下左右四种状态分别编写上下左右四种B式,也就是说需要我们推导的B式共有16条。这对于开始初学者来说过于

苛刻,并且臃肿的代码行会产生很多难以发现的小错误,以至于游戏不能够按我们的想法进行。

这是其中一个方向的判断源代码:

 if(et!=this)
	                {
	                    //如果敌人的方向是向下或者向上
	                    if(et.direct==0||et.direct==2)
	                    {
	                        //上点
	                        if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y>=et.y&&this.y<=et.y+30)
	                        {
	                            return true;
	                        }
	                        //下点
	                        if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30)
	                        {
	                            return true;
	                        }
	                    }
	                    if(et.direct==3||et.direct==1)
	                    {
	                        if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y>=et.y&&this.y<=et.y+20)
	                        {
	                            return true;
	                        }
	                        if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20)
	                        {
	                            return true;
	                        }
	                    }
	                }

在一番折腾之后,我思来想去,终究还是放弃了这个判断方法,Java的包那么丰富,这几天我就一直在找关于矩形碰撞的类方法。终于,我发现了intersects方法可以解决我的问题。于是,这个简单的矩形碰撞测试边在我的脑海里应运而生。这个方法并不难实现,基本的思想就是将两个Rectangle对象依附在既定好的两个矩形上,通过线程时时判断是否相交。

public boolean isHitA() {
		Rectangle rA=new Rectangle(A.getX(),A.getY(),100,100);
		Rectangle rB=new Rectangle(B.getX(),B.getY(),100,100);	
		if(rA.intersects(rB)) {
			return false;
		}else {
			return true;
		}
	}
	//碰撞函数
	public boolean isHitB() {
		Rectangle rA=new Rectangle(A.getX(),A.getY(),105,105);
		Rectangle rB=new Rectangle(B.getX(),B.getY(),105,105);
		if(rB.intersects(rA)) {
			//System.out.println("sdas");
			return false;
		}else {
			return true;
		}
	}

虽然还没精确到像素单位,但效果也基本达到了预期,在这基础上,我会尝试着继续改进。

源代码:

/*
 * 目的:学会使用intersects方法进行游戏碰撞测试
 * 方法:两个移动的正方形间的碰撞测试
 */
package First;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.Graphics;
public class Two extends JFrame {
	Mypanel mp=null;
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Two two=new Two();
	}
	public Two() {
		mp=new Mypanel();
		Thread tM=new Thread();
		tM.start();
		this.add(mp);
		this.setTitle("碰撞测试");
		this.setSize(400, 400);
		this.setLocation(100, 100);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
	}
}

class Mypanel extends JPanel implements Runnable{
	RectangleA A=null;
	RectangleA B=null; 
	public void paint(Graphics g)
	{
		super.paint(g);
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, 400, 400);
		g.setColor(Color.cyan);
		this.drawRactangle(A.x, A.y, g);
		this.drawRactangle(B.x, B.y, g);
		A.setBump(this.isHitA());
		B.setBump(this.isHitB());
		this.repaint();
	}
	public Mypanel(){
		A=new RectangleA(30,30);
		A.setSpeed(15);
		Thread tA=new Thread(A);
		tA.start();
		B=new RectangleA(190,190);
		B.setSpeed(10);
		Thread tB=new Thread(B);
		tB.start();
	}
	public void drawRactangle(int x,int y,Graphics g) {
		g.setColor(Color.cyan);
		g.fill3DRect(x, y, 100, 100, true);
	}
	public boolean isHitA() {
		Rectangle rA=new Rectangle(A.getX(),A.getY(),100,100);
		Rectangle rB=new Rectangle(B.getX(),B.getY(),100,100);	
		if(rA.intersects(rB)) {
			return false;
		}else {
			return true;
		}
	}
	//碰撞函数
	public boolean isHitB() {
		Rectangle rA=new Rectangle(A.getX(),A.getY(),105,105);
		Rectangle rB=new Rectangle(B.getX(),B.getY(),105,105);
		if(rB.intersects(rA)) {
			//System.out.println("sdas");
			return false;
		}else {
			return true;
		}
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stu;
		try {
			Thread.sleep(50);
		}catch(Exception e) {
			e.printStackTrace();
		}
		//重绘
		this.repaint();
	}
}
class RectangleX{
	boolean bump=true;
	//碰撞值输入输出方法组
	public boolean isBump() {
		return bump;
	}

	public void setBump(boolean bump) {
		this.bump = bump;
	}
	int x,y;
	int direct=1;
	int times=0;
	int speed;
	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public int getX() {
		return x;
	}
	
	public void setX(int x) {
		this.x = x;
	}
	
	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
	RectangleX(int x,int y){
		this.x=x;
		this.y=y;
	}
}
class RectangleA extends RectangleX implements Runnable{
	RectangleA(int x, int y) {
		super(x, y);
		// TODO Auto-generated constructor stub
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true) {
			//System.out.println("saa");
			this.direct=(int)(Math.random()*4);
			switch(this.direct){
			case 0:
				for(int i=0;i<15;i++){
					if(this.y>0&&this.bump){
						y-=speed;
					}else if(this.y>0&&this.bump==false){
						y+=speed;
						this.setBump(true);
						break;
					}
					try {         
						Thread.sleep(50);}
					catch(Exception e){
						e.printStackTrace();
					}
				}
				break;
			case 1:
				for(int i=0;i<15;i++){
					if(this.x<275&&this.bump){
						x+=speed;
					}else if(this.x<275&&this.bump==false) {
						x-=speed;
						i=15;
						this.setBump(true);
						break;
					}
					try {         
						Thread.sleep(50);}
					catch(Exception e){
						e.printStackTrace();
					}
				}
				break;
			case 2:
				for(int i=0;i<15;i++){
					if(this.y<253&&this.bump){
						y+=speed;
					}else if(this.y<253&&this.bump==false) {
						y-=speed;
						i=15;
						this.setBump(true);
						break;
					}
					try {         
						Thread.sleep(50);}
					catch(Exception e){
						e.printStackTrace();
					}
				}
				break;
			case 3:for(int i=0;i<15;i++){
				if(this.x>0&&this.bump){
					x-=speed;
				}else if(this.x>0&&this.bump==false) {
					x+=speed;
					i=15;
					this.setBump(true);
					break;
				}
				try {         
					Thread.sleep(50);}
				catch(Exception e){
					e.printStackTrace();
				}
			}
				break;
			}
			this.direct=(int)(Math.random()*4);
		}	
	}
}

猜你喜欢

转载自blog.csdn.net/Huangxu_MIKU/article/details/82730828