制作第一个世界界面
这篇教程会把一个欢迎面板放进 Minecraft 世界。它不是固定在屏幕上的 HUD,而是一张真正存在于世界位置中的界面:玩家靠近时会自然变大,远离时会变小,也会被前方方块遮挡。
开始前,请先完成制作第一个界面,并确认普通页面能够保存和打开。
完成后的效果
最终页面包含:
- 一张约
2.2 × 1.3格大小的世界面板; - 标题“欢迎来到大厅”;
- 一行交互提示;
- 一个可以点击的按钮;
- 页面始终水平朝向查看它的玩家;
- 可以使用不同实例 ID,在多个位置重复打开。
第一步:创建世界页面
打开一个新的页面:
/chaui editor world_welcome进入编辑器后,在左侧“页面组件”中选择“页面变量”,设置页面本身的属性:
| 属性 | 推荐值 | 说明 |
|---|---|---|
| 页面宽 | 220 | 世界页面使用固定画布宽度更容易控制实际尺寸。 |
| 页面高 | 130 | 与后面的背景面板保持一致。 |
| 默认坐标 | absolute | 组件直接使用页面内坐标。 |
| 打开模式 | world | 作为世界页面打开。 |
| 世界 X | 当前目标位置 | 页面中心所在的世界 X 坐标。 |
| 世界 Y | 当前目标位置 | 页面中心所在的世界 Y 坐标。 |
| 世界 Z | 当前目标位置 | 页面中心所在的世界 Z 坐标。 |
| 世界缩放 | 0.01 | 每个 GUI 像素占 0.01 格。 |
| 世界朝向 | follow_player | 页面始终水平朝向玩家。 |
| 世界倾角 | 0 | 页面保持竖直;改为 90 时正面朝上横放。 |
切换到世界模式后,不会再显示“界面遮罩”。遮罩只属于普通屏幕页面,世界页面不需要配置。
第二步:添加背景
在“组件库”中添加一个矩形,并填写:
| 属性 | 推荐值 |
|---|---|
| ID | world_panel |
| X | 0 |
| Y | 0 |
| 宽 | 220 |
| 高 | 130 |
| 层级 | 0 |
| 指针处理 | block |
| 透明度 | 0.88 |
| 颜色 | #202730 |
背景覆盖整个页面画布。世界缩放为 0.01 时,这个页面实际约为 2.2 格宽、1.3 格高。
第三步:添加标题和说明
添加标题文本:
| 属性 | 推荐值 |
|---|---|
| ID | world_title |
| X | (220 - self.width) / 2 |
| Y | 24 |
| 宽、高 | 随文字自动,无需填写 |
| 内容 | 欢迎来到大厅 |
| 文字大小 | 1.5 |
| 对齐 | center |
再添加一行说明:
| 属性 | 推荐值 |
|---|---|
| ID | world_description |
| X | (220 - self.width) / 2 |
| Y | 54 |
| 宽、高 | 随文字自动,无需填写 |
| 内容 | 将准星移到按钮上即可交互 |
| 文字大小 | 1 |
| 对齐 | center |
世界页面中的组件仍然使用普通页面坐标。左上角是 0, 0,不需要填写 window.width 或 window.height。
上面的 220 是本例页面宽度,self.width 是文字的自动宽度,因此内容变化后仍能居中。限制长文本使用“每行字数”或“每行宽度”;“对齐”只决定多行文字之间如何对齐。
世界页面会按客户端窗口的实际物理像素密度绘制,GUI 缩放只影响像素密度换算,不会改变这里填写的逻辑坐标。
第四步:添加按钮
添加一个按钮:
| 属性 | 推荐值 |
|---|---|
| ID | world_button |
| 层级 | 10 |
| X | 65 |
| Y | 88 |
| 宽 | 90 |
| 高 | 24 |
| 指针处理 | auto |
| 缩放 | 1 |
| 透明度 | 1 |
| 文字 | 我知道了 |
| 图片路径 | gui/tutorial/button.png |
| 悬浮路径 | gui/tutorial/button_hover.png |
在按钮的左键脚本中填写:
日志("欢迎来到服务器")玩家点击后会在自己的聊天栏看到消息。世界页面不会因此关闭,方便继续观察和调整。
如果希望按钮直接关闭当前世界实例,可以改为:
日志("欢迎来到服务器")
关闭()无参数 关闭() / close() 会定位这次点击所属的世界实例,不需要在脚本里填写页面 ID 或实例 ID。
世界页面同样只会选择准星下最前面的一个组件。背景使用 pointerEvents: block 后,会挡住同一页面中位于它后方的交互组件;按钮因为 z 更高而正常接收准星悬浮和点击。编辑器预览也使用同一规则,可以先在预览里确认没有穿透。
第五步:保存页面
点击编辑器顶部“保存”,等待底部状态栏提示保存成功。页面会写入服务端的 plugins/ChaUI/pages/world_welcome.yml。
退出编辑器后,站到准备放置页面的位置附近。为了便于第一次查看,建议把页面中心放在玩家视线前方,并让 Y 坐标略高于地面。
第六步:使用页面默认位置打开
向自己打开页面:
/chaui openworld <玩家> world_welcome 111111 是这份世界页面的实例 ID。实例 ID 是普通字符串,纯数字可以直接使用。
页面打开后依次确认:
- 页面内容左右顺序正常。
- 移动位置时,页面仍然水平朝向自己。
- 页面会随观察距离自然改变屏幕中的大小。
- 页面前方有方块时,页面会被遮挡。
- 准星移动到按钮上时出现悬浮状态,点击后聊天栏出现消息。
第七步:临时指定位置打开
如果不想修改页面里保存的位置,可以在指令中临时覆盖:
/chaui openworld <玩家> world_welcome 大厅提示 <x> <y> <z> follow_player最后一个参数填写 follow_player 时,页面跟随玩家朝向;填写数字时,页面使用固定水平角度。
需要临时指定倾角时,在末尾再添加一个数字:
/chaui openworld <玩家> world_welcome 地面提示 <x> <y> <z> <yaw> 90pitch: 0 是教程当前使用的竖直欢迎牌,90 会让页面正面朝上横放,-90 会让正面朝下。制作地面地图时建议给 yaw 填固定数字,地图方向就不会随玩家位置旋转。
例如,同一个页面可以分别使用 大厅提示、任务提示、111 作为实例 ID,在不同位置打开多份。实例 ID 对同一玩家的全部世界页面全局唯一;如果另一个页面也使用 大厅提示,旧实例会先正常关闭,再被新页面替换。
让页面跟随玩家或实体
世界页面可以放在实体头顶,显示名称和血量。位置随目标移动,文字和进度条读取同一个绑定目标的数据。
把以下完整配置保存为 plugins/ChaUI/pages/entity_health.yml,然后执行 /chaui reload:
id: entity_health
version: 1
title: 实体血条
size:
width: 160
height: 40
coordinateMode: absolute
display:
mode: world
world:
# 固定模式才使用下面三个坐标。
x: 0
y: 64
z: 0
scale: 0.01
yaw: follow_player # 面向观看玩家,与位置跟随独立
pitch: 0
follow: player # 默认跟随观看玩家自己
entityUuid: "" # entity 模式才填写 UUID
offsetX: 0
offsetY: 2.4 # 从目标脚底向上 2.4 格
offsetZ: 0
vars: {}
papi:
refreshTicks: 20
values: {}
events:
open: ""
close: ""
methods: {}
elements:
- id: entity_name
type: text
parent: ""
visible: true
enabled: false
pointerEvents: pass
scale: 1
rotation: 0
opacity: 1
z: 1
layout:
x: (160 - self.width) / 2 # 本例页面宽度为 160
y: 2
text:
value: "{常量.绑定实体.名称} {常量.绑定实体.血量}/{常量.绑定实体.最大血量}"
font: ""
color: "#FFFFFF"
textSize: 1
align: center
events: {}
- id: entity_health_bar
type: progress
parent: ""
visible: true
enabled: false
pointerEvents: pass
scale: 1
rotation: 0
opacity: 1
z: 1
layout:
x: 10
y: 22
width: 140
height: 8
progress:
value: vals.boundEntity.health
min: 0
max: max(1, vals.boundEntity.maxHealth)
direction: left_to_right
path: "" # 留空使用内置样式,无需图片
fillPath: ""
gifLoop: true
gifLoopCount: 0
fillGifLoop: true
fillGifLoopCount: 0
events: {}让 Steve 看到自己头顶的页面:
/chaui openworld Steve entity_health self_health follow_player让 Steve 看到 Alex 头顶的页面:
/chaui openworld Steve entity_health alex_health follow_entity Alex 0 2.4 0把 Alex 换成实体的完整 UUID,就能跟随怪物或其他实体。观看玩家需要处于同一维度,目标也必须在客户端加载范围内;目标缺失或死亡时页面暂时隐藏,同一 UUID 重新可见后恢复。第一人称查看自己头顶的页面不方便,初次验证推荐跟随另一名玩家。
若页面需要替代 Alex 的原版名字条,可在保存的页面事件中写入 setPlayerNameVisible("Alex", false),它只影响当前观看者;对所有观看者生效则使用 setPlayerNameVisible("Alex", "all", false)。显隐独立于页面,关闭页面不会自动恢复;停止替代时要显式调用对应的 true 写法,完整示例见名称显隐脚本。服务端插件和观看者客户端都需更新到支持此能力的配套包。
follow_player 跟随观看者自己。需要全世界的玩家都看到同一个目标时,使用常驻实体跟随:
/chaui addworld world entity_health alex_health follow_entity Alex 0 2.4 0偏移按世界轴计算,不随实体旋转;offsetY 从实体脚底算起。新参数位于实例 ID 后面,和旧坐标指令末尾的朝向参数 follow_player 含义不同。全部格式和删除方式见插件指令,更多数据见只读常量。
第八步:关闭指定实例
/chaui closeworld <玩家> 111如果打开时使用的是其他实例 ID,关闭时也要填写对应的 ID。实例 ID 在同一玩家当前打开的全部世界页面中全局唯一,因此关闭时不需要填写页面 ID。
第九步:把欢迎页面设为全服常驻
如果这个页面要长期用作大厅广告牌或欢迎处,不需要为每个玩家分别执行 openworld。把它注册到对应 Bukkit 世界:
/chaui addworld world world_welcome 大厅欢迎短格式使用页面保存的 X、Y、Z、yaw 与 pitch。需要为常驻实例覆盖位置时使用:
/chaui addworld world world_welcome 大厅欢迎 <x> <y> <z> follow_player旧的完整格式会使用 pitch: 0。如果常驻页面需要横放,在末尾追加倾角:
/chaui addworld world world_welcome 地面欢迎 <x> <y> <z> <yaw> 90注册成功后,当前位于 world 且客户端已就绪的玩家会立即看到页面;以后进入服务器或从其他维度回到 world 的玩家也会自动打开。离开 world 时页面自动关闭,不会错误显示到下界或末地的相同坐标。
临时为某个玩家执行 closeworld 不会删除常驻记录。需要永久停止自动打开时执行:
/chaui removeworld 大厅欢迎视频组件也支持世界播放
当前全部受支持的 ChaUIMod 客户端都可以让世界页面中的视频声音随距离变化。编辑视频组件时打开“距离衰减”,再设置:
| 属性 | 推荐值 | 说明 |
|---|---|---|
| 音量 | 1.0 | 视频在近距离时的最大组件音量。 |
| 距离衰减 | true | 只对真实打开的世界页面生效。 |
| 满音量距离 | 4.0 | 相机距离页面 4 格以内保持完整音量。 |
| 静音距离 | 32.0 | 从 4 格到 32 格平滑降低,32 格外完全静音。 |
距离取玩家相机到整张页面矩形的最近位置,不是到页面中心。大型影院屏幕因此不会出现站在屏幕边缘却突然变小声的问题。silentDistance 必须大于 fullVolumeDistance。
下面是一份可以直接保存为 plugins/ChaUI/pages/world_cinema.yml 的完整页面。把 video/cinema.mp4 放进客户端 .minecraft/resourcepacks/ChaUI/video/cinema.mp4 后,再按本教程前面的 openworld 或 addworld 方式打开:
id: world_cinema
version: 1
title: 世界影院
size:
width: 320
height: 180
coordinateMode: absolute
display:
mode: world
world:
# 页面中心所在的世界坐标,请改成影院屏幕的位置。
x: 0.0
y: 66.0
z: 0.0
scale: 0.01
yaw: follow_player
pitch: 0
vars: {}
papi:
refreshTicks: 20
values: {}
events: {}
methods: {}
elements:
- id: cinema_video
type: video
visible: true
enabled: true
pointerEvents: auto
scale: 1
rotation: 0
opacity: 1
z: 0
layout:
x: 0
y: 0
width: 320
height: 180
video:
path: video/cinema.mp4
autoplay: true
loop: true
startTimeMs: 0
playbackRate: 1.0
volume: 1.0
muted: false
# 关闭时无论距离多远都保持固定音量。
distanceAttenuation: true
fullVolumeDistance: 4.0
silentDistance: 32.0
fit: contain
events: {}玩家走出静音距离后,视频仍会继续播放,只把声音降到 0;再次靠近时无需重新加载或重新对齐进度。普通 screen、HUD 和编辑器预览不会应用这组距离设置。
常见问题
指令显示打开成功,但附近看不到页面
先核对页面保存的 X、Y、Z。世界坐标表示页面中心,不是玩家当前屏幕中心。也可以使用带坐标的打开方式,把页面临时放到自己附近。
页面太大或太小
调整“世界缩放”。0.01 表示一个 GUI 像素占 0.01 格;数值越大,世界中的页面越大。
世界缩放不是清晰度倍率。使用 window.width / window.height 的页面通常从 0.01 左右开始调整;填写 0.1 会让页面在世界中扩大十倍,近距离只能看到一部分。调整 GUI 缩放或窗口尺寸后,离屏纹理会自动按新的物理像素密度更新。
页面背对玩家
把世界朝向设置为 follow_player,或在带坐标的打开指令最后填写 follow_player。
页面被地形挡住
这是世界页面的正常表现。它会和世界方块发生正确的前后遮挡关系。移动页面位置,或换到能直接看到页面的位置。
按钮没有反应
让准星落在按钮范围内,并确认页面没有被方块挡住。还要检查页面是否已经保存,以及按钮是否启用。
下一步
完成第一个世界界面后,可以继续尝试:
- 用不同实例 ID 在大厅多个位置重复展示同一页面;
- 使用固定数字 yaw,让告示牌保持统一朝向;
- 加入图片、GIF、物品展示或实体渲染组件;
- 使用页面变量显示不同实例中的临时状态;
- 通过按钮事件打开普通页面,组成“世界入口 + 屏幕详情页”的交互流程。
猹件开发组