Java實(shí)現(xiàn)矩形碰撞檢測(cè)
本文實(shí)例為大家分享了Java實(shí)現(xiàn)矩形碰撞檢測(cè)的具體代碼,供大家參考,具體內(nèi)容如下
第1種方法:通過檢測(cè)一個(gè)矩形的4個(gè)頂點(diǎn)是否在另一個(gè)矩形的內(nèi)部來完成。
通常由x和y坐標(biāo)以及長(zhǎng)度和寬度來確定一個(gè)矩形,因此又可以利用這四個(gè)參數(shù)來確定是否發(fā)生了碰撞。

相交的情況下一定會(huì)發(fā)生碰撞,如下圖:

還有一類特殊的相交情況,就是重疊,如下圖:

所以開發(fā)的碰撞檢測(cè)類如下:
public class Actor {
int x, y, w, h;// 分別是x和y坐標(biāo),寬度和高度,構(gòu)成一個(gè)矩形
public Actor() {
}
public Actor(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getActorWidth() {
return w;
}
public int getActorHeight() {
return h;
}
@Override
public String toString() {
return "Actor{" +
"x=" + x +
", y=" + y +
", w=" + w +
", h=" + h +
'}';
}
public boolean isCollidingWith(int px, int py) {
// px和py分別傳入的是x坐標(biāo)和y坐標(biāo)
// 等號(hào)的情況就是考慮垂直重疊和水平重疊的情況
// 考慮的情況就是傳入的坐標(biāo)是否在當(dāng)前的矩形范圍內(nèi),只要滿足下面所有條件就表示傳入的坐標(biāo)在當(dāng)前矩形范圍內(nèi),返回true
if (px >= getX() && px < getX() + getActorWidth() && py >= getY() && py < getY() + getActorHeight()) {
return true;
}
return false;
}
// 碰撞檢測(cè),發(fā)生碰撞返回true,否則返回false
public boolean isCollidingWith(Actor another) {
// 判斷矩形只要有任何一個(gè)點(diǎn)在另一個(gè)Actor所表示的矩形范圍內(nèi),就表示發(fā)生了碰撞
if (isCollidingWith(another.getX(), another.getY()) ||
isCollidingWith(another.getX() + another.getActorWidth(), another.getY()) ||
isCollidingWith(another.getX(), another.getY() + another.getActorHeight()) ||
isCollidingWith(another.getX() + another.getActorWidth(), another.getY() + another.getActorHeight())) {
return true;
}
return false;
}
public static void main(String[] args) {
Actor actor = new Actor(10, 10, 100, 150);
Actor another = new Actor(20, 50, 100, 150);
boolean collidingWith = actor.isCollidingWith(another);
System.out.println(collidingWith);
}
}
上面測(cè)試代碼你不能很好的觀察是否發(fā)生矩形碰撞了,所以寫了下面這個(gè)界面,可以通過ASWD操作左邊的矩形進(jìn)行移動(dòng),通過上下左右鍵操作右邊的矩形進(jìn)行移動(dòng),效果如下圖:

代碼如下:
class TestPanel extends JPanel implements KeyListener {
private int x1 = 20, y1 = 20, x2 = 160, y2 = 20, width = 100, height = 100;
public TestPanel() {
// 設(shè)置焦點(diǎn)并且添加鍵盤事件監(jiān)聽器
setFocusable(true);
addKeyListener(this);
}
@Override
public void paint(Graphics g) {
// 在進(jìn)行繪制之前,一定要清除之前的圖形
g.clearRect(0, 0, this.getWidth(), this.getHeight());// 先清除屏幕上原來的畫
g.drawRect(x1, y1, width, height);
g.drawRect(x2, y2, width, height);
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
// 處理第一個(gè)矩形的移動(dòng)
switch (e.getKeyCode()) {
case KeyEvent.VK_A:// 'A'鍵
x1 -= 5;
break;
case KeyEvent.VK_D:// 'D'鍵
x1 += 5;
break;
case KeyEvent.VK_W:// 'W'鍵
y1 -= 5;
break;
case KeyEvent.VK_S://'S'鍵
y1 += 5;
break;
case KeyEvent.VK_LEFT://'LEFT'鍵
x2 -= 5;
break;
case KeyEvent.VK_RIGHT:// 'RIGHT'鍵
x2 += 5;
break;
case KeyEvent.VK_UP:// 'UP'鍵
y2 -= 5;
break;
case KeyEvent.VK_DOWN:// 'DOWN'鍵
y2 += 5;
break;
}
repaint();// 修改坐標(biāo)后,重繪圖形
// 判斷是否碰撞,輸出信息
Actor actor = new Actor(x1, y1, width, height);
Actor another = new Actor(x2, y2, width, height);
System.out.println("是否碰撞:" + (actor.isCollidingWith(another) || another.isCollidingWith(actor)) + "| " + actor + "| " + another);
}
@Override
public void keyReleased(KeyEvent e) {
}
}
public class Demo {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLocation(200, 200);
frame.setSize(500, 500);
TestPanel panel = new TestPanel();
frame.setContentPane(panel);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
第2種方法:從相反的角度考慮,以前是處理什么時(shí)候相交,現(xiàn)在處理什么時(shí)候不會(huì)相交。如兩個(gè)矩形a和b來判斷4條邊,假如a矩形在左邊,b矩形在右邊,那么可以判斷左邊a矩形的右邊界在b矩形的左邊界之外,同理,a的上邊界需要在b的下邊界以外,4條邊都判斷,則可以知道a矩形是否與b矩形相交。

方法如下:
/**
* 判斷兩個(gè)矩形是否會(huì)發(fā)生碰撞
*
* @param ax 矩形a的x坐標(biāo)
* @param ay 矩形a的y坐標(biāo)
* @param aw 矩形a的寬度
* @param ah 矩形a的高度
* @param bx 矩形b的x坐標(biāo)
* @param by 矩形b的y坐標(biāo)
* @param bw 矩形b的寬度
* @param bh 矩形b的高度
* @return 如果發(fā)生碰撞則返回true,否則返回false
*/
public boolean isCollidingWith(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) {
if (ay > by + bh || by > ay + ah || ax > bx + bw || bx > ax + aw) {
return false;
}
return true;
}
第3種方法:是方法2的變異,我們保存兩個(gè)矩形的左上和右下兩個(gè)坐標(biāo)的坐標(biāo)值,然后對(duì)兩個(gè)坐標(biāo)的一個(gè)對(duì)比就可以得出兩個(gè)矩形是否相交。

/**
* rect1[0]:矩形1左上角x坐標(biāo)
* rect1[1]:矩形1左上角y坐標(biāo)
* rect1[2]:矩形1右下角x坐標(biāo)
* rect1[3]:矩形1右下角y坐標(biāo)
* rect2[0]:矩形2左上角x坐標(biāo)
* rect2[1]:矩形2左上角y坐標(biāo)
* rect2[2]:矩形2右下角x坐標(biāo)
* rect2[3]:矩形2右下角y坐標(biāo)
*
* @param rect1 第一個(gè)矩形的左上角坐標(biāo)和右下角坐標(biāo)數(shù)組
* @param rect2 第二個(gè)矩形的左上角坐標(biāo)和右下角坐標(biāo)數(shù)組
* @return 如果發(fā)生碰撞則返回true,否則返回false
*/
public static boolean isCollidingWith(int rect1[], int rect2[]) {
if (rect1[0] > rect2[2]) {
return false;
}
if (rect1[2] < rect2[0]) {
return false;
}
if (rect1[1] > rect2[3]) {
return false;
}
if (rect1[3] < rect2[1]) {
return false;
}
return true;
}
最后Actor類的完整代碼如下:
public class Actor {
int x, y, w, h;// 分別是x和y坐標(biāo),寬度和高度,構(gòu)成一個(gè)矩形
public Actor() {
}
public Actor(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getActorWidth() {
return w;
}
public int getActorHeight() {
return h;
}
@Override
public String toString() {
return "Actor{" +
"x=" + x +
", y=" + y +
", w=" + w +
", h=" + h +
'}';
}
public boolean isCollidingWith(int px, int py) {
// px和py分別傳入的是x坐標(biāo)和y坐標(biāo)
// 等號(hào)的情況就是考慮垂直重疊和水平重疊的情況
// 考慮的情況就是傳入的坐標(biāo)是否在當(dāng)前的矩形范圍內(nèi),只要滿足下面所有條件就表示傳入的坐標(biāo)在當(dāng)前矩形范圍內(nèi),返回true
if (px >= getX() && px < getX() + getActorWidth() && py >= getY() && py < getY() + getActorHeight()) {
return true;
}
return false;
}
// 碰撞檢測(cè),發(fā)生碰撞返回true,否則返回false
public boolean isCollidingWith(Actor another) {
// 判斷矩形只要有任何一個(gè)點(diǎn)在另一個(gè)Actor所表示的矩形范圍內(nèi),就表示發(fā)生了碰撞
if (isCollidingWith(another.getX(), another.getY()) ||
isCollidingWith(another.getX() + another.getActorWidth(), another.getY()) ||
isCollidingWith(another.getX(), another.getY() + another.getActorHeight()) ||
isCollidingWith(another.getX() + another.getActorWidth(), another.getY() + another.getActorHeight())) {
return true;
}
return false;
}
/**
* 判斷兩個(gè)矩形是否會(huì)發(fā)生碰撞
*
* @param ax 矩形a的x坐標(biāo)
* @param ay 矩形a的y坐標(biāo)
* @param aw 矩形a的寬度
* @param ah 矩形a的高度
* @param bx 矩形b的x坐標(biāo)
* @param by 矩形b的y坐標(biāo)
* @param bw 矩形b的寬度
* @param bh 矩形b的高度
* @return 如果發(fā)生碰撞則返回true,否則返回false
*/
public boolean isCollidingWith(int ax, int ay, int aw, int ah, int bx, int by, int bw, int bh) {
if (ay > by + bh || by > ay + ah || ax > bx + bw || bx > ax + aw) {
return false;
}
return true;
}
/**
* isCollidingWith方法的重載方法
*
* @param a
* @param b
* @return
*/
public boolean isCollidingWith(Actor a, Actor b) {
return isCollidingWith(a.getX(), a.getY(), a.getActorWidth(), a.getActorHeight(), b.getX(), b.getY(), b.getActorWidth(), b.getActorHeight());
}
/**
* rect1[0]:矩形1左上角x坐標(biāo)
* rect1[1]:矩形1左上角y坐標(biāo)
* rect1[2]:矩形1右下角x坐標(biāo)
* rect1[3]:矩形1右下角y坐標(biāo)
* rect2[0]:矩形2左上角x坐標(biāo)
* rect2[1]:矩形2左上角y坐標(biāo)
* rect2[2]:矩形2右下角x坐標(biāo)
* rect2[3]:矩形2右下角y坐標(biāo)
*
* @param rect1 第一個(gè)矩形的左上角坐標(biāo)和右下角坐標(biāo)數(shù)組
* @param rect2 第二個(gè)矩形的左上角坐標(biāo)和右下角坐標(biāo)數(shù)組
* @return 如果發(fā)生碰撞則返回true,否則返回false
*/
public static boolean isCollidingWith(int rect1[], int rect2[]) {
if (rect1[0] > rect2[2]) {
return false;
}
if (rect1[2] < rect2[0]) {
return false;
}
if (rect1[1] > rect2[3]) {
return false;
}
if (rect1[3] < rect2[1]) {
return false;
}
return true;
}
public static void main(String[] args) {
Actor actor = new Actor(10, 10, 100, 150);
Actor another = new Actor(20, 50, 100, 150);
boolean collidingWith = actor.isCollidingWith(another);
System.out.println(collidingWith);
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot整合ActiveMQ實(shí)現(xiàn)消息隊(duì)列的過程淺析
昨天仔細(xì)研究了activeMQ消息隊(duì)列,也遇到了些坑,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合ActiveMQ的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
Spring boot2基于Mybatis實(shí)現(xiàn)多表關(guān)聯(lián)查詢
這篇文章主要介紹了Spring boot2基于Mybatis實(shí)現(xiàn)多表關(guān)聯(lián)查詢,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
mybatis plus saveOrUpdate實(shí)現(xiàn)有重復(fù)數(shù)據(jù)就更新,否則新增方式
這篇文章主要介紹了mybatis plus saveOrUpdate實(shí)現(xiàn)有重復(fù)數(shù)據(jù)就更新,否則新增方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Java實(shí)戰(zhàn)之晚會(huì)抽獎(jiǎng)系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了如何利用Java語(yǔ)言編寫一個(gè)晚會(huì)抽獎(jiǎng)系統(tǒng),文中采用到的技術(shù)有Jdbc、Servlert、JavaScript、JQuery、Ajax等,感興趣的可以學(xué)習(xí)一下2022-03-03
springboot+springJdbc+postgresql 實(shí)現(xiàn)多數(shù)據(jù)源的配置
本文主要介紹了springboot+springJdbc+postgresql 實(shí)現(xiàn)多數(shù)據(jù)源的配置,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
JDBC對(duì)MySQL數(shù)據(jù)庫(kù)布爾字段的操作方法
這篇文章主要介紹了JDBC對(duì)MySQL數(shù)據(jù)庫(kù)布爾字段的操作方法,實(shí)例分析了JDBC操作mysql布爾字段的原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-02-02
Mybatis操作多數(shù)據(jù)源的實(shí)現(xiàn)
本文主要介紹了Mybatis操作多數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
maven pom中內(nèi)置變量及引用的實(shí)現(xiàn)
maven其實(shí)有很多內(nèi)置變量供開發(fā)著在開發(fā)中使用,本文主要介紹了maven pom中內(nèi)置變量及引用的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01

