自读FairyGUI以及源码分析
版权声明:本文为博主原创文章,未经博主允许不得转载。https://mp.csdn.net/postedit/82223258
这里简单介绍一下自己看了几天对FairyGUI的一些认识,以及对和UGUI一样,理解的Text,NGraphic,Image,Shape这几个类的主要功能。只要是关于在Unity里面的使用,这里只是写一下自己对源码的一些认识和理解,有错误的地方,还希望大家给出意见。
一:参考的地址链接
官方地址:http://www.fairygui.com/以及UnityPackage包地址:https://github.com/fairygui/FairyGUI-unity/releases可以下载关于Unity里面各个版本支持的FairyGUI的SDK。
二:编辑器功能以及介绍
首先是编辑器下载,直接官方文档进行下载。以及了解编辑器常用的功能也是参考上面的官方文档。了解编辑器操作和一些概念和流程制作。
这里介绍一些简单布局操作面板,主要工具栏:主工具栏,库面板,侧工具栏。制作时常用的组件比如文本,滚动列表,滑动条,图片Image。这些官方文档都有介绍,这里就不着重进行介绍了。
三:编辑器到运行时创建流程
启动创建组件UIPanel为例
Start()方法启动-----UIPanel
CreateUI_PlayMode()
GComponent组件创建 UIPackage.CreateObject(string pkgName, string resName)
CreateObject(PackageItem item, System.Type userClass) 创建组件 里面有ConstructFromResource()方法接着解析创建
GetItemAsset(PackageItem item) 根据PackageItemType创建
LoadComponentChildren()根据XML解析出信息进行创建组件
UIObjectFactory.NewObject()根据类型new 出相应的类比如GCompont,GImage走对应类里面的构造方法
Image.Create先走构造方法 LatestGraphicsCreation现在创建到第几个组件
驱动更新Update
StageEngine继承自Monbehaviour
LateUpdate()更新驱动Stage.inst.InternalUpdate() stage舞台继承自Container容器是一个承载器
Container.Update(_updateContext)更新要更新的上下文信息 遍历所有的Children.Count驱动每个DisplayObject.Update
DisplayObject.Update(context)展示对象的Update
执行到Image.Update(context)调用基类的Update 更新材质,更新Mesh,画图形了
Rebuild()进行重建 都有标志位进行过滤提升性能 _requireUpdateMesh是否要求更新Mesh数据
重建清除模式,根据填充方式,进行顶点填充。
PackageItem 描述包里面组件的信息基本会把信息存在一个XML里面,到运行时进行解析
四:重要组件的介绍
- 介绍组件之前介绍,先介绍一下组件之间的继承体系。让更清楚类之间的关系
上面两层是FairyGUI核心事件系统,处理显示对象可以接收来自鼠标和键盘响应的事件,做出注册委托的事件处理。
IEventDispatcher接口
public interface IEventDispatcher
{void AddEventListener(string strType, EventCallback0 callback);void AddEventListener(string strType, EventCallback1 callback);void RemoveEventListener(string strType, EventCallback0 callback);void RemoveEventListener(string strType, EventCallback1 callback);bool DispatchEvent(EventContext context);
}
IEventDispatcher接口负责对EventCallBack0和EventCallBack1带有EventContext事件上下文参数两个委托的封装,接口是增加监听事件和移除事件监听,string strType是事件类型参数比如OnTouchBegin触摸开始,OnTouchEnd触摸结束。
EventDispatcher类
下面是这个类的部分代码
public class EventDispatcher : IEventDispatcher
{Dictionary _dic;internal bool BubbleEvent(string strType, object data, List addChain){EventContext context = EventContext.Get();context.initiator = this;context.type = strType;context.data = data;if (data is InputEvent)sCurrentInputEvent = (InputEvent)data;context.inputEvent = sCurrentInputEvent;List bubbleChain = context.callChain;bubbleChain.Clear();GetChainBridges(strType, bubbleChain, true);int length = bubbleChain.Count;for (int i = length - 1; i >= 0; i--){bubbleChain[i].CallCaptureInternal(context);if (context._touchCapture){context._touchCapture = false;if (strType == "onTouchBegin")Stage.inst.AddTouchMonitor(context.inputEvent.touchId, bubbleChain[i].owner);}}if (!context._stopsPropagation){for (int i = 0; i < length; ++i){bubbleChain[i].CallInternal(context);if (context._touchCapture){context._touchCapture = false;if (strType == "onTouchBegin")Stage.inst.AddTouchMonitor(context.inputEvent.touchId, bubbleChain[i].owner);}if (context._stopsPropagation)break;}if (addChain != null){length = addChain.Count;for (int i = 0; i < length; ++i){EventBridge bridge = addChain[i];if (bubbleChain.IndexOf(bridge) == -1){bridge.CallCaptureInternal(context);bridge.CallInternal(context);}}}}EventContext.Return(context);context.initiator = null;context.sender = null;context.data = null;return context._defaultPrevented;}
}
里面重要的数据结构Dictionary
所以EventListener是对外包装了EventDispatcher,鼠标左键点击,都会调用owner.BubbleEvent(_type, data)开始执行自身的委托事件和与之关联的组件的委托事件。
还有就是在创建物体的时候是建立父子关系的,在点击子物体的时候,由于父子关系,从根节点到最后的子节点形成一条链,通过在BubbleEvent方法里面GetChainBridges(string strType, List
此设计运用设计模式责任链模式,责任链模式涉及的对象只有处理者角色,但由于有多个处理者,它们具有共同的处理请求的方法,根据有一个链条的关联。形成了一个请求,可以找到所有这个链上的所有对象然后执行这个请求命令。
2:介绍Text,NGraphic,Image,Shape组件
NGraphic组件
NGraphic负责可以在屏幕显示的绘画功能,看类的结构图,被DisplayObject所引用,所以只负责显示对象的渲染功能的封装。
介绍NGraphic之前,还有一些概念,渲染出图元需要经过GPU渲染流水线,需要经过几何阶段和光栅化阶段,另外需要Mesh需要有顶点数据,颜色,三角形连接索引,UV数组,纹理和材质球等数据,最后映射到屏幕上,这只是简单的介绍一下。
另外Unity连接顶点索引的三角形是顺时针连接的。
else if (_scale9Grid != null){Rect gridRect = (Rect)_scale9Grid;if (_flip != FlipType.None)ToolSet.FlipInnerRect(_texture.width, _texture.height, ref gridRect, _flip);GenerateGrids(gridRect, uvRect);if (_tileGridIndice == 0){graphics.Alloc(16);int k = 0;for (int cy = 0; cy < 4; cy++){for (int cx = 0; cx < 4; cx++){graphics.uv[k] = new Vector2(gridTexX[cx], gridTexY[cy]);graphics.vertices[k] = new Vector2(gridX[cx], -gridY[cy]);k++;}}graphics.FillTriangles(NGraphics.TRIANGLES_9_GRID);}
里面有方法生成格子GenerateGrids()方法,还有生成九宫格的三角形索引连接public static int[] TRIANGLES_9_GRID = new int[] {
4,0,1,1,5,4,
5,1,2,2,6,5,
6,2,3,3,7,6,
8,4,5,5,9,8,
9,5,6,6,10,9,
10,6,7,7,11,10,
12,8,9,9,13,12,
13,9,10,10,14,13,
14,10,11,
11,15,14
};
生成格子的代码
void GenerateGrids(Rect gridRect, Rect uvRect)
{float sx = uvRect.width / (float)_texture.width;float sy = uvRect.height / (float)_texture.height;gridTexX[0] = uvRect.xMin;gridTexX[1] = uvRect.xMin + gridRect.xMin * sx;gridTexX[2] = uvRect.xMin + gridRect.xMax * sx;gridTexX[3] = uvRect.xMax;gridTexY[0] = uvRect.yMax;gridTexY[1] = uvRect.yMax - gridRect.yMin * sy;gridTexY[2] = uvRect.yMax - gridRect.yMax * sy;gridTexY[3] = uvRect.yMin;if (_contentRect.width >= (_texture.width - gridRect.width)){gridX[1] = gridRect.xMin;gridX[2] = _contentRect.width - (_texture.width - gridRect.xMax);gridX[3] = _contentRect.width;}else{float tmp = gridRect.xMin / (_texture.width - gridRect.xMax);tmp = _contentRect.width * tmp / (1 + tmp);gridX[1] = tmp;gridX[2] = tmp;gridX[3] = _contentRect.width;}if (_contentRect.height >= (_texture.height - gridRect.height)){gridY[1] = gridRect.yMin;gridY[2] = _contentRect.height - (_texture.height - gridRect.yMax);gridY[3] = _contentRect.height;}else{float tmp = gridRect.yMin / (_texture.height - gridRect.yMax);tmp = _contentRect.height * tmp / (1 + tmp);gridY[1] = tmp;gridY[2] = tmp;gridY[3] = _contentRect.height;}
}
具体生成顶点和连接三角形的索引见图示:
不过这里只介绍这些了,感兴趣的可以继续探究里面各个效果的实现,后续看到还会继续补充,大家互相学习。
Text组件
这里只介绍一些TextField显示文本,TextField也是继承DisplayObject.
下面是部分代码
public class TextField : DisplayObject
{VertAlignType _verticalAlign;TextFormat _textFormat;bool _input;string _text;AutoSizeType _autoSize;bool _wordWrap;bool _singleLine;bool _html;bool _rtl;int _stroke;Color _strokeColor;Vector2 _shadowOffset;List _elements;List _lines;List _charPositions;BaseFont _font;float _textWidth;float _textHeight;float _minHeight;bool _textChanged;int _yOffset;float _fontSizeScale;float _renderScale;string _parsedText;
}
上面是TextFiled处理的一些字段,下面介绍一些方法。
BuildLinesFinal()改变行的大小,设置大小
EnableRichSupport(RichTextField richTextField)是否开启支持富文本
BuildMesh()构建字体的mesh信息,节约性能,缓存顶点,UV,和颜色的数组,避免new。是否有下划线,取中点的UV*0.5 取中间。是否有阴影,加上一个阴影的偏移量。是否有描边,会对顶点有一个偏移。填充三角形和更新mesh
Redraw()重画 _requireUpdateMesh是否要更新
ParseText()解析Html用的方法。
不过Text不光是TextFiled还有富文本,字体格式和字体资源的管理的内容,还有好多方面进行学习和了解。
Shape形状图元
此类继承DisplayObject,对外接口暴漏类型,对画图类型做了对外封装的接口。下面是部分代码
public class Shape : DisplayObject
{int _type;int _lineSize;Color _lineColor;Color _fillColor;Color[] _colors;Vector2[] _polygonPoints;float[] _cornerRadius;
}
Update(UpdateContext context)方法里面根据类型,另Graphics画不同的图元,矩形,椭圆,多边形等,然后更新Mesh数据。
HitTest()会判断是否点击点在图元类,并返回对象。
五:其他的对FairyGUI的了解
Editor文件夹 包括对一些编辑器功能例如分辨率的一些设置
Event文件夹 封装一些事件的接口
Gesture 常用的一些手势,长按手势, 两个指头捏或者放的手势,滑动手势,手指反向操作的手势。
Tween 一些缓动效果,例如DoTween插件
UI FairyGUI常用组件例如UIPanel,GImage组件
Utils工具类 对XML和html格式组件进行封装一些处理方法
总结:
FairyGUI就像官方说的方便设计,总体效率提升。但是工具的使用就是提高开发效率,还要验证效率有没有问题,所以深挖插件的源码功能是有必要的,我只是写一点看了源码的一些收获。具体里面的功能是复杂的,还需要后面不断的进行学习,并运用到项目中,不断优化效率。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!