查询(Queries)
概述
学习目标:
- 理解查询的概念和作用
- 掌握如何定义和使用查询
- 了解查询过滤器的使用方法
- 理解自定义查询参数和查询组合
前置知识要求:
- 核心编程框架(ECS)
- 组件(Components)
- 实体(Entities)
- 系统(Systems)
- Rust 基础语法
核心概念
什么是查询?
查询用于访问具有特定组件的实体。查询会自动过滤出具有指定组件的实体,并允许系统对这些实体进行操作。
为什么使用查询?
- 自动过滤:查询自动过滤出具有指定组件的实体
- 高效访问:查询提供高效的组件访问方式
- 并行执行:查询可以并行执行,提高性能
查询的设计思想
查询采用数据导向的设计思想,将数据(组件)和逻辑(系统)分离。这种设计使得:
- 系统可以高效访问组件
- 查询可以并行执行,提高性能
- 查询可以灵活组合,实现复杂的查询需求
基础用法
基本查询
使用 Query<T> 查询具有特定组件的实体。
源代码文件:bevy/examples/ecs/ecs_guide.rs
代码示例:
1 | // 这个系统更新所有具有 `Player`、`Score` 和 `PlayerStreak` 组件的实体的分数 |
关键要点:
- 使用
Query<T>查询具有特定组件的实体 &T表示不可变访问组件&mut T表示可变访问组件- 查询可以同时访问多个组件
- 使用
Mut<T>类型进行可变访问
说明:
查询是访问组件的主要方式。查询会自动过滤出具有指定组件的实体,并允许系统对这些实体进行操作。查询可以并行执行,提高性能。
查询过滤器
使用查询过滤器进一步过滤查询结果。
源代码文件:bevy/examples/ecs/change_detection.rs
代码示例:
1 | /// 查询过滤器如 [`Changed<T>`] 和 [`Added<T>`] 确保只有匹配这些过滤器的实体 |
关键要点:
- 使用
Changed<T>过滤器查询已变更的组件 - 使用
Added<T>过滤器查询新添加的组件 - 使用
With<T>过滤器查询具有特定组件的实体 - 使用
Without<T>过滤器查询不具有特定组件的实体 - 使用
Ref<T>访问变更检测信息,但不过滤查询
说明:
查询过滤器用于进一步过滤查询结果。使用 Changed<T> 过滤器可以只查询已变更的组件,这对于性能优化很重要。使用 Added<T> 过滤器可以只查询新添加的组件。
进阶用法
自定义查询参数
使用 QueryData 派生宏定义自定义查询类型,避免使用元组。
源代码文件:bevy/examples/ecs/custom_query_param.rs
代码示例:
1 | use bevy::{ |
关键要点:
- 使用
QueryData派生宏定义自定义查询类型 - 自定义查询类型可以避免使用元组
- 自定义查询类型可以支持组合模式
- 自定义查询类型可以绕过 15 个组件的限制
- 使用
QueryFilter派生宏定义自定义过滤器类型
注意事项:
- 自定义查询类型需要实现
QueryDatatrait - 自定义过滤器类型需要实现
QueryFiltertrait - 使用
#[query_data(mutable)]属性定义可变查询
最佳实践:
- 对于复杂的查询,使用自定义查询类型
- 对于需要重用的查询,使用自定义查询类型
- 对于超过 15 个组件的查询,使用自定义查询类型
查询组合
查询组合用于处理实体间的交互,如碰撞检测。
源代码文件:bevy/examples/ecs/iter_combinations.rs
代码示例:
1 | use bevy::prelude::*; |
关键要点:
- 使用
iter_combinations_mut()获取可变组合迭代器 - 使用
fetch_next()获取下一对实体 - 查询组合会跳过重复的组合(如 (A, B) 和 (B, A))
- 查询组合用于处理实体间的成对交互
注意事项:
- 查询组合用于处理实体间的成对交互
- 查询组合会跳过重复的组合
- 查询组合对于大量实体可能较慢
最佳实践:
- 使用查询组合处理碰撞检测、物理交互等场景
- 注意性能影响,对于大量实体考虑使用空间分区
- 考虑使用并行查询组合提高性能
并行查询
并行查询使用并行迭代器提高系统执行效率。
源代码文件:bevy/examples/ecs/parallel_query.rs
代码示例:
1 | use bevy::{ecs::batching::BatchingStrategy, prelude::*}; |
关键要点:
- 使用
par_iter_mut()获取并行迭代器 - 使用
batching_strategy()自定义批处理策略 - 并行查询适用于计算密集型操作
- 对于简单操作,并行查询可能不会更快
注意事项:
- 并行查询适用于计算密集型操作
- 对于简单操作,并行查询可能不会更快
- 可以使用
batching_strategy()自定义批处理策略
最佳实践:
- 只在计算密集型操作时使用并行查询
- 对于简单操作,使用普通查询
- 根据操作复杂度调整批处理策略
实际应用
在游戏开发中的应用场景
查询在游戏开发中有广泛的应用:
- 游戏对象访问:访问玩家、敌人、道具等游戏对象
- 碰撞检测:使用查询组合检测实体间的碰撞
- 性能优化:使用并行查询提高系统执行效率
常见问题
问题 1:如何查询具有多个组件的实体?
解决方案:使用元组查询多个组件,如 Query<(&ComponentA, &ComponentB)>。
问题 2:如何查询不具有特定组件的实体?
解决方案:使用 Without<T> 过滤器,如 Query<&ComponentA, Without<ComponentB>>。
问题 3:如何优化查询性能?
解决方案:
- 只查询需要的组件
- 使用查询过滤器减少查询的实体数量
- 对于计算密集型操作,使用并行查询
性能考虑
- 查询优化:只查询需要的组件,减少查询开销
- 并行执行:查询可以并行执行,但可变访问会阻止并行
- 查询组合:注意性能影响,考虑使用空间分区
相关资源
相关源代码文件:
bevy/examples/ecs/ecs_guide.rs- ECS 完整指南示例(查询使用)bevy/examples/ecs/change_detection.rs- 变更检测示例(查询过滤器)bevy/examples/ecs/custom_query_param.rs- 自定义查询参数示例bevy/examples/ecs/iter_combinations.rs- 查询组合示例bevy/examples/ecs/parallel_query.rs- 并行查询示例
官方文档链接:
进一步学习建议:
- 学习系统(Systems),了解如何在系统中使用查询
- 学习组件(Components),了解如何定义组件
- 学习 ECS 进阶,了解查询的高级功能
索引:返回上级目录