欢迎光临散文网 会员登陆 & 注册

【HZ/ICMod开发教程】2 - UI PART2

2021-08-22 01:46 作者:SugarBreeze_微风  | 我要投稿


注意:本教程仅为简单介绍UI的窗口,不会涉及详细的函数。如果想要了解更多请阅读官方文档。

在上期教程中我们简要介绍了ICMod的UI构成与基本控件,接下来将详细介绍控件用法以及如何组成一个“精美”的界面。

StandardWindow

在此纠正上一篇专栏的严重错误:StandartWindow在现在版本的InnerCore中已经弃用,使用StandardWindow替代。

你可以永远相信StandardWindow。 ---Prosto Sostavil

StandardWindow是一个由三部分组成的WindowGroup,分别为main, inventoryheader,对应关系如下图:

StandardWindow


在此使用工业的火力发电机界面作为示例:

火力发电机界面截图


这是一个简单的界面,但基本上包含了常用控件,让我们简要分析一下其代码:

 //源码使用TypeScript编写且分不同部分在多个文件中,为方便讲解取主要代码并使用JavaScript重写
 const GUI_SCALE = 3.2; //声明GUI_SCALE常量,以便统一模组内各界面
 new UI.StandardWindow({
     standard: {
         header: {text: {text: Translation.translate("Generator")}}, //此处使用Translate类函数以实现多语言,详见官方文档
         inventory: {standard: true},
         background: {standard: true}
     },
     drawing: [//两个scale元素对应的当其为空时的贴图
   {type: "bitmap", x: 530, y: 144, bitmap: "energy_bar_background", scale: GUI_SCALE},
   {type: "bitmap", x: 450, y: 150, bitmap: "fire_background", scale: GUI_SCALE},
  ],
     elements: {
   "energyScale": {type: "scale", x: 530 + GUI_SCALE * 4, y: 144, direction: 0, value: 0.5, bitmap: "energy_bar_scale", scale: GUI_SCALE}, //注意此处x的值比对应的bitmap加了GUI_SCALE*4,这是因为它的贴图两端各少了4个像素,以便完整显示进度
   "burningScale": {type: "scale", x: 450, y: 150, direction: 1, value: 0.5, bitmap: "fire_scale", scale: GUI_SCALE},
   "slotEnergy": {type: "slot", x: 441, y: 75},
   "slotFuel": {type: "slot", x: 441, y: 212},
   "textInfo1": {type: "text", x: 642, y: 142, width: 300, height: 30, text: "0/"},
   "textInfo2": {type: "text", x: 642, y: 172, width: 300, height: 30, text: "10000"}
  }
 });

可以看出在StandardWindow中使用的是绝对坐标,而且可与贴图像素对应,因此只需要耐心的慢慢调整就能够得到一个不错的界面。

与方块实体互动

此部分不是本教程的主要内容,因此将简要带过。

在IC中,注册方块实体的函数为TileEntity.registerPrototype(blockID: number, customPrototype: TileEntityPrototype): void,参数只有两个:方块ID方块实体原型

方块实体原型是一个JS对象,包含方块实体的数据和事件。要将创建的StandardWindow对象与方块实体绑定则需要在方块实体原型中设置getGuiScreen函数并返回界面对象。这样IC会自动为该界面对象创建相应的容器对象,你可以在方块实体原型的函数中使用this.container来获得容器对象并使用其提供的方法与界面交互。

更进一步

StandardWindow的可玩性远不止如此,你可以试着除去StandardWindow的默认控件,并从0开始自定义界面,或者在方块实体原型的getGuiScreen方法中编写逻辑以使在不同的情况下打开不同的界面。

示例为我去年3月份初次尝试UI时所写的会根据MC设置的UI档案切换StandardWindow的方块实体(PS:图二的界面标题有偏移Bug,在之后的版本中已被修复)。整个界面从开始构思到完成大概用了5天时间(大部分时间用在编写库上,但如今得益于WindowGroup,可以更快地完成该任务。

PockerUI
ClassicUI


Window

Window是最基本的窗口,相较于StandardWindow,Window更为灵活,适合用作弹窗或者HUD。

在创建一个Window对象的时候,可以像StandardWindow那样传入一个包含Drawing和Elements等的对象。但能够突出Window特色的是location参数,你可以自定义Window的大小,在屏幕上的位置,内边距和可滑动窗口大小(PS:Window内的unit为此Window宽度的千分之一)。

值得一提,内边距padding的会覆盖x|y|width|height的效果。

举个简单的空白窗口界面的例子:

 

//定义一些常量
 const GUI_SCALE = 5;
 const WIDTH = 1000;
 const HEIGHT = UI.getScreenHeight();
 //创建窗口
 let testWindow = new UI.Window({
     location: { //此处运算是为方便居中
         x: (WIDTH - 300) / 2,
         y: (HEIGHT - 225) / 2,
         width: 300,
         height: 225
     },
     drawing: [ //贴图是从拆原版包扒的XD
         {type: "background", color: android.graphics.Color.TRANSPARENT},
         {type: "frame", bitmap: "background_panel", width: 1000, height: 750, scale: GUI_SCALE}
     ],
     elements: {
         "closeButton": {type: "closeButton", x: 904, y: 26, bitmap: "close_button_default", bitmap2: "close_button_pressed", scale: GUI_SCALE}
     }
 });
 //一些常规设置
 testWindow.setCloseOnBackPressed(true);
 testWindow.setBlockingBackground(true);


效果图:

空白窗口


TabbedWindow

TabbedWindow可用于创建标签式窗口,如原版的玩家背包一样,具有多个可切换的标签页。

TabbedWindow和StandardWindow一样,都继承自WindowGroup。在创建TabbedWindow对象时,所传入的参数与Window相同,与之不同的是TabbedWindow多了一些函数。

使用new UI.TabbedWindow()创建一个空白的TabbedWindow,效果如下(PS:部分异形屏可能会被遮挡部分边界)

空白TabbedWindow


简单地说明一下这个窗口,左上角的关闭按钮是一个索引值为0的FakeTabPS:FakeTab指没有对应标签页的标签),标签页的上限为12个,即索引值的范围为0-11(左侧为0-5,右侧为6-11)。

要添加一个标签页可以使用setTab(index: number, tabOverlay: ElementSet, tabContent: WindowContent, isAlwaysSelected?: boolean): void函数,index即标签页的索引值,tabOverlay是标签的元素集(如关闭按钮),tabContent即为标签页展示的窗口内容,格式与之前介绍的基本无异。

因为setTab函数并不返回创建的Window对象,所以你需要用到getWindowForTab(index: number): Window来函数获取对应索引值的Window实例化对象,以完成对其的动态修改。

WindowGroup

WindowGroup是StandardWindow和TabbedWindow的父类,其方法基本上都可以在StandardWindow和TabbedWindow中使用。

WindowGroup诞生的目的是为了能够将复杂的界面模块化,以便提高代码的复用率并降低调试难度,使开发效率提高,最为典型的例子就是IC中的工作台界面(PS:此处不谈其交互逻辑,仅谈其界面)。

工作台界面


该界面由三部分组成,分别为Main·,SlotsGrid,对应下图中的青色,粉色和黄色部分:

工作台界面结构


阅读workbench.js中工作台界面部分的代码,可以看出该三部分都是先定义WindowContent的JSON描述,然后一一创建Window对象,并使用addWindowInstance(name: string, window: Window): void函数将Window对象添加到WindowGroup对象并声明其对应的名称ID。你也可以直接使用addWindow(name: string, content: WindowContent): Window函数向WindowGroup添加窗口。

至此,关于UI界面的内容就基本上介绍完毕,当然全部内容不止这些,你需要认真地查阅官方文档以及去学习他人的优秀作品。 另外,虽然本教程对于UI与容器的互动只是简单地带过,但此部分内容是相当重要的,应当注重学习(PS:谁让你们当时评论不提容器和方块实体呢XD)。



【HZ/ICMod开发教程】2 - UI PART2的评论 (共 条)

分享到微博请遵守国家法律