From df9b1e4620c36ef8821c8ea20925f687fe635f05 Mon Sep 17 00:00:00 2001 From: kwiilh Date: Mon, 17 Nov 2025 15:44:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E5=AE=98=E7=BD=91=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../16-美术/9-特效/21-原版特效属性详细说明.md | 2 +- mcguide/18-界面与交互/30-UI说明文档.md | 420 ++---------------- 2 files changed, 37 insertions(+), 385 deletions(-) diff --git a/mcguide/16-美术/9-特效/21-原版特效属性详细说明.md b/mcguide/16-美术/9-特效/21-原版特效属性详细说明.md index 03c15e8..46cac1f 100644 --- a/mcguide/16-美术/9-特效/21-原版特效属性详细说明.md +++ b/mcguide/16-美术/9-特效/21-原版特效属性详细说明.md @@ -378,7 +378,7 @@ mc里的特效实例有两种承载方式,一种是在世界空间单独存在 动画是否循环播放,如果设置为false,则会在每个发射器的生命周期开始时重新播放动画。 - `size` 设置发射出来的骨骼模型的大小,支持molang表达式。 - - `ignore_lighting`(3.6beta版内容) + - `ignore_lighting` 设置粒子模型是否受到环境光照影响,与实体json中ignore_lighting作用相同。该值设置为true时,粒子模型不受环境光影响,始终保持默认亮度。 ```json diff --git a/mcguide/18-界面与交互/30-UI说明文档.md b/mcguide/18-界面与交互/30-UI说明文档.md index 1cd4558..c1bc7cd 100644 --- a/mcguide/18-界面与交互/30-UI说明文档.md +++ b/mcguide/18-界面与交互/30-UI说明文档.md @@ -1188,12 +1188,6 @@ JSON如下: "size": [100, 100], "offset": "@UIDemo.animation_in", "texture": "textures/netease/common/image/default", - "is_new_nine_slice": false, - "nine_slice_buttom" : 0, - "nine_slice_left" : 0, - "nine_slice_right" : 0, - "nine_slice_top" : 0, - "nineslice_size" : [0, 0, 0, 0], "type": "image" }, "animation_in": { @@ -1246,104 +1240,6 @@ button是按钮控件,按钮有四种状态,分别为default/hover/pressed/l 下面是一个使用了三种状态的按钮,我们继承common.button里的属性,无需自己再定义default_control等属性。 ```json -{ - "button0@common.button" : { - "$default_texture" : "textures/netease/common/button/default", - "$hover_texture" : "textures/netease/common/button/hover", - "$is_new_nine_slice" : false, - "$label_color" : [ 1, 1, 1 ], - "$label_font_scale_factor" : 1.0, - "$label_font_size" : "large", - "$label_layer" : 3, - "$label_offset" : [ 0, 0 ], - "$label_text" : "Button", - "$nine_slice_buttom" : 0, - "$nine_slice_left" : 0, - "$nine_slice_right" : 0, - "$nine_slice_top" : 0, - "$nineslice_size" : [ 0, 0, 0, 0 ], - "$pressed_button_name" : "%fpsBattle.click", - "$pressed_texture" : "textures/netease/common/button/pressed", - "$texture_layer" : 2, - "anchor_from" : "center", - "anchor_to" : "center", - "is_handle_button_move_event" : true, - "button_mappings" : [], - "bindings" : [ - { - "binding_collection_name" : "", - "binding_condition" : "always_when_visible", - "binding_type" : "collection_details" - } - ], - "controls" : [ - { - "default@fpsBattle.default" : {} - }, - { - "hover@fpsBattle.hover" : {} - }, - { - "pressed@fpsBattle.pressed" : {} - }, - { - "button_label@fpsBattle.button_label" : {} - } - ], - "default_control" : "default", - "hover_control" : "hover", - "layer" : 3, - "offset" : [ 0, 0 ], - "pressed_control" : "pressed", - "size" : [ 100, 50 ], - "type" : "button", - "visible" : true - }, - "button_label" : { - "color" : "$label_color", - "font_scale_factor" : "$label_font_scale_factor", - "font_size" : "$label_font_size", - "font_type" : "smooth", - "layer" : "$label_layer", - "max_size" : [ "100%", "100%" ], - "offset" : [ 0, 0 ], - "shadow" : false, - "text" : "$label_text", - "text_alignment" : "center", - "type" : "label" - }, - "default" : { - "is_new_nine_slice" : "$is_new_nine_slice", - "layer" : "$texture_layer", - "nine_slice_buttom" : "$nine_slice_buttom", - "nine_slice_left" : "$nine_slice_left", - "nine_slice_right" : "$nine_slice_right", - "nine_slice_top" : "$nine_slice_top", - "texture" : "$default_texture", - "type" : "image" - }, - "hover" : { - "is_new_nine_slice" : "$is_new_nine_slice", - "layer" : "$texture_layer", - "nine_slice_buttom" : "$nine_slice_buttom", - "nine_slice_left" : "$nine_slice_left", - "nine_slice_right" : "$nine_slice_right", - "nine_slice_top" : "$nine_slice_top", - "texture" : "$hover_texture", - "type" : "image" - }, - "pressed" : { - "is_new_nine_slice" : "$is_new_nine_slice", - "layer" : "$texture_layer", - "nine_slice_buttom" : "$nine_slice_buttom", - "nine_slice_left" : "$nine_slice_left", - "nine_slice_right" : "$nine_slice_right", - "nine_slice_top" : "$nine_slice_top", - "texture" : "$pressed_texture", - "type" : "image" - } -} -``` "button0@common.button": { "size": [100, 50], "button_mappings": [], //和$pressed_button_name只能二选一 @@ -2372,7 +2268,7 @@ hover事件的触发本质上是与鼠标悬浮相关,在PC模式中,当鼠 UI编辑器暂时不支持编辑 -### MiniMap +### mini\_map 该控件可以在UI上画小地图,需要继承mini_map命名空间下的mini_map_wrapper控件。 @@ -2423,290 +2319,19 @@ UI编辑器暂时不支持编辑 | $face_icon_size | 脸部icon的大小,默认为[4,4] | | $face_icon_bg_color | 标记icon底部背景颜色,默认为白色 | | $highest_y | 绘制的高度最大值,默认当前区块的最大值,当该值为-1时,表示最大高度值为玩家当前位置所在的高度 | -| enable_scissor_test | 超出父控件区域后是否裁剪,默认为false, [enable_scissor_test](https://wiki.bedrock.dev/json-ui/json-ui-documentation.html)| - -### **颜色渐变控件(gradientRenderer)** - -该控件可以用于在ui上绘制渐变颜色 - -```json -{ - "gradient": { - "color1": [1, 0, 1, 1], - "color2": [0, 0, 1, 1], - "gradient_direction": "vertical", - "renderer": "gradient_renderer", - "type": "custom" - } -} -``` - -| 变量 | 解释 | -| ------------------ | -------------------------------------- | -| color1 | 渐变起始颜色的RGBA | -| color2 | 渐变结束颜色的RGBA | -| gradient_direction | 渐变方向,可选"vertical"或"horizontal" | -| renderer | 需要指定为gradient_renderer | -| type | 需要指定为custom | - -图片描述 - -下图为UI编辑器中颜色渐变控件的属性编辑面板 - -图片描述 - -| 变量 | 解释 | -| ------------ | ------------------------------------------------------ | -| 渐变起始颜色 | 对应color1字段,支持调整不透明度(Alpha通道) | -| 渐变结束颜色 | 对应color2字段,支持调整不透明度(Alpha通道) | -| 渐变方向 | 对应gradient_direction字段,可选“垂直排布”或“水平排布” | -### 继承控件 - -继承控件允许开发者选择并继承目标控件,继承成功后该控件拥有目标控件的所有属性,并可以重写其中任何一个属性的数据。 - -#### 继承写法简述 - -在界面json文件所有的编写技巧中,最为好用和灵活的功能当属继承写法。当界面中有一个需求,需要将若干个相同的控件按序排列,除了可以通过复制粘贴出若干个控件副本外,继承模板控件并只修改我们所需要修改的属性,其他的属性依然沿用模板控件的数据才是最便捷,也是最漂亮的写法。下面我们从一个简单的例子入手熟悉继承的写法,从例子中我们可以快速熟悉继承技巧。 - -```json -{ - "main" : { - "absorbs_input" : true, - "always_accepts_input" : false, - "controls" : [ - { - "label0@myInherit.label0" : {} - }, - { - "inheritor0@myInherit.label0" : { - "offset" : [ 10.0, 0.0 ] - } - }, - { - "inheritor1@myInherit.label0" : { - "offset" : [ 20.0, 0.0 ] - } - } - ], - "force_render_below" : false, - "is_showing_menu" : true, - "render_game_behind" : true, - "render_only_when_topmost" : true, - "should_steal_mouse" : false, - "type" : "screen" - }, - "label0" : { - "anchor_from" : "center", - "anchor_to" : "center", - "color" : [ 1, 1, 1 ], - "font_scale_factor" : 1.0, - "font_size" : "normal", - "font_type" : "smooth", - "layer" : 0, - "offset" : [ 0, 0 ], - "shadow" : false, - "size" : [ 100, 100 ], - "text" : "Hello World!", - "text_alignment" : "center", - "type" : "label", - "visible" : true - }, - "namespace" : "myInherit" -} -``` - -该段json描述了在main画布中创建了一个文本控件label0,并使继承控件inherit0和inherit1均继承了label0控件,并重写了offset属性,在场景中就得到了三个文本控件,这三个文本控件除了在场景中的位置因为重写而不同外,其他的属性一模一样。但是要注意的是,可以被继承的控件必须写在json文件的最外层,和main处在同一层级,即一个命名空间下有且仅有一个该名称的控件,满足该条件的控件才可以被继承。 -#### UI编辑器中的继承 - -新版的UI编辑器对继承提供了更可视化的方法,请参考[继承和自定义控件](./13-继承和自定义控件.md)。 ## Python编写说明 -### 必要的属性 - -```python -import mod.client.extraClientApi as clientApi -ViewBinder = clientApi.GetViewBinderCls() -ViewRequest = clientApi.GetViewViewRequestCls() -ScreenNode = clientApi.GetScreenNodeCls() -``` -| 变量 | 解释 | -| :------------: | :----------------------------------- | -| extraClientApi | 我们开发的Client端Api接口文件 | -| ViewBinder | 用于绑定回调函数的类型和响应的方法 | -| ViewRequest | 用于返回绑定函数的返回值 | -| ScreenNode | UI的基类,用于继承基类的方法和UI管理 | - -### UI界面初始化 - -```python -import mod.client.extraClientApi as clientApi - -ScreenNode = clientApi.GetScreenNodeCls() - -class TestScreen(ScreenNode): - def __init__(self, namespace, name, param): - ScreenNode.__init__(self, namespace, name, param) -``` - -ScreenNode是我们的UI节点基类,必须继承。 - -```python -# Bind Type -class ViewBinder(object): - ButtonFilter = 0x10000000 - BF_ButtonClickUp = 0 | ButtonFilter - BF_ButtonClickDown = 1 | ButtonFilter - BF_ButtonClick = 2 | ButtonFilter - BF_ButtonClickCancel = 3 - BF_InteractButtonClick = 4 - BindFilter = 0x01000000 - BF_BindBool = 5 | BindFilter - BF_BindInt = 6 | BindFilter - BF_BindFloat = 7 | BindFilter - BF_BindString = 8 | BindFilter - BF_BindGridSize = 9 | BindFilter - BF_BindColor = 10 | BindFilter - EditFilter = 0x00100000 - BF_EditChanged = 11 | EditFilter - BF_EditFinished = 12 | EditFilter - ToggleFilter = 0x00010000 - BF_ToggleChanged = 13 | ToggleFilter - -# Return Type -class ViewRequest(object): - Nothing = 0 - Refresh = 1 << 0 - PointerHeldEventsRequest = 1 << 1 - PointerHeldEventsCancel = 1 << 2 - Exit = 1 << 3 -``` -### UI绑定和返回 - -UI的绑定分为binding单个绑定和binding_collection集合绑定,适合集合容器。 - -| 绑定类型 | 绑定方式 | 解释 | -| :--------------------- | :---------------------------: | :------------------------------------- | -| BF_ButtonClickUp | binding | 绑定按钮的Up事件 | -| BF_ButtonClickDown | binding | 绑定按钮的Down事件 | -| BF_ButtonClick | binding | 同时绑定Up和Down事件 | -| BF_ButtonClickCancel | binding | 绑定按钮的Cancel事件(按钮down其他up) | -| BF_InteractButtonClick | binding | 绑定游戏原生的按钮点击事件 | -| BF_BindBool | binding \| binding_collection | 绑定Bool变量 | -| BF_BindInt | binding \| binding_collection | 绑定Int变量 | -| BF_BindFloat | binding \| binding_collection | 绑定Float变量 | -| BF_BindString | binding \| binding_collection | 绑定String变量 | -| BF_BindGridSize | binding | 绑定GridSize变量 | -| BF_BindColor | binding \| binding_collection | 绑定颜色变量 | -| BF_EditChanged | binding | 绑定输入框输入改变事件 | -| BF_EditFinished | binding | 绑定输入框输入完成事件 | -| BF_ToggleChanged | binding | 开关状态改变事件 | - -**binding(bind_flag, binding_name = None)** - -bind_flag为上文中绑定类型,binding_name为绑定名称。 - -binding_name为脚本绑定变量,binding_name_override为引擎变量,json格式如下 - -```json -{ - "bindings": [ - { - "binding_condition" : "always", - "binding_name" : "#scoreboard_grid.item_count", - "binding_name_override" : "#StackGridItemsCount" - } - ] -} -``` -对应的Python代码如下 -```python -import mod.client.extraClientApi as clientApi - -ViewBinder = clientApi.GetViewBinderCls() - -@ViewBinder.binding(ViewBinder.BF_BindInt, "#scoreboard_grid.item_count") -def OnStarkGridResize(self): - return len(self.scoreBoardList) -``` - -**binding_collection(bind_flag, collection_name, binding_name = None)** - -bind_flag为上文中的绑定类型,collection_name为集合名称,binding_name为绑定的变量名称。 - -集合的json如下: - -```json -{ - "collection_name" : "scoreboard_stackgrid" -} -``` - -在集合的子控件中,binding_collection_name为集合名,binding_condition为绑定条件,binding_name为绑定名称,binding_type为collection绑定,property_bag设置他的初始值,text为它的绑定值。 - -```json -{ - "label_score_board" : { - "bindings" : [ - { - "binding_collection_name" : "scoreboard_stackgrid", - "binding_condition" : "always", - "binding_name" : "#label_score_board.text", - "binding_type" : "collection" - } - ], - "offset" : [ "0%+0 px", "0%+0px" ], - "property_bag" : { - "#label_score_board.text" : "666666666666" - }, - "text" : "#label_score_board.text", - "text_alignment" : "left", - "type" : "label", - "visible" : true - } -} -``` - -对应的Python代码如下,其中index表示在集合中的哪一元素。 - -```python -import mod.client.extraClientApi as clientApi - -ViewBinder = clientApi.GetViewBinderCls() - -@ViewBinder.binding_collection(ViewBinder.BF_BindString, "scoreboard_stackgrid", "#label_score_board.text") -def OnRefreshScoreBoardLabel(self, index): - return self.scoreBoardList[index] if len(self.scoreBoardList) > index else "" -``` -## 接口调用说明 - -### 参数命名说明 - -@Mod.Binding(name = myModName, version = myModVersion) - -| 参数 | 类型 | 解释 | -| :----------: | :--: | :------ | -| myModName | str | Mod名称 | -| myModVersion | str | Mod版本 | - -假设设置Mod名称为"myModName",示例: -```python -from mod.common.mod import Mod -@Mod.Binding(name = "myModName", version = "0.1") -class MyModClass(object): - def __init__(self): - pass -``` - -### 界面创建流程及生命周期 +### 界面创建流程 界面在 UiInitFinished 事件发送之后就可以开始创建 -创建UI的第一步是UI的注册,通过调用 RegisterUI 接口,将想开启UI的相关数据进行注册。同一UI只需要注册一次即可 +创建UI的第一步是UI的注册,通过调用 RegisterUI 接口,传入UI类路径和JSON控件路径注册UI,同一UI只需要注册一次即可。 注册完成之后就可以在需要的时候实例化UI,可使用的接口有 CreateUI PushScreen 两种。使用 CreateUI 生成的界面都生成在操作UI下,不同的生成参数UI层级不同,而使用 PushScreen 生成的界面以堆栈管理的方式生成,该界面生成时上一个 PushScreen 生成的界面就会被隐藏。值得注意的是,MC原生界面(比如暂停界面,背包界面等)也是类似 PushScreen 的方式加载进来,并以堆栈管理。 在UI创建完成之后,可以调用 GetUI 接口拿到UI对应的ScreenNode实例。 + 如果想获取MC原生界面的实例,则需要监听原生界面Push进来的事件 PushScreenEvent ,然后在事件回调中调用接口 GetTopPushedUI 。 每个ScreenNode都有生命周期函数,生命周期函数会被自动在以下情况下调用,重写函数可以完成一些逻辑。 @@ -2716,9 +2341,38 @@ class MyModClass(object): | Create | UI创建成功时调用 | | OnActive | UI重新回到栈顶时调用 | | OnDeactive | 栈顶UI有其他UI入栈时调用 | +| Update | 客户端每帧调用,1秒有30帧 | | Destroy | UI销毁时调用 | 最后,当UI需要销毁时,可以调用ScreenNode实例的 SetRemove 接口,此外使用 PushScreen 接口创建的界面还可以使用 PopScreen 接口进行销毁。 + +### 编写UI类 + +UI类用于编写界面逻辑,需要在 RegisterUI 时传入UI类的路径。一个客户端类可以对应多个UI类。UI类一般包含以下内容: + +```python +import client.extraClientApi as clientApi +ScreenNode = clientApi.GetScreenNodeCls() +ViewBinder = clientApi.GetViewBinderCls() +ViewRequest = clientApi.GetViewViewRequestCls() +Client = clientApi.GetSystem('xxxxMod', 'xxxxClientSystem') +CF = clientApi.GetEngineCompFactory() +PID = clientApi.GetLocalPlayerId() + +class uiName(ScreenNode): + def __init__(self, namespace, name, param): + ScreenNode.__init__(self, namespace, name, param) + + def Create(self): + pass + + def Destroy(self): + pass + + def Update(self): + pass +``` + | 变量 | 解释 | | :------------: | :----------------------------------- | | extraClientApi | 我们开发的Client端Api接口文件 | @@ -2858,11 +2512,9 @@ button_data: { 在字符串中嵌入`link_data`样式会被解析成超链接,外观和普通文本无异但可以被点击,link_data为特殊化数据,开发者可以在其中添加符合JSON格式的自定义数据,在点击富文本中对应超链接时会将link_data通过回调函数整个返回,以下属性为必须属性,text表示显示文本,format_code表示该段显示文本的样式代码,注意,基岩版的文本控件不支持下划线和删除线。 ```json -{ - "link_data":{ - "text":"末影人", - "format_code":"§2" - } +link_data: { + "text": "末影人", + "format_code": "§2" } ```