js实现碰撞
检测矩形碰撞
使用矩形边界框检测碰撞是最简单的方法。假设两个矩形的位置和尺寸已知,可以通过比较它们的边界来判断是否重叠。
function checkRectCollision(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
);
}
检测圆形碰撞
对于圆形物体,通过比较两圆圆心距离与半径之和来判断碰撞。

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;
}
像素级碰撞检测
更精确的方法是使用像素级检测,适合不规则形状物体。HTML5 Canvas提供了getImageData方法可以获取像素数据。
function checkPixelCollision(ctx1, ctx2, x1, y1, x2, y2) {
const data1 = ctx1.getImageData(x1, y1, width, height).data;
const data2 = ctx2.getImageData(x2, y2, width, height).data;
for (let i = 0; i < data1.length; i += 4) {
if (data1[i+3] > 0 && data2[i+3] > 0) {
return true;
}
}
return false;
}
分离轴定理(SAT)
对于凸多边形之间的碰撞检测,分离轴定理是最可靠的方法。需要检查所有边的法向量作为潜在分离轴。

function projectPolygon(axis, polygon) {
let min = Infinity;
let max = -Infinity;
for (const point of polygon.points) {
const proj = point.x * axis.x + point.y * axis.y;
min = Math.min(min, proj);
max = Math.max(max, proj);
}
return {min, max};
}
function checkSATCollision(poly1, poly2) {
const axes = [...poly1.edges, ...poly2.edges].map(edge => {
return {x: -edge.y, y: edge.x}; // 法向量
});
for (const axis of axes) {
const proj1 = projectPolygon(axis, poly1);
const proj2 = projectPolygon(axis, poly2);
if (proj1.max < proj2.min || proj2.max < proj1.min) {
return false;
}
}
return true;
}
性能优化建议
对于大量物体的碰撞检测,应使用空间分割技术如四叉树或网格来减少检测次数。四叉树将空间递归划分为四个区域,只检测同一区域或相邻区域内的物体。
class Quadtree {
constructor(bounds, capacity) {
this.bounds = bounds;
this.capacity = capacity;
this.objects = [];
this.divided = false;
}
insert(obj) {
if (!this.bounds.contains(obj)) return false;
if (this.objects.length < this.capacity) {
this.objects.push(obj);
return true;
}
if (!this.divided) this.subdivide();
return (this.northeast.insert(obj) ||
this.northwest.insert(obj) ||
this.southeast.insert(obj) ||
this.southwest.insert(obj));
}
query(range, found) {
if (!this.bounds.intersects(range)) return found;
for (const obj of this.objects) {
if (range.contains(obj)) found.push(obj);
}
if (this.divided) {
this.northeast.query(range, found);
this.northwest.query(range, found);
this.southeast.query(range, found);
this.southwest.query(range, found);
}
return found;
}
}
物理引擎集成
对于复杂场景,建议使用成熟的物理引擎如Matter.js或Box2D。这些引擎提供了完整的碰撞检测和物理模拟功能。
// 使用Matter.js示例
const engine = Matter.Engine.create();
const boxA = Matter.Bodies.rectangle(400, 200, 80, 80);
const boxB = Matter.Bodies.rectangle(450, 50, 80, 80);
Matter.Composite.add(engine.world, [boxA, boxB]);
Matter.Events.on(engine, 'collisionStart', (event) => {
const pairs = event.pairs;
pairs.forEach(pair => {
console.log('碰撞发生在:', pair.bodyA, pair.bodyB);
});
});






