2D游戏开发必知:碰撞检测全解析

“等一下,我碰!”——常见的 2D 碰撞检测

在2D游戏开发中,”碰撞检测”(Collision Detection)是决定游戏交互真实性的核心技术。无论是角色跳跃踩踏平台、子弹击中敌人,还是道具拾取,都离不开精准的碰撞判断。本文将系统梳理2D碰撞检测的核心方法,从基础几何检测到高级优化策略,为开发者提供完整的技术解决方案。

一、基础几何碰撞检测

1. 轴对齐包围盒(AABB)

AABB(Axis-Aligned Bounding Box)是最简单高效的检测方式,通过比较两个矩形的边界坐标实现:

  1. def aabb_check(box1, box2):
  2. return (box1.x < box2.x + box2.width and
  3. box1.x + box1.width > box2.x and
  4. box1.y < box2.y + box2.height and
  5. box1.y + box1.height > box2.y)

适用场景:规则形状物体(如方块角色、平台)的快速检测
优势:计算量小(仅需4次比较),适合移动设备
局限:无法处理旋转物体,紧密贴合度低

2. 圆形碰撞检测

基于圆心距离与半径和的比较:

  1. import math
  2. def circle_collision(circle1, circle2):
  3. dx = circle1.x - circle2.x
  4. dy = circle1.y - circle2.y
  5. distance = math.sqrt(dx*dx + dy*dy)
  6. return distance < (circle1.radius + circle2.radius)

适用场景:球形物体(如弹球、粒子效果)
优势:天然支持旋转物体,计算效率高
优化技巧:可省略平方根计算,直接比较距离平方

3. 分离轴定理(SAT)

处理凸多边形碰撞的核心算法,通过检测所有可能的分离轴实现:

  1. def project_polygon(axis, vertices):
  2. min_proj = max_proj = dot(axis, vertices[0])
  3. for vertex in vertices[1:]:
  4. proj = dot(axis, vertex)
  5. min_proj = min(min_proj, proj)
  6. max_proj = max(max_proj, proj)
  7. return min_proj, max_proj
  8. def sat_check(poly1, poly2):
  9. edges = get_edges(poly1) + get_edges(poly2)
  10. for edge in edges:
  11. axis = perpendicular(edge)
  12. proj1 = project_polygon(axis, poly1.vertices)
  13. proj2 = project_polygon(axis, poly2.vertices)
  14. if not overlaps(proj1, proj2):
  15. return False
  16. return True

适用场景:任意凸多边形(如不规则地形、斜坡)
关键点:需检测所有边对应的法线轴,计算量较大
优化方向:提前终止检测(发现分离轴立即返回)

二、高级检测技术

1. 像素级碰撞检测

通过逐像素比较实现最高精度检测,常用方法包括:

  • 颜色键检测:为碰撞区域设置特定颜色
  • Alpha通道检测:利用透明度信息判断碰撞

    1. # 伪代码示例
    2. def pixel_perfect_collision(sprite1, sprite2):
    3. # 获取两个精灵的位图数据
    4. bitmap1 = sprite1.get_bitmap()
    5. bitmap2 = sprite2.get_bitmap()
    6. # 计算重叠区域
    7. overlap_area = calculate_overlap(sprite1, sprite2)
    8. # 遍历重叠像素
    9. for x in range(overlap_area.width):
    10. for y in range(overlap_area.height):
    11. if (bitmap1.get_pixel(x,y).alpha > 0 and
    12. bitmap2.get_pixel(x,y).alpha > 0):
    13. return True
    14. return False

    适用场景:不规则形状(如复杂角色、特效)
    性能优化

  • 结合粗检测阶段(先用AABB筛选)
  • 使用位掩码加速像素比较
  • 限制检测频率(如每3帧检测一次)

2. 空间分区技术

解决大量物体检测时的性能问题:

  • 网格分区:将场景划分为固定大小网格
  • 四叉树:递归分割空间,动态适应物体分布

    1. class QuadTreeNode:
    2. def __init__(self, boundary, capacity):
    3. self.boundary = boundary # 节点边界
    4. self.capacity = capacity # 最大容量
    5. self.points = [] # 存储的物体
    6. self.divided = False # 是否已分割
    7. self.children = None # 子节点
    8. def insert(self, point):
    9. if not self.boundary.contains(point):
    10. return False
    11. if len(self.points) < self.capacity:
    12. self.points.append(point)
    13. return True
    14. else:
    15. if not self.divided:
    16. self.subdivide()
    17. return (self.children[0].insert(point) or
    18. self.children[1].insert(point) or
    19. self.children[2].insert(point) or
    20. self.children[3].insert(point))

    选择建议

  • 静态场景:网格分区(实现简单)
  • 动态场景:四叉树(自适应性强)
  • 物体分布不均:空间哈希(内存效率高)

三、碰撞响应处理

检测到碰撞后,需要正确处理物体间的相互作用:

1. 位置修正

当物体穿透时,需将其移回合法位置:

  1. def resolve_penetration(obj1, obj2, penetration):
  2. # 计算修正方向(从obj1指向obj2的法线)
  3. correction = penetration.normalized() * (penetration.length() * 0.5)
  4. obj1.position -= correction
  5. obj2.position += correction

关键参数

  • 穿透深度(penetration depth)
  • 修正比例(通常取50%-100%)
  • 最大修正次数(防止无限循环)

2. 物理响应

实现弹性碰撞效果:

  1. def elastic_collision(obj1, obj2):
  2. # 计算相对速度
  3. velocity_diff = obj1.velocity - obj2.velocity
  4. # 计算法线方向的速度分量
  5. dot_product = dot(velocity_diff, normal)
  6. # 计算冲量(使用恢复系数e)
  7. e = 0.8 # 弹性系数
  8. impulse = (1 + e) * dot_product / (1/obj1.mass + 1/obj2.mass)
  9. # 应用冲量
  10. obj1.velocity -= (impulse / obj1.mass) * normal
  11. obj2.velocity += (impulse / obj2.mass) * normal

物理参数

  • 质量(mass)
  • 恢复系数(0=完全非弹性,1=完全弹性)
  • 摩擦系数(可选)

四、性能优化策略

1. 检测阶段划分

采用”粗检测→细检测”的多阶段流程:

  1. 1. 空间分区筛选(四叉树/网格)
  2. 2. 包围盒检测(AABB/圆形)
  3. 3. 精确形状检测(SAT/像素级)
  4. 4. 碰撞响应处理

效果:可减少90%以上的冗余计算

2. 缓存优化

  • 预计算物体几何信息(如多边形法线)
  • 复用计算结果(如连续帧间的边界框)
  • 使用对象池管理检测数据

3. 并行计算

  • 多线程处理独立物体的检测
  • GPU加速像素级检测(使用Compute Shader)
  • SIMD指令优化向量计算

五、实用建议

  1. 选择合适的检测精度:根据游戏类型平衡精度与性能(如休闲游戏可用AABB,动作游戏需SAT)

  2. 分层检测体系:建立”世界→区域→物体”的检测层级,减少无效比较

  3. 调试可视化:实现碰撞边界渲染功能,便于快速定位检测问题

    1. # 调试渲染示例(使用Pygame)
    2. def draw_debug(screen, objects):
    3. for obj in objects:
    4. if obj.show_debug:
    5. # 绘制AABB
    6. pygame.draw.rect(screen, RED, obj.aabb, 1)
    7. # 绘制法线(SAT用)
    8. if hasattr(obj, 'normals'):
    9. for normal in obj.normals:
    10. end_point = (obj.center.x + normal.x*20,
    11. obj.center.y + normal.y*20)
    12. pygame.draw.line(screen, GREEN, obj.center, end_point, 2)
  4. 性能监控:实时统计检测耗时,设置性能预警阈值

  5. 工具链建设:开发自动化测试用例,覆盖各种碰撞场景

结语

2D碰撞检测是游戏物理系统的基石,其实现质量直接影响游戏体验。开发者应根据项目需求,灵活组合基础检测方法与高级优化技术。建议从AABB开始实现,逐步增加复杂度,同时建立完善的调试和性能监控体系。随着游戏复杂度的提升,空间分区和并行计算将成为关键优化手段。掌握这些技术后,开发者将能创造出更具沉浸感和物理真实性的2D游戏世界。