【Unity3D技巧】一个简单的Unity-UI框架的实现
如何使用
请直接导入UnityUIFramework这个UnityPackage,然后进入名为Test的Scene即可开始体验各种特性,Enjoy!你可以通过访问我的Github进行查阅和下载。
View,Context和UI的定义
UI是游戏中主要界面和它的子节点上的物体的统称,如装备列表界面中的装备列表和每个装备通常会被制作成两个Prefab,这两个Prefab被我们称作两个UI,这两个UI会对应两个UIType,在UIType里面会存储有这个UI全局唯一的名字和路径,如下:
public class UIType {
public string Path { get; private set; }
public string Name { get; private set; }
public UIType(string path)
{
Path = path;
Name = path.Substring(path.LastIndexOf('/') + 1);
}
public override string ToString()
{
return string.Format("path : {0} name : {1}", Path, Name);
}
}
View代指游戏中的主要界面,例如:主界面,装备界面,装备详情界面等等。在View中包含了界面中处理数据的逻辑。
Context代指游戏中每个View的上下文,存储了这个界面的各种数据状态,每个特定的View会持有特定的Context,游戏中会通过栈的方式管理Context。
在本框架中,会把Context和View定义在同一个cs文件中,如下:
public class OptionMenuContext :BaseContext
{
public OptionMenuContext() : base(UIType.OptionMenu){}
}
public class OptionMenuView : AnimateView
{
public override void OnEnter(BaseContext context)
public override void OnExit(BaseContext context)
public override void OnPause(BaseContext context)
public override void OnResume(BaseContext context)
}
View的创建和销毁
所有界面上挂上的Mono脚本和关联的Prefab统一以XXXView
命名。
所有View的路径统一放在UIType中进行管理,每当新创建一个View的时候,都需要在UIType中新添加一个成员变量指明View的路径。
public static readonly UIType MainMenu = new UIType("View/MainMenuView");
public static readonly UIType OptionMenu = new UIType("View/OptionMenuView");
public static readonly UIType NextMenu = new UIType("View/NextMenuView");
public static readonly UIType HighScore = new UIType("View/HighScoreView");
在游戏中单独出现的View会通过UIManager中的GetSingleUI
和DestroySingleUI
来进行创建和销毁。
View的跳转
每个View都相应拥有相应的Context来保存该界面的状态,View的跳转通过ContextManger管理,ContextManager中以栈的形式储存了已经经过的界面的Context。这样在返回的时候就可以得到需要的状态参数。
当需要进入下一个View的时候,调用ContextManger.Instance.Push(nextContext)
即可,nextContext即为下一个View需要的上下文参数, 这是会调用当前View的OnPause函数,对当前View的上下文进行存储,并调用下一个View的OnEnter函数,对下一个Viwe的上下文进行初始化
当需要返回上一个界面的时候,调用ContextManger.Instance.Push.Pop()
即可。这是会调用当前界面的OnExit函数,接着调用下一个界面的OnResume函数。
View的动画
如果在界面上使用3D的旋转动画,就很难使用DoTween或者iTween在代码里面进行动画控制,而且为了保持战斗模块和UI模块设计的一致性。因此建议使用Animator对View的各种动画进行控制,而View的动画一般又和View的跳转逻辑联系紧密,所以建议将两者进行绑定,一个View的动画状态机如下图:
一个界面在没有显示的时候会处于Empty状态,当接收到OnEnter的Trigger的时候,会播放OnEnter动画,其他的状态如图所示,可以参考上图以及项目中的状态机。不同的界面可以使用相同的状态机,只是在某些状态上绑定的动画会有所不同。
这样做的另一个好处是,我们可以使用动画时间的方式在动画过程中做一些回调,这样的在界面上对回调时机进行编辑,相比使用协程或者Dotween的OnFinished函数,有更好的可编辑性。
本地化
本地化是通过单例Localization和组件LocalizedText两个来协同实现的,不同语言的文字会存储在Resources/Localization
中的不同JSON文件中,在单例Localization中配置后语言之后,即可读入相应的JSON文件。
每个LocalizedText所在的GameObject上都需要与Text绑定,LocalizedText会根据自己的textID对Text中的text进行本地化
分辨率适配
UGUI中的分辨率适配是通过CanvasScaler来实现的,如下图:
在这里,我建议使用Scale With Width Or Height这种Scale模式,同时,由于大多数游戏是横屏游戏,通过使用高度固定,宽度随之变化的模式。这样我们就可以以一个固定的高度进行UI设计,只需要考虑UI在水平尺度上的延伸就可以了。
提升滑动列表的性能
在UGUI中Scroller和Grid都是很好用的组件,但是由于它们在实现过程中考虑了太多对齐,排序的问题,这就导致它们在处理无限列表问题的时候遇到了极大的性能瓶颈,相关资料参考:Performance issues on android with Scrollrect。在本框架中实现的自定义组件GridScroller可以在保证可编辑性的同时,提升了滑动列表的性能。
GridScroller的原理是:在滑动到某个item上的时候,会把之前的item进行回收,并且把它放到下一个位置进行再利用。在使用GridScroller的时候,你同样要使用ScrollRect和GridLayout,GridScroller会从这两个组件中读取相应的属性并且运用到UI逻辑中。
GridScroller对外界代码提供了一个Init的接口,通过这个接口,外界模块可以向GridScroller传入一个onChange回调函数,这样在GridScroller在刷新的时候,就会动态刷新相应的itemPrefab,实现用到时再加载的特性。
[RequireComponent(typeof(ScrollRect))]
public class GridScroller : MonoBehaviour {
// public UI elements //
[SerializeField]
private Transform _itemPrefab;
[SerializeField]
private GridLayoutGroup _grid;
// public fields //
[SerializeField]
private Movement _moveType = Movement.Horizontal;
public delegate void OnChange(Transform trans, int index);
public void Init(OnChange onChange, int itemCount, Vector2? normalizedPosition = null)
{
Clear();
InitScroller();
InitGrid();
InitChildren(onChange, itemCount);
InitTransform(normalizedPosition);
}
对UI进行修饰
由于UGUI的Image,Text等属性一般是不会设置Material的,我们可以通过写脚本继承BaseVertexEffect来对UI的Vertex进行修饰,项目中的Gradient Color和Blend Color就通过这种方式实现了颜色渐变和颜色运算的功能。通过重载ModifyVertices
这个方法,你可以不实用Shader直接在脚本里对UI的渲染方式进行修饰。
【Unity3D技巧】一个简单的Unity-UI框架的实现的更多相关文章
- Node.js简单介绍并实现一个简单的Web MVC框架
编号:1018时间:2016年6月13日16:06:41功能:Node.js简单介绍并实现一个简单的Web MVC框架URL :https://cnodejs.org/topic/4f16442cca ...
- 从零构建一个简单的 Python Web框架
为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...
- Directx11学习笔记【十一】 画一个简单的三角形--effect框架的使用
这里不再介绍effect框架的具体使用,有关effect框架使用可参考http://www.cnblogs.com/zhangbaochong/p/5475961.html 实现的功能依然是画一个简单 ...
- 一个简单的通讯服务框架(大家发表意见一起研究)JAVA版本
最近研究下java语言,根据一般使用的情况,写了个连接通讯服务的框架: 框架结构 C-Manager-S; 把所有通讯内容抽取成三个方法接口:GetData,SetData,带返还的Get; 所有数据 ...
- 一个简单的CPP处理框架
好久没有在csdn上写过东西了,这么多年,一方面是工作忙,下班到家也没有开过电脑了,要陪小孩玩: 下面分享一段代码,是用CPP做的一个简单的消息(协议)处理框架: 是通过成员函数指针+map来实现的: ...
- vnpy源码阅读学习(4):自己写一个类似vnpy的UI框架
自己写一个类似vnpy的界面框架 概述 通过之前3次对vnpy的界面代码的研究,我们去模仿做一个vn.py的大框架.巩固一下PyQt5的学习. 这部分的代码相对来说没有难度和深度,基本上就是把PyQt ...
- Unity3D 创建一个简单的2D游戏
开始研究Unity3d 中的2D游戏. 首先创建出一个项目: 然后创建出一个场景: 然后添加一个背景: 然后创建一个主人公对象: 可以是自己做的素材,也可以是用unity裁剪的素材, 下面贴出裁剪素材 ...
- JavaScript 实现一个简单的MVVM前端框架(ES6语法)
前言 随着前端各大框架的崛起,为我们平时的开发带来了相当的便利,我们不能一直停留在应用层面,今天就自己动手实现一个乞丐版的MVVM小框架 完整代码github地址 效果 html代码 <div ...
- 一个简单 Go Web MVC 框架实现思路
需要的知识点 为了防止你的心里不适,需要以下知识点: Go 基本知识 Go 反射的深入理解 使用过框架 Go Web 服务器搭建 package main import ( "fmt&quo ...
- 用werkzeug实现一个简单的python web框架
使用工具 Pycharm , Navicat , WebStorm等 使用库 Werkzeug用于实现框架的底层支撑,pymysql用于实现ORM,jinja2用于模板支持,json用于返回json数 ...
随机推荐
- (转)Android学习笔记---SQLite介绍,以及使用Sqlite,进行数据库的创建,完成数据添删改查的理解
原文:http://blog.csdn.net/lidew521/article/details/8655229 1.SQLite介绍:最大特点是,无数据类型;除了可以使用文件或SharedPrefe ...
- hdu 2042
Ps:...好简单的一道题...直接AC,就是利用递归 代码: #include "stdio.h"int find(int num,int n);int main(){ int ...
- python中的namespace
python中的名称空间是名称(标识符)到对象的映射. 具体来说,python为模块.函数.类.对象保存一个字典(__dict__),里面就是重名称到对象的映射. 可以参看下面python程序的输出: ...
- shell脚本入门教程(转)
http://bbs.chinaunix.net/thread-391751-1-1.html http://www.cnblogs.com/suyang/archive/2008/05/18/120 ...
- php大力力 [021节]mysql表名在mac下不能大写
2015-08-27 php大力力021.mysql表名在mac下不能大写 刚才数据库里面,phpMyAdmin狂出错. Some errors have been detected on the s ...
- HDU 1721
http://acm.hdu.edu.cn/showproblem.php?pid=1721 非常有趣的一道水题,注意到相隔一个点的粒子数是可以相互转移的,所以只要判红点的和与蓝点的和是否相等 #in ...
- JS删除HTML元素问题
<div id='one'> <div>1</div> <div>2</div> </div> <div id=" ...
- 第二个Sprint冲刺第九天
讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 工作:接着昨天的任务
- JavaScript数据结构——树
树:非顺序数据结构,对于存储需要快速查找的数据非常有用. 二叉树:二叉树中的节点最多只能有两个子节点(左侧子节点和右侧子节点).这些定义有助于我们写出更高效的向/从树中插入.查找和删除节点的算法. 二 ...
- Page_Init 的执行过程
网上有的资料在说Page_Init这个事件只会在第一次加载页面时触发,实际上并不是这样,我们会发现每次回发页面,Page_Init事件都会被执行, 举一个例子 private static int t ...