MIT 许可证 NuGet

首页 / 文档 / 2D 控件

2D 控件

精灵、形状和文本与 3D 模型是同一面板树中的控件,在同一帧的 Overlay 阶段绘制。没有第二个框架要学,也没有 UI 事件系统 — 按钮就是一个带委托的控件。

你在哪里摆放东西

你对着 DesignResolution 布局,默认 1280×720。 BasicResolution 是你实际写坐标的盒, 它等于什么取决于平台。

属性桌面与 Web手机与平板
BasicResolution等于 DeviceResolution — 你在用真实像素布局。等于 DesignResolution — 设计盒被保留并缩放。
Scale1。两个轴比中较小的那个,让整个设计盒保持可见。
ExtendResolution等于 DeviceResolution。设计盒沿较长轴生长,覆盖高屏手机多出的空间。
DeviceResolution始终是真实交换链的像素尺寸。

实用规则:把任何必须保持可达的东西锚定到 BasicResolution,把背景和边缘装饰拉伸到 ExtendResolution。这样你在 20:9 手机上得到 没有黑边的布局,而不必维护第二套设计。

调整大小只重新计算 Scale 和 ExtendResolution。 BasicResolution 被有意地放着不动,所以拖动窗口 边缘不会重排一个移动端布局。

五种类型

控件用途
Sprite2D屏幕空间图像,包括按纹理名寻址的实时 Compute 输出。
Sprite3D世界锚定的公告牌:标记、表情、浮动图标。
Shape点、矩形、圆、圆角矩形和面板装饰用的框。
TextsMSDF 文本。见 文本与字体。
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 下重影的方式。

纯 2D 应用

在应用本身上设置域,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 唤起原生键盘,所以编辑看起来 像操作系统,而不是像你的应用。