开发者俱乐部

标题: [HTML5] canvas中的碰撞检测笔记 [打印本页]

作者: xman    时间: 2016-3-15 21:37
标题: [HTML5] canvas中的碰撞检测笔记
用 canvas 做小游戏或者特效,碰撞检测是少不了的。本文将会涉及普通的碰撞检测,以及像素级的碰撞检测。(本文的碰撞检测均以矩形为例)

  普通碰撞检测

  普通的矩形碰撞检测比较简单。即已知两个矩形的各顶点坐标,判断是否相交,如相交,则为碰撞。

  leetcode 有道题是给出两个矩形的坐标,求其相交面积(223. Rectangle Area),代码 可以直接拿过来用,如果面积大于 0,则为碰撞。

  如果只需判断是否相交或者相交面积,非常简单,可以参考 这里

  为了程序的可扩展性,如果碰撞,最好还能求得相交矩形的坐标信息(为像素级碰撞检测作准备),完善后的检测代码如下:

复制代码


  像素级碰撞检测

  为什么要有像素级检测?一图以蔽之。

  一般游戏或者动画中的精灵都是矩形,仅仅判断矩形相交是不准确的,比如上图中,图片所在矩形已经相交,但是精灵其实并没有碰撞,所以我们需要进行像素级别的碰撞检测。

  方法一:

  同时检测两图在相交矩形内的像素,若存在一点在两个图上的 alpha 值不为 0,则发生碰撞。

  因为还要对原始的图像(fish 图和 cat 图)分别提取像素点(进行判断),所以需要一个离屏的 canvas 。这里用了 canvas 的 getImageData 方法提取像素点 rgba 信息。

复制代码


  方法二:

  先画一张图,然后将混合模式改为 source-in,这时再画图,新图片会仅仅出现与原有内容重叠的地方,其他地方透明度变为 0,这时就可以通过判断是否所有像素都透明来判断碰撞了。
  • // a, b 为精灵对象
  • // a, b 分别拥有键值 img(精灵图像 DOM元素), pos(精灵瞬间位置 top-left 坐标), size(wdith, height 数据)
  • // rect 参数为 check() 函数返回值
  • function _checkInDetail(a, b, rect) {
  •   // 离屏 canvas
  •   var canvas = document.createElement('canvas');
  •   _ctx = canvas.getContext('2d');

  •   // 将 (0, 0) 作为基准点,将 a 放入 (0, 0) 位置
  •   _ctx.drawImage(a.img, 0, 0, a.size.x, a.size.y);
  •   _ctx.globalCompositeOperation = 'source-in';
  •   _ctx.drawImage(b.img, b.pos.x - a.pos.x, b.pos.y - a.pos.y, b.size.x, b.size.y);

  •   var data = _ctx.getImageData(rect[0] - a.pos.x, rect[1] - a.pos.y, rect[2] - rect[0], rect[3] - rect[1]).data;

  •   canvas = null;

  •   // 改回来(虽然并没有什么卵用)
  •   _ctx.globalCompositeOperation = 'source-over';
  •    
  •   for(var i = 3; i < data.length; i += 4) {
  •     if (data)
  •       return true;  // 碰撞
  •   }

  •   return false;
  • }

复制代码


  我测试了几次,把相交的像素点都取了出来求得相交像素点总数,两种方法有时会相差一两个像素点。对于像素级碰撞检测来说,两种方法任取其一就可。







欢迎光临 开发者俱乐部 (http://xodn.com/) Powered by Discuz! X3.2