整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

如何快速高效地完成UI界面设计?这五种主要的解决方案

如何快速高效地完成UI界面设计?这五种主要的解决方案你应该知道

者按 在游戏制作时,UI界面设计是非常重要的工作,不仅仅是考虑排版布局、美术风格,还要考虑到玩家的交互行为。另外,采取哪种实现方案也是需要慎重考虑的,一个好方案让我们在保质保量的前提下,能快速高效地完成。笔者将为大家介绍业界常用的UI解决方案,并对它们做简单地分析对比。同时,也欢迎大家留言,分享你在UI设计时所积累的经验,或是遇到的困难,咱们共同成长进步。

作者:W


笔者自14年毕业参加工作以来,一直使用Unity引擎来开发各种项目,如儿童启蒙教育类绘本、大型3D网络海战、三消、视频VR以及NBA体育竞技等,大部分工作内容是与UI界面相关。使用过的UI系统插件包括Unity原始的GUI、第3方插件NGUI、Unity进阶版的UGUI以及第3方的UI编辑器FairyGUI。另外,经网上了解还有EZ GUI、IGUI等第3方插件,以及Unity近推出的高阶版UIToolkit。这些偏冷门的或者新出炉的,笔者暂没在公司项目中使用过。你知道的,公司项目对稳定性有较高的要求,不会一味地追求新技术。读者不用惊讶,有公司还在使用Unity 4.x或者5.x旧版本的呢,哈哈!

经过前面介绍,这么多种实现方案,我们在实际项目中应该如何做选择呢?有木有最佳方案?通吃的那种?答案是否定的。每种方案都有其适用性,需要结合项目本身以及开发者自身情况综合来考量。那在选择方案时,有木有一些具体的参考点呢?这个是有的,笔者归结为以下2点:

1)可视化程度:Unity原始的UI系统,需要在运行时才能显示,这给我们搭建UI界面时带来很多不便。正因为此,许多像NGUI一样的高度可视化的插件陆续诞生。搭建UI界面时,只需将对应组件拖入场景即可显示和调整,达到所见即所得的目的。另外,像是否支持图文混排、虚拟列表等组件以及对策划美术是否友好等问题,也都可以归结为插件的可视化程度高不高的体现。

2)性能:DrawCall,每次CPU准备数据并通知GPU的过程。这个操作是比较好性能的,原则上我们是希望它越少越好的。影响它的因素:一方面表现为UI资源的管理方式,这主要与程序猿技术能力有关,知道啥时候加载,又啥时候卸载,什么类型资源共享,什么类型资源进行九宫格。另一方面表现为与UI系统本身的渲染原理相关,这是UI方案的“硬伤”,关于UI方案的硬伤,对于熟知该UI渲染原理的程序猿来说,他知道该怎么去做,一定程度“规避”产生太多DrawCall。嘻嘻,这很考验咱程序猿功底咯!如果UI方案本身这方面就做的很好,那岂不是更好,哈哈。


限于篇幅,我不能对这些UI方案深入展开,希望简短的介绍能讲清楚它们各自特点。至于具体怎么使用,我会附上官网或学习地址,那里通常配有技术文档、教程帮助上手。

2.1 Unity原始GUI

因性能和可视化方面都不足,自打好用的如NGUI等第3方插件问世后,Unity的原始GUI系统,基本不会用于游戏运行模式时的UI设计中;一般只是在编辑器工具扩展时使用。但现如今Unity又推出新的UIElement框架,可用于编辑器工具的扩展,原生GUI系统会越来越失宠,究其最终原因就是性能差且不好用。目前来看,原始GUI在编辑器工具扩展领域的地位应该不太可能迅速被UIElement取代,因为扩展工具时,原始GUI还是可以胜任的,且很多开发者应该已经习惯用它来编写工具和扩展。其实,程序猿也是有情怀的,哈哈!

2.2 NGUI

资源地址:https://assetstore.unity.com/packages/tools/gui/ngui-next-gen-ui-2413#description

其特点如下:

1) 图集:需要自己规划好后,手动打开图集。

2) 渲染原理:先根据Panel的Depth排序,Panel面板内部再根据Depth排序。将相同材质的Widget进行Mesh合并。

3) 支持图文混排。

4) 支持循环列表组件。

2.3 Unity进阶版UGUI

学习地址:http://c.biancheng.net/view/2712.html

UGUI是在NGUI之后Unity官方推出的,一定程度上借鉴了NGUI的设计理念,在某些方面做了改进优化,如自适应、图集等。其特点如下:

1)图集:图集概念不重,会自动打包成图集。要注意的是,放在Resources文件夹下的贴图不会被打入图集;

2)渲染原理:根据Hierarchy的顺序来排序,越下面渲染在越顶层。Canvas与NGUI的UIPanel类似,每个Canvas将优化合并为1个Mesh或多个SubMesh;

3)不支持图文混排,需要自己实现;

4)不支持循环列表组件,需要自己实现;

5)有锚点,方便屏幕自适应。

2.4 FairyGUI

官网地址:https://www.fairygui.com/download

它是独立的UI编辑器,且对美术、策划都友好。其特点如下:

1)目前主流的游戏开发引擎都支持;

2)渲染原理:没有采取Mesh合并的策略,而是基于类似于Unity的Dynamic Batching技术,对DrawCall进行优化。它在不改变显示效果的前提下,尽可能的把相同材质的物体调整到连续的RenderingOrder值上,以促使它们能够被Unity DynamicBatching优化;

3)支持图文混排;

4)支持虚拟列表,即使数量巨大的列表也不会感觉太卡顿。

2.5 其他方案

因为笔者未在实际项目中使用过,所以这里不做评述了,读者可以根据贴出的链接跳转过去瞅一瞅哈!

1)Unity高阶版UIToolkit

学习地址:https://docs.unity3d.com/cn/2020.1/Manual/UIElements.html

是Unity新推出的新一代UI系统,既支持游戏编辑模式也支持运行时模式。但目前还不够完善。读者可以尝尝鲜,试用一下。

2)EZGUI

资源地址:https://assetstore.unity.com/packages/tools/ez-gui-32

【注:官方资源下架 已购买可以继续使用】

3)IGUI

资源地址:https://assetstore.unity.com/packages/tools/gui/igui-basic-1946

【注:官方资源下架 已购买可以继续使用】

本篇主要介绍了Unity项目比较流行的UI解决方案,笔者在这里只是做一个汇总概述,并没有去深究。至于读者该如何选择,仁者见仁,智者见智。一句话总结:没有最好的,只有最适合的!

参考资料

1、Unity官网:https://unity.cn/

2、Siki学院:http://www.sikiedu.com/course/explore/unity?subCategory=&selectedthirdLevelCategory=&filter%5Btype%5D=all&filter%5Bprice%5D=all&filter%5BcurrentLevelId%5D=all&orderBy=hotSeq&from_flag=baidu_unity

本教程中,我们来学习一下如何使用Array.splice()方法将数组等分,还会讲一下,Array.splice() 和 Array.slice() 它们之间的不同之处。

1. 将数组分为两个相等的部分

我们可以分两步将数组分成两半:

  1. 使用length/2和Math.ceil()方法找到数组的中间索引
  2. 使用中间索引和Array.splice()方法获得数组等分的部分

Math.ceil() 函数返回大于或等于一个给定数字的最小整数。

const list = [1, 2, 3, 4, 5, 6];
const middleIndex = Math.ceil(list.length / 2);

const firstHalf = list.splice(0, middleIndex);   
const secondHalf = list.splice(-middleIndex);

console.log(firstHalf);  // [1, 2, 3]
console.log(secondHalf); // [4, 5, 6]
console.log(list);       // []

Array.splice() 方法通过删除,替换或添加元素来更改数组的内容。而 Array.slice() 方法会先对数组一份拷贝,操作。

  • list.splice(0, middleIndex) 从数组的0索引处删除前3个元素,并将其返回。
  • splice(-middleIndex)从数组中删除最后3个元素并返回它。

在这两个操作结束时,由于我们已经从数组中删除了所有元素,所以原始数组是空的。

另请注意,在上述情况下,元素数为偶数,如果元素数为奇数,则前一半将有一个额外的元素。

const list = [1, 2, 3, 4, 5];
const middleIndex = Math.ceil(list.length / 2);

list.splice(0, middleIndex); // returns [1, 2, 3]
list.splice(-middleIndex);   // returns [4, 5]

2.Array.slice 和 Array.splice

有时我们并不希望改变原始数组,这个可以配合 Array.slice() 来解决这个问题:

const list = [1, 2, 3, 4, 5, 6];
const middleIndex = Math.ceil(list.length / 2);

const firstHalf = list.slice().splice(0, middleIndex);   
const secondHalf = list.slice().splice(-middleIndex);

console.log(firstHalf);  // [1, 2, 3]
console.log(secondHalf); // [4, 5, 6]
console.log(list);       // [1, 2, 3, 4, 5, 6];

我们看到原始数组保持不变,因为在使用Array.slice()删除元素之前,我们使用Array.slice()复制了原始数组。

3.将数组分成三等分

const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const threePartIndex = Math.ceil(list.length / 3);

const thirdPart = list.splice(-threePartIndex);
const secondPart = list.splice(-threePartIndex);
const firstPart = list;     

console.log(firstPart);  // [1, 2, 3]
console.log(secondPart); // [4, 5, 6]
console.log(thirdPart);  // [7, 8, 9]

简单解释一下上面做了啥:

  1. 首先使用st.splice(-threePartIndex)提取了ThirdPart,它删除了最后3个元素[7、8、9],此时list仅包含前6个元素[1、2、3、4、5、6] 。
  2. 接着,使用list.splice(-threePartIndex)提取了第二部分,它从剩余list=[1、2、3、4、5、6](即[4、5、6])中删除了最后3个元素,list仅包含前三个元素[1、2、3],即firstPart。

4. Array.splice() 更多用法

现在,我们来看一看 Array.splice() 更多用法,这里因为我不想改变原数组,所以使用了 Array.slice(),如果智米们想改变原数组可以进行删除它。

const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];

获取数组的第一个元素

list.slice().splice(0, 1) // [1]

获取数组的前5个元素

list.slice().splice(0, 5) // [1, 2, 3, 4, 5]

获取数组前5个元素之后的所有元素

list.slice().splice(5) // 6, 7, 8, 9]

获取数组的最后一个元素

list.slice().splice(-1)   // [9]

获取数组的最后三个元素

list.slice().splice(-3)   // [7, 8, 9]

作者:Ashish Lahoti 译者:前端小智 来源:jamesknelson

原文:https://codingnconcepts.com/javascript/how-to-divide-array-in-equal-parts-in-javascript/

10 年 JavaScript 都会发生一次改朝换代式的变革。在我看来,JavaScript 当前正处于一次快速变革的开始,而这段时期未来可能会被称为 JavaScript 第三纪元。

本文最初发布于 shawn swyx wang 博客,经原作者授权由 InfoQ 中文站翻译并分享。

历说从头

JS 的第一纪元(从 1997 至 2007) 堪称虎头蛇尾。大家都知道 Brendan Eich 的故事,但是关于 ES4 是如何与诸如 Flash/Actionscript 之类的封闭生态系统艰难地进行激烈竞争的故事却鲜为人知。我推荐大家读读《JavaScript:20 年发展史》来了解 JS 起源的前前后后,我认为这本书是一个非常合适的选择, 因为该书是由 JS 的主要作者 Brendan Eich 和 Allen Wirfs-Brock 联手发布的。

JS 的第二纪元(从 2009 至 2019) 是从关键的 2009 年开始的,这一年诞生了 npm,Node.js 和 ES5。随着 Doug Crockford 在 《JavaScript 精粹》 一书中向我们展示了 JS 的精妙之后,JS 的使用者们创造出了一大堆的 JS 构建工具 和库,并将 JS 的应用范围扩展到了台式机和新型智能手机。到了 2019 年,我们甚至看见,在手机端出现了诸如 Facebook 的 Hermes 之类的定制 JS 运行时系统,以及诸如 Svelte 3 之类的预编译前端框架。

译者注:

《JavaScript 精粹》,这本书的作者是 Doug Crockford,书中他主要从以 JS 的语法、对象、函数、继承、数组、正则表达式、编码格式以及一些优秀的功能等方面,向大家展示 JS 的精妙之处,同时也指出了 JS 的很多缺陷。

Hermes,是 Facebook 推出的一款运行在安卓系统中的 JS 引擎,该引擎对运行在安卓系统中的 React Native 应用做了性能优化,该引擎最大的特点是,会提前对代码进行静态优化和字节码压缩。

Svelte,是一个全新理念的前端框架,该框架最主要的 2 大特性是:

第一,将诸如代码检查、状态管理、动画等功能都做了封装;

第二,构建时会将源码直接转换为目标运行代码,而不是在运行时再处理(这里大家可以回想下在使用 webpack 构建的过程中,那个在运行时处理代码的 runtimechunk.js)。

JS 的第三纪元

2020 年感觉像是一个新纪元的开始。如果说第一个纪元是关于一个语言的诞生,第二纪元是关于人们对这个语言的探索和扩展,那么第三纪元则是与摒弃历史观念和工具层级折叠相关。

注:作者早期提出过 层级折叠 的观点

在当前的 JS 生态里,如果我们希望将编写的代码投入目标环境(例如浏览器环境)运行的话,大部分代码都需要通过几层工具的转换,如 TS 编译器、ESLint/JSLint、Less/Scss 、Babel、uglify 等,那么作者认为未来的趋势是,这些处理层会被尽可能的折叠。

首当其冲要摒弃的历史观念是:JS 生态需要依赖 CommonJS 模块系统,这种观念是不断妥协的结果。ES Modules 作为替代者已经伺机而动很久了,只是缺少一个一蹴而就的机会,主要的原因是,当前在使用中的工具虽然慢但是“已经够用”,于是大家缺乏更换的动力。在前端,现代浏览器虽然已经具备了处理一些 ES Modules 功能的能力,但一些重要的细节依然没有得到很好的解决。

译者注:

由于这些重要的细节没有解决,所以 V8 官方建议大家,在现代浏览器上使用 ES Modules 功能时,依然通过诸如 webpack、Rollup 之类的构建工具对源代码进行构建。

Pika 的 Snowpack 项目希望通过提供一个外观模式(facade)来加快 ES Modules 功能的提前应用,该模式会随着 ES Modules 的完善而逐步消失。最后来点鼓舞人心的消息,IE11 从今年开始至 2029 年将逐步结束其缓慢的发展历程。

另一个要摒弃的历史观念是:必须使用 JavaScript 构建 JavaScript 工具。 在热路径中,类型安全性和 性能提升(10 到 100 倍) 的潜力太大了,不容忽视。这种“只使用 JS 为 JS 构建工具”的想法,随着 TypeScript 几乎完全接管了 JavaScript 而逐渐消失,同时最近崭露头角的 Deno 和 Relay 也进一步证明了,人们将会通过学习 Rust 来向 JS 核心工具库做贡献。Brandon Dail 预测这种转变(工具的构建形式)将会在 2023 年完成。不过大部分使用中的非核心工具,由于其易用性相对性能更加重要,因此我们将依然会使用 JavaScript 和 TypeScript 进行编写。以前我们考虑的是“功能内核,命令式 Shell”,而现在我们应该考虑的是“系统内核,脚本 Shell”。

注:上面的观点也是有争议的。Python 的解析器 PyPy 就表明这不是一个既定的结论。

层级也在以有趣的方式进行折叠。Deno 采取了激进的方式,它编写了一个全新的运行时,同时将诸如测试、格式化、代码校验和打包等一堆常用的任务工具折叠到一个二进制文件中,针对 TypeScript 甚至直接包含了一个 标准库。而 Rome 则采用了不同的方式,它还是基于 Node.js 将这些层折叠了起来(据我所知,这些使用起来很简单)。

10 年前,诸如 AWS、Azure、GCP 等公有云都还不存在,但是今天,它们已经是生活的一部分了。JavaScript 和云之间的关系非常微妙,以至于我都很难清晰的表述出来。云平台的开发者不会直接使用 JS,但是 JS 却又是他们最大的客户。AWS Lambda 第一个推出对 JS 的支持,它的一个明显变化是,折叠了 IDE 层和云服务层,移除了中间那个令人讨厌的笔记本电脑。许多诸如 Glitch、Repl.it、Codesandbox、GitHub Codespaces、Stackblitz 的 云服务发行者 都在利用 JS 来探索这个领域。与此同时,像 Netlify 和 Vercel 一样,JAMstack 从 PoV 开始,合并了 CI/CD 层和 CDN 层,移除了其间令人厌烦的运行时服务。

即使在前端框架中,层级折叠的发展同样鼓舞人心。从动画到状态管理,Svelte 将所有的事情都折叠到了编译器里。React 也在探索 元框架 和 客户端与服务端集成 的方案,同时 Vue 正在致力于开发一个称为 Vite 的“无需打包”的开发服务项目。

总结:

在 JS 第三纪元中,其构建工具的发展将会是下面几个方面:

  • 更快
  • ES Modules 优先
  • 层级折叠(事半功倍,而非事倍功半)
  • 类型安全 / 类型安全检查(以强类型语言为核心进行构建,同时允许用户零配置支持 TS)
  • 安全 / 安全检查(避免依赖注入攻击,或者不严格的权限)
  • 新的同构策略(充分的认识到,JS 应该首先在构建时运行,或者在到达客户端之前在服务器端运行)

所有这些工作,最终都是促使开发体验(更快的构建,行业标准的工具化)和用户体验(更小的构建包,更快的功能交付)变得更好。这是 JavaScript 从脚本编程语言到完整应用平台的最终蜕变。

JavaScript 将死?

如果 Gary Bernhardt 的预言成真,那么第三纪元将是 JavaScript 的最后一个发展纪元(Gary Bernhardt 给出的时间结点是 2035 年)。Web Assembly 总是在 JavaScript 的周围若隐若现,甚至连 Brendan Eich 都改变了他的名言称:“永远押宝在 JS 和 WASM”,他最初认为 JS 可能是“通用虚拟机”,但是曾经有人告诉我,现在 WASM 就是这个想法的最终实现。

如果真如上面所说,那么我们现在正处于 JavaScript 消亡的边缘

轮到你了

大约到 2030 年的时候,JavaScript 的第三纪元接近尾声,那时 JavaScript 将会有什么样的发展?请在下面评论区说出你的预测:

参考阅读: https://www.swyx.io/writing/js-third-age/