,让 RemSize 真正成为根字号)
Bevy 0.20 迁移指南TextFont 默认字号改为 FontSize::Rem(1.)让 RemSize 真正成为根字号【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy本文基于 Bevy 仓库中的官方迁移文档 default_font_size_is_rem.md 展开讲清 0.20 版本中TextFont::default()默认字号从FontSize::Px(20.)变为FontSize::Rem(1.)的动机与行为差异并结合 bevy_text 与 bevy_ui 的源码说明RemSize资源如何参与字号求值与重排最后给出保持固定字号与跟随根字号缩放两种迁移写法。读完后你能判断自己的文本代码在 0.20 下是否需要改动以及改动点应该写在哪里。一、变更内容默认字号从固定 20px 变为 1rem迁移文档给出的核心变更只有一句话TextFont::default()now usesFontSize::Rem(1.)instead ofFontSize::Px(20.), so that theRemSizeresource actually sets the default font size.也就是说旧行为0.19 及以前没有显式设置字号的文本字号被硬编码为 20 逻辑像素FontSize::Px(20.)与RemSize资源无关新行为0.20默认字号改为FontSize::Rem(1.)即1 个根字号单位由RemSize资源决定。由于RemSize的默认值恰好是 20 逻辑像素所以在默认配置下渲染结果完全一致但从此以后凡是保持默认字号的文本都会随RemSize的修改而整体缩放。文档给出的迁移建议是如果你希望文本大小固定不变就显式设置像素字号// 0.20 TextFont { font_size: FontSize::Px(20.), ..default() }这个改动是 Bevy 文本子系统 rem/em 单位支持的一部分与同 PR#25231中的另一篇迁移文档 val_em_and_rem.md 描述的Val::Em/Val::Rem变体、EmSize组件、FontSize::eval签名变更共同构成了 0.20 的根字号体系。二、源码印证TextFont::default()现在返回 Rem(1.)在 crates/bevy_text/src/text.rs 中TextFont的Default实现已经落实了这一变更impl Default for TextFont { fn default() - Self { Self { font: Default::default(), font_size: FontSize::Rem(1.), style: FontStyle::Normal, weight: FontWeight::NORMAL, width: FontWidth::NORMAL, font_features: FontFeatures::default(), font_variations: FontVariations::default(), font_smoothing: Default::default(), } } }需要注意一个容易混淆的细节TextFont的默认字号变了但FontSize枚举自身的Default实现仍然是Px(20.)见 crates/bevy_text/src/text.rsimpl Default for FontSize { fn default() - Self { Self::Px(20.) } }因此直接调用TextFont::default()绝大多数 UI/2D 文本路径都走这里得到的是Rem(1.)而单独使用FontSize::default()或..Default::default()展开font_size字段的地方得到的仍是Px(20.)。二者不一致正是这类迁移的常见坑点升级时建议全局搜索FontSize::default()和TextFont::default()确认行为是否符合预期。三、RemSize根字号资源的定义、注册与求值3.1 资源定义与默认值RemSize定义在 crates/bevy_text/src/text.rs/// Default [RemSize] and [EmSize], in logical pixels pub const DEFAULT_REM_SIZE_PX: f32 20.0; /// The root font size, in logical pixels. /// /// Rem units always resolve against this one global resource, including /// FontSize::Rem, LetterSpacing::Rem and Val::Rem. #[derive(Resource, Copy, Clone, Debug, PartialEq, Deref, DerefMut, Reflect)] pub struct RemSize(pub f32); impl Default for RemSize { fn default() - Self { Self(DEFAULT_REM_SIZE_PX) } }要点RemSize(pub f32)是单一全局Resource单位为逻辑像素默认值 20.0 对应常量DEFAULT_REM_SIZE_PX文档注释明确了它的作用域FontSize::Rem、LetterSpacing::Rem和Val::Rem三种 rem 单位都只解析到这一个全局资源该资源由TextPlugin在插件构建时注册init_resource::RemSize()见 crates/bevy_text/src/lib.rs。也就是说只要你的应用启用了文本功能RemSize就可用无需手动注册。3.2FontSize::evalrem 如何变成像素FontSize是文本字号的枚举支持Px、Vw、Vh、VMin、VMax、Rem六种单位定义见 crates/bevy_text/src/text.rs。求值入口是eval方法crates/bevy_text/src/text.rsimpl FontSize { /// Evaluate the font size to a value in logical pixels pub fn eval( self, // Viewport size in logical pixels logical_viewport_size: Vec2, // Base Rem size in logical pixels rem_size: RemSize, ) - f32 { match self { FontSize::Px(s) s, FontSize::Vw(s) logical_viewport_size.x * s / 100., FontSize::Vh(s) logical_viewport_size.y * s / 100., FontSize::VMin(s) logical_viewport_size.min_element() * s / 100., FontSize::VMax(s) logical_viewport_size.max_element() * s / 100., FontSize::Rem(s) rem_size.0 * s, } } }FontSize::Rem(s)的求值就是rem_size.0 * sRem(1.)在当前默认配置下等于20.0 * 1.0 20逻辑像素与旧版的Px(20.)数值相同——这就是迁移文档所说renders identically渲染结果一致的数学依据。另一个值得注意的签名变化0.20 中eval的第二个参数从裸f32改成了RemSize类型。这一点在 val_em_and_rem.md 中有专门记录// 0.19 let size font_size.eval(logical_viewport_size, rem_size_px); // 0.20 let size font_size.eval(logical_viewport_size, RemSize(rem_size_px));如果你自己封装了字号计算逻辑这是需要跟着改的调用点。3.3 渲染管线中的重排机制默认字号变成Rem之后修改RemSize能全局缩放文本这一行为是如何生效的从源码结构看答案在文本管线与重排标记里TextPipeline::update_buffer在遍历每个文本 span 时如果发现字号是 rem 系单位就把该文本块的uses_rem_sizes标记置为 true见 crates/bevy_text/src/pipeline.rsmatch text_font.font_size { crate::FontSize::Vw(_) | crate::FontSize::Vh(_) | crate::FontSize::VMin(_) | crate::FontSize::VMax(_) computed.uses_viewport_sizes true, crate::FontSize::Rem(_) computed.uses_rem_sizes true, _ (), }随后字号通过text_font.font_size.eval(logical_viewport_size, base_rem_size)求值crates/bevy_text/src/pipeline.rs。ComputedTextBlock持有uses_rem_sizes标志crates/bevy_text/src/text.rs其needs_rerender方法会在RemSize发生变化且该文本块使用了 rem 单位时返回 true从而触发重新排版crates/bevy_text/src/text.rspub fn needs_rerender( self, is_viewport_size_changed: bool, is_rem_size_changed: bool, ) - bool { self.needs_rerender || (is_viewport_size_changed self.uses_viewport_sizes) || (is_rem_size_changed self.uses_rem_sizes) }这个设计的实际效果是只有使用了 rem或视口单位的文本才会因RemSize变化而重排纯Px文本不受影响避免不必要的全量重排开销。这也再次说明0.20 之后默认字号的文本天然进入了 rem 依赖集合而显式写成Px的文本则被排除在外——这正是迁移文档推荐固定尺寸请显式写Px的底层原因。四、对 UI 布局与文本输入的影响RemSize不只影响字号本身它已经贯穿 UI 布局链路4.1 UI 节点的font_size转换在 crates/bevy_ui/src/geometry.rs 中Val到FontSize的转换显示未显式设置字号的 UI 节点Val::Auto会被转成FontSize::Rem(1.)Val::Em(em)也会被归一化为FontSize::Rem(em)em 相对于本节点字号解析先折算成 rem 表达Val::Auto FontSize::Rem(1.), Val::Px(px) FontSize::Px(px), Val::Percent(percent) FontSize::Rem(percent / 100.), Val::Rem(rem) FontSize::Rem(rem), Val::Em(em) FontSize::Rem(em), // see comment above也就是说没有手动设置字号的 UI 文本在 0.20 中会统一走 rem 路径这是本次迁移影响面最大的场景。4.2 文本输入组件的重排条件bevy_ui的文本输入布局系统同样感知了这次变化。crates/bevy_ui/src/widget/text_input_layout.rs 中的重排条件明确加入了字号是 rem 且RemSize已变化的分支|| matches!(text_font.font_size, FontSize::Rem(_)) rem_size.is_changed()并在光标宽度等计算中直接用text_font.font_size.eval(target.logical_size(), *rem_size)求值同文件 L515。所以基于TextInput的组件在RemSize变化时也会正确跟随缩放。4.3 同 PR 的其他连带变更由于 rem 求值需要根字号 节点字号两个输入同一 PR 还带来了 val_em_and_rem.md 记录的 API 变更做 0.20 升级时应一并检查Val、Val2、UiPosition、CornerRadius、RadialGradientShape、UiTransform::compute_affine、BorderRadius的resolve/compute_affine方法新增em_size: EmSize与rem_size: RemSize两个参数ComputedNode新增em_size、rem_size字段用于记录布局时实际采用的字号方便下游如 box shadow复用Node现在要求EmSize组件从bevy_text导出、经bevy_ui::prelude可用节点有TextFont时会在TextFont、RemSize或渲染目标信息变化时自动重算EmSize没有TextFont时该值由应用自行维护默认值为DEFAULT_REM_SIZE_PX20 逻辑像素且不跟随RemSize的后续变化——需要跟随根字号的布局值应使用Val::Rem。五、迁移实操如何写代码5.1 场景一保持固定字号推荐大多数游戏 UI如果你的文本尺寸是美术规格定的固定像素按迁移文档显式写死即可use bevy::prelude::*; fn setup(mut commands: Commands) { commands.spawn(Text2d::new(Hello Bevy 0.20)).insert(TextFont { font_size: FontSize::Px(20.), ..default() }); }也可以走链式构造器TextFont::from_font_size/with_font_size见 crates/bevy_text/src/text.rs例如TextFont::from_font_size(20_f32)会构造出Px语义的字号。仓库示例中的既有写法本身就是这种风格如 examples/2d/text2d.rs 里的font_size: FontSize::Px(50.0)、examples/2d/texture_atlas.rs 中的FontSize::Px(42.0)这些文本在 0.20 中行为不变。5.2 场景二让文本跟随根字号缩放如果你希望做全局字号调节例如设置面板里的 A/A 选项、高分辨率适配现在只需修改RemSize所有保持默认或显式Rem的文本会自动重排fn change_root_font_size(mut rem_size: ResMutRemSize) { rem_size.0 32.0; // 所有 Rem(1.) 的默认文本变为 32 逻辑像素 }生效链路是RemSize变化 → 使用 rem 字号的文本块needs_rerender为 truecrates/bevy_text/src/text.rs→ 文本管线按rem_size.0 * s重新求值并排版crates/bevy_text/src/pipeline.rs。注意一个行为差异在旧版本中同样的操作对默认文本完全无效因为默认就是Px(20.)升级后同一份代码里没写字号的文本会开始响应RemSize。如果你在旧代码里依赖过默认文本不会缩放这一事实需要在 0.20 中显式补上FontSize::Px。5.3 相关示例参考examples/2d/text2d.rs2D 文本示例演示显式FontSize::Px的常规写法examples/ui/text/letter_spacing.rs展示了RemSize与LetterSpacing::Rem/LetterSpacing::Px之间的换算方式LetterSpacing::Rem(v / rem_size.0)是理解一切 rem 单位都以RemSize为基准的良好参考。六、小结项目0.19 及以前0.20TextFont::default()的字号FontSize::Px(20.)FontSize::Rem(1.)FontSize::default()FontSize::Px(20.)仍为FontSize::Px(20.)默认RemSize—对默认字号无作用20.0逻辑像素且真正决定默认字号修改RemSize的影响不影响默认字号文本所有默认/Rem字号文本重排缩放保持固定尺寸的写法不写即可显式TextFont { font_size: FontSize::Px(20.), ..default() }本次变更本质上是把 Bevy 文本系统的根字号概念补齐RemSize从仅供显式Rem单位使用的资源升级为所有默认文本字号的真正来源并在渲染管线中通过uses_rem_sizes标记实现了按需重排。升级 0.20 时的检查清单很简单确认默认字号文本是否需要固定需要则显式写Px检查自定义代码中FontSize::eval、Val::resolve等 API 调用是否补上了RemSize/EmSize参数以及留意 val_em_and_rem.md 中Node对EmSize的新要求。【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考