“重置游戏界面及制作自定义GUI”的版本间的差异
Kevintien86(讨论 | 贡献) |
Skyswordkill(讨论 | 贡献) |
||
(未显示2个用户的28个中间版本) | |||
第7行: | 第7行: | ||
GUI制作样例可在模组商店中搜索“自定义GUI和LUA脚本演示MOD”,并下载对应开源MOD样例 | GUI制作样例可在模组商店中搜索“自定义GUI和LUA脚本演示MOD”,并下载对应开源MOD样例 | ||
+ | |||
+ | <br /> | ||
+ | |||
+ | ===游戏主界面重置=== | ||
+ | 在剧本战役类的MOD中,可以通过MOD配置中的特殊字段来指定游戏背景图片或动画么,以及重置主界面的UI界面,当此类MOD被启用时,这些界面重置就会生效。 | ||
+ | |||
+ | 主界面重置配置方法为,修改MOD目录中的的Config文件夹下的default.json文件,添加下列字段可对指定的主界面元素进行重置: | ||
+ | |||
+ | *homepage_background:游戏背景图片或者UI动画预制体映射路径(如:Assets/BuildSource/Backgrounds/xxx.png) | ||
+ | *homepage_gui:自定义GUI界面信息,格式为:包名#组件名#脚本名称(例如:MyGUI#MyHomeScene#MyHomeSceneScript) | ||
+ | |||
+ | ===游戏UI包预载入=== | ||
+ | 当UI包过大,或者需要提前用到Mod包内的资源(例如使用UI包内的图片作为技能页背景),可以通过插件设置表,设置提前载入UI包。 | ||
+ | |||
+ | 先将需要预加载的UI资源放到 Mod文件夹\RES\UIRes 下,在插件设置表中,新增"类型"为"ADD","目标字段"为"gui_preload_package","目标值"为UI包名的信息后,当Mod重载时便会读取所有定义了的UI包。 | ||
===游戏中可进行自定义重置的UI界面及说明=== | ===游戏中可进行自定义重置的UI界面及说明=== | ||
− | + | 重置游戏中UI界面,可以通过在“插件设置表”设置以下目标字段字段来进行UI重置(注意:插件信息的类型字段需为“OVERRIDE”)。填写的格式信息为“包名#控件名#脚本名(可选,仅部分主要界面有效)”。 | |
注意:进行重置的UI仅以所有该目标字段值的对象中优先级最高的信息生效 | 注意:进行重置的UI仅以所有该目标字段值的对象中优先级最高的信息生效 | ||
第50行: | 第65行: | ||
|gui_bs_unit_infobox_e | |gui_bs_unit_infobox_e | ||
|用来替换战斗中敌方小兵单位信息面板的GUI信息(同上) | |用来替换战斗中敌方小兵单位信息面板的GUI信息(同上) | ||
+ | |- | ||
+ | |gui_bs_building_infobox_f | ||
+ | |用来替换战斗中我方建筑单位信息面板的GUI信息(同上) | ||
+ | |- | ||
+ | |gui_bs_building_infobox_e | ||
+ | |用来替换战斗中敌方建筑单位信息面板的GUI信息(同上) | ||
|- | |- | ||
|gui_bs_panel | |gui_bs_panel | ||
第61行: | 第82行: | ||
onUpdateGameInfo():游戏内信息更新时调用的接口方法 | onUpdateGameInfo():游戏内信息更新时调用的接口方法 | ||
|- | |- | ||
− | | | + | |gui_bs_panel |
− | | | + | |游戏战斗界面面板。需指定对应的LUA脚本,如:MyGUI#MyBsPanel#MyBsPanel |
+ | 该界面LUA脚本需实现的接口有: | ||
+ | |||
+ | <br /> | ||
+ | |- | ||
+ | |gui_trade_win | ||
+ | |(UI重载)用来替换交易界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_inventory_win | ||
+ | |(UI重载)用来替换背包界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_place_win | ||
+ | |(UI重载)用来替换地点界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_repair_win | ||
+ | |(UI重载)用来替换装备修理界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_party_win | ||
+ | |(UI重载)用来替换队伍界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_globaltalent_win | ||
+ | |(UI重载)用来替换天赋界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_information_win | ||
+ | |(UI重载)用来替换情报界面 格式: 包名#控件名#脚本名 | ||
+ | |- | ||
+ | |gui_tooltips | ||
+ | |(UI重载)用来替换提示文本框 格式: 包名#控件名#脚本名 | ||
+ | |} | ||
+ | |||
+ | ===游戏中UI界面补丁脚本=== | ||
+ | 有些界面脚本可能没有列在可重载UI中,或者有时只想修改某一个界面的某个功能,不想重载整个界面,并且想让修改尽可能适应版本更新和兼容其他Mod,这时候可以使用补丁脚本,对原脚本进行修改。 | ||
+ | |||
+ | 补丁脚本类型为"ADD",目标字段为 "lua_ui_patch#脚本路径",目标值为补丁脚本路径。 | ||
+ | |||
+ | 例:要修改地点界面,在面板上显示城主的等级 | ||
+ | 在Mod里添加插件设置表,新增一条字段: | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! KEY !! 类型_Type !! 目标字段_TargetKey !! 优先级_Priority !! 目标值_TargetValue | ||
|- | |- | ||
− | | | + | | game_place_ui_patch_1 || ADD || lua_ui_patch#gui/GamePlaceWin || 0 || Patch/GamePlaceWin1 |
− | | | ||
|} | |} | ||
− | === | + | 随后打开 Mod目录下的 Res/LuaScript/Patch/GamePlaceWin1.lua.txt |
− | <br /> | + | |
+ | 写入如下内容: | ||
+ | |||
+ | local oldGetPlaceDescInfoStr = GetPlaceDescInfoStr | ||
+ | |||
+ | function GetPlaceDescInfoStr(tagPlace) | ||
+ | local str = oldGetPlaceDescInfoStr(tagPlace) | ||
+ | local lord = tagPlace:GetLordRole() | ||
+ | local lordLevel = "无" | ||
+ | if lord ~= nil then | ||
+ | lordLevel = tostring(lord.roleLevel) | ||
+ | end | ||
+ | local newStr = "城主等级: " .. lordLevel .. "\n" .. str | ||
+ | return newStr | ||
+ | end | ||
+ | |||
+ | 这样就可以先缓存旧的GetPlaceDescInfoStr方法,然后编写新的GetPlaceDescInfoStr方法并注入自定义逻辑 | ||
+ | 在游戏运行过程中,被lua驱动的界面会先读取gui/GamePlaceWin.lua.txt脚本,随后再读取定义的补丁Patch/GamePlaceWin1.lua.txt脚本 | ||
+ | |||
+ | ====获取局部变量==== | ||
+ | 有些脚本使用了局部变量存储各类数值 | ||
+ | 这些局部变量在脚本执行完后会被以字典表的形式转储到<code>debugTools.localVariables</code>变量里 | ||
+ | |||
+ | 如要获取原脚本中的<code>local contentPane</code>,则可以使用<code>debugTools.localVariables["contentPane"]</code>的形式获取。 | ||
+ | |||
+ | ====另一种替代写法==== | ||
+ | 游戏中提供了lua的debugTools库,用于方便编写补丁。 | ||
+ | 上述补丁可以替换为如下写法 | ||
+ | |||
+ | GetPlaceDescInfoStr = debugTools:postfix(GetPlaceDescInfoStr, function(args, ret) | ||
+ | local str = ret | ||
+ | local tagPlace = args[1] | ||
+ | local lord = tagPlace:GetLordRole() | ||
+ | local lordLevel = "无" | ||
+ | if lord ~= nil then | ||
+ | lordLevel = tostring(lord.roleLevel) | ||
+ | end | ||
+ | local newStr = "城主等级: " .. lordLevel .. "\n" .. str | ||
+ | return true, newStr | ||
+ | end) | ||
+ | |||
+ | <code>debugTools</code>默认在界面脚本载入后会注入到当前的全局变量中<br> | ||
+ | 注:环境中的debugTools调用函数需要用冒号":"代替点号".",冒号调用函数是lua的语法糖,意思是将自身作为函数的第一个参数,如<code>debugTools:prefix(func, patch, priority)</code>等同于<code>debugTools.prefix(debugTools ,func, patch, priority)</code><br> | ||
+ | 通过debugTools里提供的方法,可以省略手动添加补丁的繁琐,同时多个mod都使用该方法时,兼容性更高。 | ||
+ | |||
+ | debugTools里的方法: | ||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! 名称 !! 参数 !! 说明 !! 示例 | ||
+ | |- | ||
+ | | debugTools:locals() || 无 || 获取调用环境中的所有本地变量,将局部变量存储在debugTools.localVariable中 || | ||
+ | |- | ||
+ | | debugTools:prefix(func, patch, priority) | ||
+ | || func: 原函数 | ||
+ | patch: 补丁函数,函数参数为原函数参数表,返回值分别为是否打断函数执行、打断后的返回值,若无返回值则默认为不打断原函数执行<br> | ||
+ | priority: 可选,补丁的优先级,默认为0,优先级越高越先执行 | ||
+ | || 对原函数进行前缀补丁,前缀补丁会在原函数执行前执行,并且可以通过对函数参数表进行修改,以替换函数参数 | ||
+ | || | ||
+ | onInit = debugTools.prefix(onInit, function(args) | ||
+ | print("run before onInit") | ||
+ | end | ||
+ | |- | ||
+ | |- | ||
+ | | debugTools:postfix(func, patch, priority) | ||
+ | || func: 原函数 | ||
+ | patch: 补丁函数,函数参数为原函数参数表、函数返回值,返回值分别为是否替换返回值、替换后的返回值,若无返回值则默认为不替换原函数返回值<br> | ||
+ | priority: 可选,补丁的优先级,默认为0,优先级越高越先执行 | ||
+ | || 对原函数进行后缀补丁,后缀补丁会在原函数执行后执行,并且可以通过对函数参数表和返回值进行修改,以替换函数参数和返回值 | ||
+ | || | ||
+ | onInit = debugTools:postfix(onInit, function(args, ret) | ||
+ | print("run after onInit") | ||
+ | end | ||
+ | |} | ||
+ | |||
+ | ===游戏中热键注册及重置说明=== | ||
+ | 通过插件设置表,可以注册自己的热键代码或者禁用游戏中已经存在的热键代码。注册方法如下: | ||
+ | |||
+ | 在插件设置表的“类型”字段中填入“HOTKEY”关键字,然后在“目标字段”中填入要注册的热键分组及热键代码信息,格式为:“分组ID/热键代码/[子分类ID(可选)]”,例如:battle/11000 | ||
+ | |||
+ | 目前只支持两个热键分组,分别为 "common"和"battle"分组。 | ||
+ | |||
+ | *common:通用快捷键设置分组 | ||
+ | *battle:战斗中的快捷键设置分组 | ||
+ | |||
+ | |||
+ | 热键代码为一个全局唯一的整形数字代码,注册后可以在对应的脚本接口中判断该按键代码。 | ||
+ | |||
+ | 子分类ID为每个分组下面的分类的识别代码,如果热键代码为游戏中已有的代码,则此字段无效,否则会优先查找指定的子分类并注册到此子分类下,如不存在或此字段为空则注册到"其他"分类中。 | ||
+ | |||
+ | 在插件设置表中的“目标值”字段中可填写热键的重置信息,如填写"disable"标识直接禁用该热键,否则按照以下格式进行填写: | ||
+ | |||
+ | 热键显示字段名称(可以填写为[@str=ID]的格式表示从文字表中查找指定ID的对应语言文本)#设置键位1的默认KeyCode#设置键位2的默认KeyCode#键位描述信息(可选,可用[@str=ID]标记) | ||
+ | |||
+ | 多个MOD插件中的热键注册可同时生效,但同一个目标字段对应的热键信息只有一个生效(由该目标字段的条目中优先级字段最高的条目生效) |
2023年8月9日 (三) 09:35的最新版本
目录
GUI制作工具及准备
在近期的版本中,我们使用了新的GUI框架系统以实现MOD制作者自己制作图形界面极其相关功能的需求。新的UI框架是基于 FairyGUI编辑器进行制作的,可以脱离UNITY进行UI设计及制作,并通过override方式导入到游戏里。
FairyGUI编辑器下载地址(部落与弯刀项目使用的编辑器版本为5.0.10,制作MOD时尽量保持一致防止代码兼容性问题):https://www.fairygui.com/
当自定义UI制作完成后,需要将相关的资源导出到自己的MOD文件夹中,并通过 RES或者ABS方式override到“Assets\BuildSource\UIRes\"映射路径下方可正常访问Package包以及它所包含的控件资源。
GUI制作样例可在模组商店中搜索“自定义GUI和LUA脚本演示MOD”,并下载对应开源MOD样例
游戏主界面重置
在剧本战役类的MOD中,可以通过MOD配置中的特殊字段来指定游戏背景图片或动画么,以及重置主界面的UI界面,当此类MOD被启用时,这些界面重置就会生效。
主界面重置配置方法为,修改MOD目录中的的Config文件夹下的default.json文件,添加下列字段可对指定的主界面元素进行重置:
- homepage_background:游戏背景图片或者UI动画预制体映射路径(如:Assets/BuildSource/Backgrounds/xxx.png)
- homepage_gui:自定义GUI界面信息,格式为:包名#组件名#脚本名称(例如:MyGUI#MyHomeScene#MyHomeSceneScript)
游戏UI包预载入
当UI包过大,或者需要提前用到Mod包内的资源(例如使用UI包内的图片作为技能页背景),可以通过插件设置表,设置提前载入UI包。
先将需要预加载的UI资源放到 Mod文件夹\RES\UIRes 下,在插件设置表中,新增"类型"为"ADD","目标字段"为"gui_preload_package","目标值"为UI包名的信息后,当Mod重载时便会读取所有定义了的UI包。
游戏中可进行自定义重置的UI界面及说明
重置游戏中UI界面,可以通过在“插件设置表”设置以下目标字段字段来进行UI重置(注意:插件信息的类型字段需为“OVERRIDE”)。填写的格式信息为“包名#控件名#脚本名(可选,仅部分主要界面有效)”。
注意:进行重置的UI仅以所有该目标字段值的对象中优先级最高的信息生效
目前支持的可重置界面对象有:
插件表目标字段 | 说明 |
---|---|
gui_sandbox_panel | 游戏大地图主界面面板。需指定对应的LUA脚本,如:MyGUI#MySandboxPanel#MySandboxPanel
该界面LUA脚本需实现的接口有: initPanel(_view, _controllerScript) :初始化控件对象接口 _view为界面对应的GComponent对象 _controllerScript为面板当前的c#控制代码对象 onHotkeyPressed(_keycode):按下已注册热键接口 _keycode为按下热键的整形代码(注册热键代码见“游戏中热键注册及重置说明”)。当此热键被成功响应后返回true,否则返回false onUpdateGameInfo():游戏内信息更新时调用的接口方法
|
gui_team_infobox | 用来替换大地图上队伍信息面板的GUI信息 (只需要填写"包名#控件名",暂不支持脚本改写,需按照样例中的控件对象来命名关键对象) |
gui_place_infobox | 用来替换大地图上地点信息面板的GUI信息 (同上) |
gui_building_infobox | 用来替换大地图上建筑信息面板的GUI信息 (同上) |
gui_bs_hero_infobox_f | 用来替换战斗中我方英雄信息面板的GUI信息(同上) |
gui_bs_hero_infobox_e | 用来替换战斗中敌方英雄信息面板的GUI信息(同上) |
gui_bs_unit_infobox_f | 用来替换战斗中我方小兵单位信息面板的GUI信息(同上) |
gui_bs_unit_infobox_e | 用来替换战斗中敌方小兵单位信息面板的GUI信息(同上) |
gui_bs_building_infobox_f | 用来替换战斗中我方建筑单位信息面板的GUI信息(同上) |
gui_bs_building_infobox_e | 用来替换战斗中敌方建筑单位信息面板的GUI信息(同上) |
gui_bs_panel | 战斗中主界面面板。需指定对应的LUA脚本,如:MyGUI#MyBsPanel#MyBsPanel
该界面LUA脚本需实现的接口有: initPanel(_view, _controllerScript) :初始化控件对象接口 _view为界面对应的GComponent对象 _controllerScript为面板当前的c#控制代码对象 onHotkeyPressed(_keycode):按下已注册热键接口 _keycode为按下热键的整形代码(参考 gui_sandbox_panel) onUpdateGameInfo():游戏内信息更新时调用的接口方法 |
gui_bs_panel | 游戏战斗界面面板。需指定对应的LUA脚本,如:MyGUI#MyBsPanel#MyBsPanel
该界面LUA脚本需实现的接口有:
|
gui_trade_win | (UI重载)用来替换交易界面 格式: 包名#控件名#脚本名 |
gui_inventory_win | (UI重载)用来替换背包界面 格式: 包名#控件名#脚本名 |
gui_place_win | (UI重载)用来替换地点界面 格式: 包名#控件名#脚本名 |
gui_repair_win | (UI重载)用来替换装备修理界面 格式: 包名#控件名#脚本名 |
gui_party_win | (UI重载)用来替换队伍界面 格式: 包名#控件名#脚本名 |
gui_globaltalent_win | (UI重载)用来替换天赋界面 格式: 包名#控件名#脚本名 |
gui_information_win | (UI重载)用来替换情报界面 格式: 包名#控件名#脚本名 |
gui_tooltips | (UI重载)用来替换提示文本框 格式: 包名#控件名#脚本名 |
游戏中UI界面补丁脚本
有些界面脚本可能没有列在可重载UI中,或者有时只想修改某一个界面的某个功能,不想重载整个界面,并且想让修改尽可能适应版本更新和兼容其他Mod,这时候可以使用补丁脚本,对原脚本进行修改。
补丁脚本类型为"ADD",目标字段为 "lua_ui_patch#脚本路径",目标值为补丁脚本路径。
例:要修改地点界面,在面板上显示城主的等级 在Mod里添加插件设置表,新增一条字段:
KEY | 类型_Type | 目标字段_TargetKey | 优先级_Priority | 目标值_TargetValue |
---|---|---|---|---|
game_place_ui_patch_1 | ADD | lua_ui_patch#gui/GamePlaceWin | 0 | Patch/GamePlaceWin1 |
随后打开 Mod目录下的 Res/LuaScript/Patch/GamePlaceWin1.lua.txt
写入如下内容:
local oldGetPlaceDescInfoStr = GetPlaceDescInfoStr function GetPlaceDescInfoStr(tagPlace) local str = oldGetPlaceDescInfoStr(tagPlace) local lord = tagPlace:GetLordRole() local lordLevel = "无" if lord ~= nil then lordLevel = tostring(lord.roleLevel) end local newStr = "城主等级: " .. lordLevel .. "\n" .. str return newStr end
这样就可以先缓存旧的GetPlaceDescInfoStr方法,然后编写新的GetPlaceDescInfoStr方法并注入自定义逻辑 在游戏运行过程中,被lua驱动的界面会先读取gui/GamePlaceWin.lua.txt脚本,随后再读取定义的补丁Patch/GamePlaceWin1.lua.txt脚本
获取局部变量
有些脚本使用了局部变量存储各类数值
这些局部变量在脚本执行完后会被以字典表的形式转储到debugTools.localVariables
变量里
如要获取原脚本中的local contentPane
,则可以使用debugTools.localVariables["contentPane"]
的形式获取。
另一种替代写法
游戏中提供了lua的debugTools库,用于方便编写补丁。 上述补丁可以替换为如下写法
GetPlaceDescInfoStr = debugTools:postfix(GetPlaceDescInfoStr, function(args, ret) local str = ret local tagPlace = args[1] local lord = tagPlace:GetLordRole() local lordLevel = "无" if lord ~= nil then lordLevel = tostring(lord.roleLevel) end local newStr = "城主等级: " .. lordLevel .. "\n" .. str return true, newStr end)
debugTools
默认在界面脚本载入后会注入到当前的全局变量中
注:环境中的debugTools调用函数需要用冒号":"代替点号".",冒号调用函数是lua的语法糖,意思是将自身作为函数的第一个参数,如debugTools:prefix(func, patch, priority)
等同于debugTools.prefix(debugTools ,func, patch, priority)
通过debugTools里提供的方法,可以省略手动添加补丁的繁琐,同时多个mod都使用该方法时,兼容性更高。
debugTools里的方法:
名称 | 参数 | 说明 | 示例 |
---|---|---|---|
debugTools:locals() | 无 | 获取调用环境中的所有本地变量,将局部变量存储在debugTools.localVariable中 | |
debugTools:prefix(func, patch, priority) | func: 原函数
patch: 补丁函数,函数参数为原函数参数表,返回值分别为是否打断函数执行、打断后的返回值,若无返回值则默认为不打断原函数执行 |
对原函数进行前缀补丁,前缀补丁会在原函数执行前执行,并且可以通过对函数参数表进行修改,以替换函数参数 |
onInit = debugTools.prefix(onInit, function(args) print("run before onInit") end |
debugTools:postfix(func, patch, priority) | func: 原函数
patch: 补丁函数,函数参数为原函数参数表、函数返回值,返回值分别为是否替换返回值、替换后的返回值,若无返回值则默认为不替换原函数返回值 |
对原函数进行后缀补丁,后缀补丁会在原函数执行后执行,并且可以通过对函数参数表和返回值进行修改,以替换函数参数和返回值 |
onInit = debugTools:postfix(onInit, function(args, ret) print("run after onInit") end |
游戏中热键注册及重置说明
通过插件设置表,可以注册自己的热键代码或者禁用游戏中已经存在的热键代码。注册方法如下:
在插件设置表的“类型”字段中填入“HOTKEY”关键字,然后在“目标字段”中填入要注册的热键分组及热键代码信息,格式为:“分组ID/热键代码/[子分类ID(可选)]”,例如:battle/11000
目前只支持两个热键分组,分别为 "common"和"battle"分组。
- common:通用快捷键设置分组
- battle:战斗中的快捷键设置分组
热键代码为一个全局唯一的整形数字代码,注册后可以在对应的脚本接口中判断该按键代码。
子分类ID为每个分组下面的分类的识别代码,如果热键代码为游戏中已有的代码,则此字段无效,否则会优先查找指定的子分类并注册到此子分类下,如不存在或此字段为空则注册到"其他"分类中。
在插件设置表中的“目标值”字段中可填写热键的重置信息,如填写"disable"标识直接禁用该热键,否则按照以下格式进行填写:
热键显示字段名称(可以填写为[@str=ID]的格式表示从文字表中查找指定ID的对应语言文本)#设置键位1的默认KeyCode#设置键位2的默认KeyCode#键位描述信息(可选,可用[@str=ID]标记)
多个MOD插件中的热键注册可同时生效,但同一个目标字段对应的热键信息只有一个生效(由该目标字段的条目中优先级字段最高的条目生效)