跳转到内容

UI 控件

所有控件都需要在同一实体上添加 InteractableUIRect。交互事件处理详见 UI 交互

获取特定控件

当你在场景中放置了多个控件后,使用 Query 来查找特定的那一个。

按标签查找(推荐)

定义一个 Tag 并在编辑器中挂到实体上,然后用 query.single() 直接获取唯一匹配的实体:

import { defineTag, defineSystem, addSystem, Query, Mut, ProgressBar } from 'esengine';
const HealthBar = defineTag('HealthBar');
addSystem(defineSystem(
[Query(Mut(ProgressBar), HealthBar)],
(query) => {
const [, bar] = query.single()!;
bar.value = playerHealth / maxHealth;
}
));

按名称查找

编辑器中每个实体都有 Name 组件。将它和控件组件一起查询:

addSystem(defineSystem(
[Query(Mut(ProgressBar), Name)],
(query) => {
for (const [, bar, name] of query) {
if (name.value === 'HealthBar') bar.value = playerHealth / maxHealth;
if (name.value === 'ManaBar') bar.value = playerMana / maxMana;
if (name.value === 'ExpBar') bar.value = playerExp / expToNextLevel;
}
}
));

findEntityByName + 直接访问

使用 GetWorld() 获取 World 实例。findEntityByName() 按编辑器中的名称查找实体,然后 world.get() / world.set() 以 O(1) 读写组件:

import { GetWorld, findEntityByName, ProgressBar } from 'esengine';
addSystem(defineSystem(
[GetWorld()],
(world) => {
const entity = findEntityByName(world, 'HealthBar');
if (entity) {
const bar = world.get(entity, ProgressBar);
bar.value = playerHealth / maxHealth;
world.set(entity, ProgressBar, bar);
}
}
));

处理特定控件的事件

Tag + hasEvent

先用 query.single() 获取实体 ID,然后用 UIEvents.hasEvent() 直接检查——无需循环:

import { defineTag, defineSystem, addSystem, Res, Query } from 'esengine';
import { UIEvents, Button } from 'esengine';
const StartButton = defineTag('StartButton');
addSystem(defineSystem(
[Res(UIEvents), Query(Button, StartButton)],
(events, query) => {
const match = query.single();
if (match && events.hasEvent(match[0], 'click')) {
startGame();
}
}
));

使用 UIInteraction(无需 UIEvents)

对于简单的按下/释放检测,直接读取 UIInteraction 组件:

import { UIInteraction } from 'esengine';
const StartButton = defineTag('StartButton');
addSystem(defineSystem(
[Query(UIInteraction, StartButton)],
(query) => {
const match = query.single();
if (match) {
const [, interaction] = match;
if (interaction.justPressed) startGame();
}
}
));

按名称匹配事件

当需要在一个系统中处理多个控件的事件时:

addSystem(defineSystem(
[Res(UIEvents), Query(Button, Name)],
(events, query) => {
for (const e of events.query('click')) {
for (const [entity, , name] of query) {
if (entity === e.entity) {
console.log('点击了:', name.value);
}
}
}
}
));

Button

Interactable 之上的状态机,支持可选颜色过渡。

属性类型默认值说明
stateButtonStateNormalNormal (0)、Hovered (1)、Pressed (2)、Disabled (3)
transitionColorTransition | nullnull各状态颜色
cmds.entity(button).insert(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 },
},
});

Toggle

复选框,可选分组实现互斥。

属性类型默认值说明
isOnbooleantrue开关状态
graphicEntityEntity0显示/隐藏的子实体(勾选标记)
groupEntity0ToggleGroup 实体,实现单选按钮行为
transitionColorTransition | nullnull颜色过渡
onColorColor{r:0.2, g:0.6, b:1, a:1}开启时的颜色(无 transition 时使用)
offColorColor{r:0.4, g:0.4, b:0.4, a:1}关闭时的颜色(无 transition 时使用)

ToggleGroup — 挂载到父实体使子级 Toggle 互斥:

属性类型默认值说明
allowSwitchOffbooleanfalse允许所有 Toggle 关闭

监听开关变化:

addSystem(defineSystem(
[Res(UIEvents), Query(Toggle, Name)],
(events, query) => {
for (const e of events.query('change')) {
for (const [entity, toggle, name] of query) {
if (entity === e.entity) {
console.log(name.value, '现在是:', toggle.isOn);
}
}
}
}
));

Slider

交互式数值滑块,带填充和可选可拖拽手柄。

属性类型默认值说明
valuenumber0当前值
minValuenumber0最小值
maxValuenumber1最大值
directionFillDirectionLeftToRightLeftToRight (0)、RightToLeft (1)、BottomToTop (2)、TopToBottom (3)
fillEntityEntity0填充可视化的子实体
handleEntityEntity0可拖拽手柄的子实体
wholeNumbersbooleanfalse吸附到整数

监听滑块变化:

addSystem(defineSystem(
[Res(UIEvents), Query(Slider, Name)],
(events, query) => {
for (const e of events.query('change')) {
for (const [entity, slider, name] of query) {
if (entity === e.entity) {
if (name.value === 'VolumeSlider') setVolume(slider.value);
if (name.value === 'BrightnessSlider') setBrightness(slider.value);
}
}
}
}
));

ProgressBar

非交互式进度条显示。

属性类型默认值说明
valuenumber0进度 0–1
fillEntityEntity0填充的子实体
directionFillDirectionLeftToRight填充方向

下拉列表选择器。

属性类型默认值说明
optionsstring[][]选项标签
selectedIndexnumber-1选中项索引
isOpenbooleanfalse列表可见性
listEntityEntity0下拉列表的子实体
labelEntityEntity0显示选中标签的子实体

ScrollView

带惯性和弹性回弹的滚动容器。

属性类型默认值说明
contentEntityEntity0持有可滚动内容的子实体
horizontalEnabledbooleanfalse启用水平滚动
verticalEnabledbooleantrue启用垂直滚动
scrollXnumber0当前水平偏移
scrollYnumber0当前垂直偏移
inertiabooleantrue启用惯性滚动
decelerationRatenumber0.135惯性摩擦力
elasticbooleantrue边缘回弹
wheelSensitivitynumber0.1鼠标滚轮灵敏度
contentWidthnumber0可滚动内容总宽度(由插件自动计算)
contentHeightnumber0可滚动内容总高度(由插件自动计算)

ListView

大列表虚拟滚动——仅渲染可见项目。

属性类型默认值说明
itemHeightnumber40固定项目高度
itemCountnumber0总项目数
scrollYnumber0滚动位置
overscannumber2视口上下额外渲染的项目数

自定义项目渲染器

使用 setListViewRenderer() 定义每个列表项的填充方式。回调接收项目索引和要配置的实体:

import { setListViewRenderer, Text, Sprite } from 'esengine';
setListViewRenderer(listEntity, (index, itemEntity) => {
world.set(itemEntity, Text, { content: `Item ${index}`, fontSize: 16 });
});
参数类型说明
indexnumber列表项的 0 基索引
entityEntity该列表项的实体——用组件填充它

TextInput

可编辑文本输入框,支持光标、选择和占位符。

属性类型默认值说明
valuestring''当前文本
placeholderstring''为空时的提示
placeholderColorColor{r:0.6, g:0.6, b:0.6, a:1}占位符颜色
fontFamilystring'Arial'字体
fontSizenumber16字号
colorColor{r:1, g:1, b:1, a:1}文本颜色
backgroundColorColor{r:0.15, g:0.15, b:0.15, a:1}背景颜色
paddingnumber6内边距
maxLengthnumber0最大字符数(0 = 无限)
multilinebooleanfalse允许换行
passwordbooleanfalse密码遮罩
readOnlybooleanfalse禁止编辑
focusedbooleanfalse当前是否获得焦点
cursorPosnumber0文本中的当前光标位置
dirtybooleantrue是否需要重新渲染

事件: change(值变化)、submit(单行模式下按 Enter)

下一步