如何使用Pymunk Categories和Masks配置自定义碰撞规则
Pymunk ShapeFilter categories/mask 配置方法
核心逻辑
不用对位运算有畏难情绪,Chipmunk2D(Pymunk底层)的碰撞过滤规则非常直白,两个形状发生碰撞必须同时满足两个条件:
- 形状A的
categories值 与 形状B的mask值 做按位与(&)运算结果不为0- 形状B的
categories值 与 形状A的mask值 做按位与(&)运算结果不为0
你可以把这套规则理解成双向白名单:
categories是形状自身的身份标签,为32位整数,每一位对应一个独立类别,日常开发只要给每类对象分配一个唯一的、仅单个二进制位为1的值即可(也就是2的整数次幂),最多支持32个独立类别,完全覆盖常规项目需求mask是形状的碰撞许可名单,哪一类对应的二进制位设为1,就代表该形状认可对应类别的碰撞资格- 要给一个形状开放多个类别的碰撞权限,直接用按位或(
|)把对应类别的值拼接起来即可
针对你当前场景的落地配置
第一步:先给场景内所有需要独立判定碰撞的对象分配唯一类别值,注意线段和末端圆形是两个独立形状,需要单独分配类别:
# 每个值的二进制仅一位为1,互不冲突 CAT_WALL = 1 << 0 # 墙体 CAT_ANCHOR = 1 << 1 # 墙体上的锚点 CAT_SEGMENT = 1 << 2 # 连接锚点的线段 CAT_CIRCLE = 1 << 3 # 线段末端的圆形 CAT_CART = 1 << 4 # 小车
第二步:对照你提出的碰撞规则,逐个给形状配置ShapeFilter即可,group参数保持默认0即可,不需要额外设置:
from pymunk import ShapeFilter # 墙体:允许和小车、线段、末端圆形碰撞 wall_filter = ShapeFilter( categories=CAT_WALL, mask=CAT_CART | CAT_SEGMENT | CAT_CIRCLE ) # 锚点:不与任何对象碰撞 anchor_filter = ShapeFilter( categories=CAT_ANCHOR, mask=0 ) # 线段:允许和墙体、小车碰撞 segment_filter = ShapeFilter( categories=CAT_SEGMENT, mask=CAT_WALL | CAT_CART ) # 线段末端圆形:仅允许和墙体碰撞 end_circle_filter = ShapeFilter( categories=CAT_CIRCLE, mask=CAT_WALL ) # 小车:仅允许和墙体、线段碰撞 cart_filter = ShapeFilter( categories=CAT_CART, mask=CAT_WALL | CAT_SEGMENT )
规则校验
你可以直接套核心逻辑验证所有组合,不会出现规则外的碰撞:
- 小车与末端圆形:小车mask仅包含墙体、线段,和圆形的categories做与运算结果为0,不碰撞
- 线段与末端圆形:线段mask仅包含墙体、小车,和圆形的categories做与运算结果为0,不碰撞
- 锚点与所有对象:锚点mask为0,和任何对象的categories做与运算结果都为0,无碰撞
- 墙体与小车/线段/末端圆形、小车与线段:双向与运算结果均不为0,正常触发碰撞
常见注意事项
- 普通场景下每个形状的categories仅设置自己对应的单个类别位即可,不要随意给categories叠加多个值,容易出现规则冲突
- group参数优先级高于categories/mask规则,非必要不要设置非0的group值,避免规则被覆盖
- 后续新增碰撞类别时,直接按
1 << n的顺序往后递增值即可,不要复用已有类别的数值
内容的提问来源于stack exchange,提问作者Shark Coding
相关产品推荐
相关产品推荐

