UI 与文本
Text 和 UIRect 组件配合 Sprite 实现游戏中的文本渲染。TextPlugin 会在每帧自动将文本内容转换为纹理。
设置步骤
在场景编辑器中:创建实体 → 添加 LocalTransform、Sprite、Text 和 UIRect 组件。
- Text — 定义文本内容和样式(字体、大小、颜色、对齐)
- UIRect — 定义布局矩形(尺寸、锚点、旋转中心)
- Sprite — 文本系统内部使用,用于显示渲染后的纹理
Text 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
content | string | '' | 显示的文本内容 |
fontFamily | string | 'Arial' | 字体名称 |
fontSize | number | 24 | 字号(像素) |
color | Color | {r:1, g:1, b:1, a:1} | 文本颜色 RGBA(0–1) |
align | TextAlign | Left | 水平对齐方式 |
verticalAlign | TextVerticalAlign | Top | 垂直对齐方式 |
wordWrap | boolean | true | 启用自动换行 |
overflow | TextOverflow | Visible | 溢出处理模式 |
lineHeight | number | 1.2 | 行高倍率 |
UIRect 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
anchorMin | Vec2 | {0.5, 0.5} | 相对于父级的左下角锚点(0–1 范围) |
anchorMax | Vec2 | {0.5, 0.5} | 相对于父级的右上角锚点(0–1 范围) |
offsetMin | Vec2 | {0, 0} | 从 anchorMin 的像素偏移 |
offsetMax | Vec2 | {0, 0} | 从 anchorMax 的像素偏移 |
size | Vec2 | {100, 100} | 宽高(anchorMin 等于 anchorMax 时使用) |
pivot | Vec2 | {0.5, 0.5} | 旋转和缩放的中心点 |
当 anchorMin 等于 anchorMax 时,元素具有固定 size,定位在锚点位置。当两者不同时,元素在两个锚点之间拉伸,size 由 UILayoutPlugin 自动计算。
枚举类型
TextAlign
| 值 | 名称 | 说明 |
|---|---|---|
| 0 | Left | 左对齐 |
| 1 | Center | 居中对齐 |
| 2 | Right | 右对齐 |
TextVerticalAlign
| 值 | 名称 | 说明 |
|---|---|---|
| 0 | Top | 顶部对齐 |
| 1 | Middle | 垂直居中 |
| 2 | Bottom | 底部对齐 |
TextOverflow
| 值 | 名称 | 说明 |
|---|---|---|
| 0 | Visible | 文本溢出矩形边界 |
| 1 | Clip | 在边界处裁剪 |
| 2 | Ellipsis | 截断处显示省略号 |
运行时修改文本
在系统中通过 Mut() 查询 Text 组件来更新文本内容或样式:
import { defineSystem, addSystem, Query, Mut } from 'esengine';import { Text } from 'esengine';
addSystem(defineSystem( [Query(Mut(Text))], (query) => { for (const [entity, text] of query) { text.content = '已更新!'; text.fontSize = 32; } }));示例:动态计分板
一种常见模式是在数值变化时更新分数显示:
import { defineComponent, defineTag, defineSystem, addSystem, Query, Mut } from 'esengine';import { Text } from 'esengine';
const ScoreDisplay = defineTag('ScoreDisplay');
const GameState = defineComponent('GameState', { score: 0,});
addSystem(defineSystem( [Query(Mut(Text), ScoreDisplay), Query(GameState)], (displayQuery, stateQuery) => { let score = 0; for (const [, state] of stateQuery) { score = state.score; } for (const [, text] of displayQuery) { text.content = `分数:${score}`; } }));在编辑器中:创建一个文本实体,添加 Text、UIRect、Sprite、LocalTransform 和 ScoreDisplay 标签。
UIMask
UIMask 将子实体裁剪到父实体的 UIRect 边界内。任何超出矩形的子实体部分会被视觉裁切。
设置: 在父实体上添加 UIMask、UIRect 和 LocalTransform。所有子实体(及其后代)都会被裁剪到该矩形范围内。
UIMask 属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | true | 是否启用裁剪 |
嵌套遮罩
当子实体也拥有 UIMask 时,其裁剪矩形为自身 UIRect 与父级裁剪矩形的交集。这允许嵌套滚动区域或分层裁剪。
示例:可滚动列表
创建遮罩容器,然后移动子实体来实现滚动:
import { defineSystem, addSystem, Res, Input, Query, Mut, LocalTransform, Children } from 'esengine';import { UIMask } from 'esengine';import { ScrollList } from './components';
addSystem(defineSystem( [Res(Input), Query(Children, UIMask, ScrollList), Query(Mut(LocalTransform))], (input, maskQuery, childQuery) => { for (const [entity, children, mask, scroll] of maskQuery) { const scrollDelta = input.getScrollDelta(); for (const child of children.entities) { const [, transform] = childQuery.get(child); transform.position.y += scrollDelta * 20; } } }));UI 交互
ESEngine 提供了内置的 UI 交互系统,用于处理 UI 元素的悬停、按压和点击事件。
设置
在任何拥有 UIRect 和 LocalTransform 的 UI 实体上添加 Interactable 组件。UIInteractionPlugin(由 createWebApp() 自动注册)每帧执行命中检测并管理交互状态。
Interactable
标记实体为可交互。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | boolean | true | 是否启用交互 |
Button
在 Interactable 基础上添加状态机,支持可选的颜色过渡。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
state | ButtonState | Normal | 当前按钮状态(运行时只读) |
transition | ButtonTransition | null | null | 颜色过渡配置 |
ButtonState: Normal (0)、Hovered (1)、Pressed (2)、Disabled (3)
设置 transition 后,状态变化时 Sprite 颜色会自动更新:
import { Button, Interactable } from 'esengine';
world.insert(entity, Button, { state: 0, transition: { normalColor: { r: 1, g: 1, b: 1, a: 1 }, hoveredColor: { r: 0.9, g: 0.9, b: 0.9, a: 1 }, pressedColor: { r: 0.7, g: 0.7, b: 0.7, a: 1 }, disabledColor: { r: 0.5, g: 0.5, b: 0.5, a: 0.5 }, },});UIInteraction
由插件自动添加到拥有 Interactable 的实体上,提供逐实体状态:
| 属性 | 类型 | 说明 |
|---|---|---|
hovered | boolean | 指针悬停在该实体上 |
pressed | boolean | 实体正在被按压 |
justPressed | boolean | 本帧开始按压 |
justReleased | boolean | 本帧释放按压 |
UIEvents
UIEvents 资源在每帧收集交互事件。在系统中查询:
import { defineSystem, addSystem, Res } from 'esengine';import { UIEvents } from 'esengine';
addSystem(defineSystem( [Res(UIEvents)], (events) => { for (const e of events.query('click')) { console.log('点击了实体:', e.entity); } }));事件类型: click、press、release、hover_enter、hover_exit
ScreenSpace
用于根 UI 实体的标签组件。拥有 ScreenSpace、UIRect 和 LocalTransform 的实体会由 UILayoutPlugin 相对于相机边界进行布局。
import { ScreenSpace, UIRect, LocalTransform } from 'esengine';
world.insert(entity, ScreenSpace);world.insert(entity, UIRect, { anchorMin: { x: 0, y: 0 }, anchorMax: { x: 1, y: 1 }, offsetMin: { x: 0, y: 0 }, offsetMax: { x: 0, y: 0 }, size: { x: 100, y: 100 }, pivot: { x: 0.5, y: 0.5 },});