精灵、形状和文本与 3D 模型是同一面板树中的控件,在同一帧的 Overlay 阶段绘制。没有第二个框架要学,也没有 UI 事件系统 — 按钮就是一个带委托的控件。
你对着 DesignResolution 布局,默认 1280×720。
BasicResolution 是你实际写坐标的盒,
它等于什么取决于平台。
| 属性 | 桌面与 Web | 手机与平板 |
|---|---|---|
BasicResolution | 等于 DeviceResolution — 你在用真实像素布局。 | 等于 DesignResolution — 设计盒被保留并缩放。 |
Scale | 1。 | 两个轴比中较小的那个,让整个设计盒保持可见。 |
ExtendResolution | 等于 DeviceResolution。 | 设计盒沿较长轴生长,覆盖高屏手机多出的空间。 |
DeviceResolution | 始终是真实交换链的像素尺寸。 | |
实用规则:把任何必须保持可达的东西锚定到
BasicResolution,把背景和边缘装饰拉伸到
ExtendResolution。这样你在 20:9 手机上得到
没有黑边的布局,而不必维护第二套设计。
调整大小只重新计算 Scale 和
ExtendResolution。
BasicResolution 被有意地放着不动,所以拖动窗口
边缘不会重排一个移动端布局。
| 控件 | 用途 |
|---|---|
Sprite2D | 屏幕空间图像,包括按纹理名寻址的实时 Compute 输出。 |
Sprite3D | 世界锚定的公告牌:标记、表情、浮动图标。 |
Shape | 点、矩形、圆、圆角矩形和面板装饰用的框。 |
Texts | MSDF 文本。见 文本与字体。 |
Texture | 引擎侧的纹理句柄,用于自定义上传和共享引用。 |
icon = new Sprite2D
{
Name = "Assets/Setting.png",
Color = Colors.White,
PosX = 20, PosY = 20, Width = 48,
OnClick = () => settingPanel.Alpha = 1f
};
AddControl(icon);
divider = new Shape
{
ShapeType = ShapeType.Square,
Color = Colors.DarkGray,
PosX = 20, PosY = 80, Width = 240, Height = 1
};
AddControl(divider);
精灵。 SpriteBase 携带两种精灵
类型都需要的东西:一个 Color 染色、
用于文件扩展名的 Ext、
用于源像素尺寸的 OriginWidth 和
OriginHeight,以及
从图集中画出一格的 SourceX/Y/Width/Height。
Clock 推进图集帧,
FlipX 和 FlipY 镜像它,而
TextureOverride 接受一次性上传 — 一个路径或
已解码的 RGBA8 像素 — 下一次更新消费它并清除。
形状。 ShapeType 是
Dot、Square、
Circle、RoundRect、
RectFrame、Gradual 或
GradualCircle,配以
控制框线粗细的 Border。曲线是解析式
抗锯齿,而不是缩放的位图,所以圆在任何尺寸下都锐利。
公告牌。 Sprite3D.Mode 选择它面向
相机的方式:Spherical 始终面向你,
Cylindrical 只绕世界 Y 轴转动,让名牌保持
直立,而 None 把朝向交给四元数
Rotation。
每个控件都有 OnClick 和
OnTouch,两者都从控件自己的
Update 内部触发。这有一个值得直说的后果:一个
你忘记更新的控件永远不会收到点击,即使它绘制得完美无缺。
Update 在调用
OnClick 时返回 true,并清除挂起的释放,让后面的
控件收不到同一次点击。因此更新顺序就是命中测试优先级:先更新你最顶层的
面板,并用返回值停止遍历其余部分。
MouseOver 会替你维护,它是闸门的一部分,与
Enable、Ready 和
Alpha > 0 一起。没有冒泡模型,没有焦点系统,也没有
命令模式。
实现了 IRenderOrder 的控件和面板按
Layer 排序,再按 Order,再按插入
索引 — 一个稳定的全序,所以重建的列表不会乱序。
RenderDomain 决定控件在帧中 何时 被
绘制,与它在树中的位置无关。
RenderDomain | 含义 |
|---|---|
Inherit | 跟随父级。默认值,几乎总是对的。 |
Scene | 与 3D 场景一起绘制,在后处理之前。经过色调映射、泛光、TAA 解析。 |
Overlay | 在所有东西之后绘制。不受后处理影响,这就是 UI 保持锐利的原因。 |
把一个世界内的叙事性屏幕放进 Scene 完全
正确。把 HUD 放进去,就是你意外让你的文本在 TAA 下重影的方式。
在应用本身上设置域,3D 通道就不花你任何代价:
RenderDomain = RenderDomain.Overlay;
这就是 Samples/Creator 所做的 — 同样的控件、同样的
面板模型,没有场景开销。域解析沿树向下继承,所以应用上的一行
覆盖它下面的每一个面板。
| 面板 | 你得到什么 |
|---|---|
BoardPanel | 一个带边框的板,FrameColor 可设置。大多数叠加层的背景。 |
FrameButton | 文本按钮,底色和文本各有独立的普通色和悬停色。 |
Input | 带描述、对齐、缩略和可选清除按钮的文本字段。 |
MovePanel | 滚动与滑动容器,内边距、尺寸和运动类型可配置。 |
Picker、SimplePicker | 基于 List<EData> 的单选或多选列表,带悬停色和 OnSelect。 |
ImageView、FullView | 带可选清除手势的缩略图,以及它的展开形态。 |
ObjectPicker | 不是小部件 — 是 3D 拾取与编辑面板。见 拾取与编辑。 |
没有 flexbox,没有约束,没有锚点,没有停靠。位置是你算出来的数字,
这对 HUD 来说很好,对四十行的设置屏幕来说很繁琐。文本输入也
委托给平台:Input 通过
DeviceServices.Dialog.ShowKeyboard 唤起原生键盘,所以编辑看起来
像操作系统,而不是像你的应用。