游戏中很重要的一个部分是检测物体之间的冲突。下面我们就来一起看看如何来通过边界盒来检测冲突。
这里讲的冲突是针对于刚体的,就是说这里所说的两个物体不会同时在同一空间存在。当我们检测出冲突时,就能够触发另一种状态。
测试实际的像素点显然非常耗时,所我们尝试用简单图形(比如说长方形)来框住物体,从而我们近似地将长方形之间的冲突看做物体之间的冲突。
长方形之间的相互重叠比较容易检测出来,所以我们选择他来作为我们检测冲突的边界盒。下面来看看示例代码:
import java.applet.Applet;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.Random;
public class CollisionTest extends Applet implements MouseListener, MouseMotionListener{
private final int NUM_RECTS = 10;
private LinkedList rectangles;
private AlphaComposite alpha;
private Rectangle2D pick;
private Image bufImg;
private Graphics bufG;
public void init()
{
rectangles = new LinkedList();
pick = null;
alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
Random r = new Random();
int width = (int)getSize().getWidth();
int height = (int)getSize().getHeight();
for(int i = 0 ; i < NUM_RECTS ; i++)
{
rectangles.add(new Rectangle2D.Double(
(double) Math.abs(r.nextInt())%width,
(double) Math.abs(r.nextInt())%height,
(double) Math.abs(r.nextInt())%50,
(double) Math.abs(r.nextInt())%50));
}
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
public void update(Graphics g) {
bufImg = this.createImage(this.getWidth(), this.getHeight());
bufG = bufImg.getGraphics();
paint(bufG);
g.drawImage(bufImg, 0, 0, this);
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(alpha);
g2d.setPaint(Color.BLACK);
for(int i = 0 ; i < NUM_RECTS ; i++)
{
g2d.draw((Rectangle2D.Double) rectangles.get(i));
}
if(pick != null)
{
Rectangle2D rect;
g2d.setPaint(Color.RED.darker());
for(int i = 0 ; i < NUM_RECTS ; i++)
{
rect = (Rectangle2D) rectangles.get(i);
if(pick != rect && pick.intersects(rect))
{
g2d.fill(rect);
}
}
g2d.setPaint(Color.BLUE.brighter());
g2d.fill(pick);
}
}
@Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
if(pick != null)
{
pick.setRect(arg0.getX()-pick.getWidth()/2, arg0.getY()-pick.getHeight()/2, pick.getWidth(), pick.getHeight());
repaint();
}
}
public void mouseMoved(MouseEvent arg0) {}
public void mouseClicked(MouseEvent arg0) {}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
if(pick == null)
{
Rectangle2D rect;
for(int i = 0 ; i < NUM_RECTS ; i++)
{
rect = (Rectangle2D) rectangles.get(i);
if(rect.contains(arg0.getPoint()))
{
pick = rect;
break;
}
}
}
}
@Override
public void mouseReleased(MouseEvent arg0) {
pick = null;
repaint();
}
}
成员变量中的NUM_RECTS表示要随机生成的矩形的数量,rectangles是我们用来存储矩形的一个链表,而AlphaComposite类对象alpha用来设置画图的透明度,pick表示的是当前鼠标选中的矩形。
在init()函数中我们主要做了以下事情:1)初始化链表以及透明成分;2)利用随机数生成指定数量的矩形;3)添加鼠标事件。
在paint()重载函数中,我们将矩形外框画出,同时对于相交的矩形进行颜色填充。同时我们在update()函数中利用双缓冲,使得显示效果不那么闪烁。
在mousePressed()方法中,我们设置选取的长方形。(利用了Rectangle2D中的contains方法),在mouseReleased释放选中长方形,同时在mouseDragged中设置拖动长方形的功能(利用了Rectangle2D中的setRect方法)。
实现的功能如图所示:
这里讲的仅是简单的冲突检测,所以它必然有很多缺陷。比如长方形与原来的形状之间有很多空隙,但是当这些空隙相重叠时我们会检测出不应该检测到得冲突。所以呢,继续学习吧,看看后面还有什么好方法。O(∩_∩)O~