在Rapier2D与Bevy中使用filter_groups属性过滤失效问题
使用Bevy Rapier的
filter_groups无法过滤障碍物的解决方法 尝试用KinematicCharacterController的filter_groups属性过滤部分障碍物,但始终无效,切换为filter_flags: QueryFilterFlags::all()时功能正常,但业务需求必须用filter_groups实现部分固定障碍物的过滤。当前角色的代码实现如下:
fn setup( mut commands: Commands, mut atlases: ResMut<Assets<TextureAtlas>>, server: Res<AssetServer>, ) { let image_handle: Handle<Image> = server.load("spritesheets/spritesheet_Mario.png"); let texture_atlas = TextureAtlas::from_grid( image_handle, Vec2::new(SPRITE_MARIO_WIDTH, SPRITE_MARIO_HEIGHT), SPRITESHEET_COLS, SPRITESHEET_ROWS, Option::from(Vec2::new(SPRITE_PADDING_X, SPRITE_PADDING_Y)), Option::from(Vec2::new(SPRITE_OFFSET_X, SPRITE_OFFSET_Y)), ); let atlas_handle = atlases.add(texture_atlas); commands .spawn(SpriteSheetBundle { sprite: TextureAtlasSprite::new(SPRITE_IDX_STAND), texture_atlas: atlas_handle, transform: Transform { scale: Vec3::new( SPRITE_RENDER_WIDTH / SPRITE_MARIO_WIDTH, SPRITE_RENDER_HEIGHT / SPRITE_MARIO_HEIGHT, 1.0, ), translation: Vec3::new(WINDOW_LEFT_X + 300.0, WINDOW_BOTTOM_Y + 300.0, 0.0), ..Default::default() }, ..Default::default() }) .insert(RigidBody::KinematicPositionBased) .insert(Collider::cuboid( SPRITE_MARIO_WIDTH / 2.0, SPRITE_MARIO_HEIGHT / 2.0, )) .insert(KinematicCharacterController{ filter_groups: Option::from(CollisionGroups::new( Group::GROUP_1, Group::ALL, // Even if I try to filter ALL )), ..Default::default() }) .insert(Direction::Right) .insert(ActiveEvents::COLLISION_EVENTS) .insert(ActiveHooks::MODIFY_SOLVER_CONTACTS); }
问题原因
filter_groups的碰撞规则是双向匹配的:只给角色设置CollisionGroups没用,必须给需要过滤的障碍物也配置对应的CollisionGroups,且两者的组规则要满足:
- 角色的
CollisionGroups第二个参数(允许碰撞的组)需排除目标障碍物的组 - 障碍物的自身组要被角色的排除规则覆盖
解决方案
- 给需要过滤的障碍物实体添加
CollisionGroups,将其归为特定组(比如GROUP_2) - 调整角色的
filter_groups,排除该组的障碍物 - 确保没有其他过滤配置(如
filter_flags)干扰filter_groups的生效
修改后的角色代码
.insert(KinematicCharacterController{ filter_groups: Some(CollisionGroups::new( Group::GROUP_1, Group::ALL - Group::GROUP_2, // 排除GROUP_2的障碍物 )), ..Default::default() })
障碍物配置示例
// 不需要被角色碰撞的障碍物 commands.spawn(( SpriteBundle { /* 障碍物渲染组件 */ }, RigidBody::Fixed, Collider::cuboid(50.0, 50.0), CollisionGroups::new( Group::GROUP_2, // 自身属于GROUP_2 Group::ALL, // 可根据需求设置允许碰撞的其他组 ), )); // 需要被角色碰撞的障碍物(可使用默认组或GROUP_1) commands.spawn(( SpriteBundle { /* 障碍物渲染组件 */ }, RigidBody::Fixed, Collider::cuboid(50.0, 50.0), CollisionGroups::new( Group::GROUP_1, Group::ALL, ), ));
补充说明
如果需求是只和特定组碰撞,可直接指定允许的组,比如Group::GROUP_1 | Group::GROUP_3,表示只与GROUP_1、GROUP_3的实体产生碰撞。
内容的提问来源于stack exchange,提问作者Adri HM
相关产品推荐
相关产品推荐

