引言
在Canvas小游戏开发中,碰撞检测是构建游戏逻辑的核心环节。无论是角色移动、子弹射击还是物体交互,精准的碰撞判断直接影响游戏体验。本文将系统梳理Canvas小游戏开发中常用的碰撞检测方法,从基础几何检测到高级像素级检测,结合代码示例与优化技巧,为开发者提供完整的解决方案。
一、矩形碰撞检测:基础中的基础
矩形碰撞检测是游戏开发中最基础的检测方式,适用于大多数规则形状的物体碰撞判断。其核心原理是通过比较两个矩形的边界坐标是否重叠来实现。
1.1 轴对齐矩形检测(AABB)
轴对齐矩形检测(Axis-Aligned Bounding Box)是最简单的矩形碰撞检测方法。其实现逻辑如下:
function checkAABBCollision(rect1, rect2) {return (rect1.x < rect2.x + rect2.width &&rect1.x + rect1.width > rect2.x &&rect1.y < rect2.y + rect2.height &&rect1.y + rect1.height > rect2.y);}
适用场景:角色与地面、墙壁等规则物体的碰撞检测。
优化建议:在移动帧率较低的游戏中,可结合速度预测提前判断碰撞。
1.2 动态矩形检测
当物体发生旋转时,需将矩形坐标转换至同一坐标系后再检测:
function rotatePoint(x, y, angle, originX, originY) {const rad = angle * Math.PI / 180;const cos = Math.cos(rad);const sin = Math.sin(rad);return {x: (x - originX) * cos - (y - originY) * sin + originX,y: (x - originX) * sin + (y - originY) * cos + originY};}
技术要点:需先计算旋转后的顶点坐标,再转换为AABB矩形进行检测。
二、圆形碰撞检测:精准的球体交互
圆形碰撞检测通过计算两圆心距离与半径和的关系实现,适用于子弹、粒子等圆形物体的碰撞判断。
2.1 基础圆形检测
function checkCircleCollision(circle1, circle2) {const dx = circle1.x - circle2.x;const dy = circle1.y - circle2.y;const distance = Math.sqrt(dx * dx + dy * dy);return distance < circle1.radius + circle2.radius;}
性能优化:使用距离平方比较避免开方运算:
const distanceSquared = dx * dx + dy * dy;const radiusSumSquared = (circle1.radius + circle2.radius) ** 2;return distanceSquared < radiusSumSquared;
2.2 圆形与矩形混合检测
结合矩形检测与圆形检测的优化方法:
function checkCircleRectCollision(circle, rect) {const closestX = Math.max(rect.x, Math.min(circle.x, rect.x + rect.width));const closestY = Math.max(rect.y, Math.min(circle.y, rect.y + rect.height));const distanceX = circle.x - closestX;const distanceY = circle.y - closestY;const distanceSquared = distanceX * distanceX + distanceY * distanceY;return distanceSquared < circle.radius * circle.radius;}
三、像素级碰撞检测:极致精准的实现
对于不规则形状物体,像素级检测能提供最精确的碰撞判断。Canvas提供了getImageDataAPI实现该功能。
3.1 基础实现方案
function checkPixelCollision(ctx1, rect1, ctx2, rect2) {// 创建离屏Canvasconst offscreenCanvas = document.createElement('canvas');const offscreenCtx = offscreenCanvas.getContext('2d');// 绘制第一个物体offscreenCtx.clearRect(0, 0, rect1.width, rect1.height);offscreenCtx.drawImage(ctx1.canvas, rect1.x, rect1.y, rect1.width, rect1.height, 0, 0, rect1.width, rect1.height);const data1 = offscreenCtx.getImageData(0, 0, rect1.width, rect1.height).data;// 绘制第二个物体(需坐标转换)// ...(实现略)// 像素比较逻辑for (let y = 0; y < Math.min(rect1.height, rect2.height); y++) {for (let x = 0; x < Math.min(rect1.width, rect2.width); x++) {const alpha1 = data1[(y * rect1.width + x) * 4 + 3];const alpha2 = data2[(y * rect2.width + x) * 4 + 3];if (alpha1 > 0 && alpha2 > 0) return true;}}return false;}
性能瓶颈:该方案在移动端性能较差,建议仅在关键交互时使用。
3.2 优化策略
- 区域采样:将检测区域划分为网格,仅对可能碰撞的网格进行像素检测
- 颜色标记法:使用特定颜色通道存储碰撞信息,减少数据量
- 缓存机制:对静态物体预先计算碰撞掩模
四、分离轴定理(SAT):复杂多边形的终极方案
对于任意凸多边形,分离轴定理提供最通用的解决方案。其核心思想是:若两个凸多边形在任意轴上的投影不重叠,则它们不相交。
4.1 算法实现
function checkSATCollision(polygon1, polygon2) {const polygons = [polygon1, polygon2];for (let i = 0; i < polygons.length; i++) {const polygon = polygons[i];const otherPolygon = polygons[(i + 1) % 2];for (let j = 0; j < polygon.vertices.length; j++) {const nextIndex = (j + 1) % polygon.vertices.length;const edge = {x: polygon.vertices[nextIndex].x - polygon.vertices[j].x,y: polygon.vertices[nextIndex].y - polygon.vertices[j].y};const normal = { x: -edge.y, y: edge.x };const min1 = projectPolygon(polygon, normal);const min2 = projectPolygon(otherPolygon, normal);if (min1.max < min2.min || min2.max < min1.min) {return false;}}}return true;}function projectPolygon(polygon, axis) {let min = Infinity;let max = -Infinity;for (const vertex of polygon.vertices) {const projection = vertex.x * axis.x + vertex.y * axis.y;min = Math.min(min, projection);max = Math.max(max, projection);}return { min, max };}
实现要点:
- 需预先计算多边形的边法向量
- 投影计算需考虑浮点数精度问题
- 适用于凸多边形,凹多边形需先分解为凸多边形
五、性能优化实战建议
- 分层检测:先进行粗略检测(如AABB),再对可能碰撞的对象进行精确检测
- 空间分区:使用四叉树或网格分区减少检测次数
- 休眠机制:对静止物体暂停碰撞检测
- Web Workers:将复杂检测计算移至后台线程
六、实战案例解析
以经典《打砖块》游戏为例:
- 球体与砖块检测:使用圆形与矩形混合检测
- 砖块破碎效果:碰撞后将砖块分解为多个小矩形进行二次检测
- 性能优化:对已破碎的砖块区域建立空间索引
结论
Canvas小游戏的碰撞检测体系是一个从简单到复杂的渐进过程。开发者应根据游戏类型、性能需求和开发成本综合选择检测方案:
- 简单游戏:优先使用AABB矩形检测
- 中等复杂度:结合圆形检测与矩形检测
- 高端需求:在关键交互处使用SAT或像素级检测
掌握这些核心检测技术后,开发者可进一步探索物理引擎集成、碰撞响应优化等高级主题,构建出更加流畅真实的游戏体验。