自读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里面,到运行时进行解析

四:重要组件的介绍

  1. 介绍组件之前介绍,先介绍一下组件之间的继承体系。让更清楚类之间的关系

上面两层是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 _dic存取所有事件类型的EventBridge,然而EventBridge封装了EventCallback0,EventCallback1执行的细节。里面有一个_captureCallback捕获监听。添加监听是EventListener里面关联了EventDispatcher owner和EventBridge _bridge,当DisplayObject构造的时候,初始化onClick,onTouchMove,onClickLink等事件的监听。

所以EventListener是对外包装了EventDispatcher,鼠标左键点击,都会调用owner.BubbleEvent(_type, data)开始执行自身的委托事件和与之关联的组件的委托事件。

还有就是在创建物体的时候是建立父子关系的,在点击子物体的时候,由于父子关系,从根节点到最后的子节点形成一条链,通过在BubbleEvent方法里面GetChainBridges(string strType, List chain, bool bubble)获得自身关联的事件,在向上找父节点,然后依次找父节点,有这种类型的事件都添加到chain这个集合里面,然后遍历执行。所以和发起者关联的组件都执行了此事件类型。

此设计运用设计模式责任链模式,责任链模式涉及的对象只有处理者角色,但由于有多个处理者,它们具有共同的处理请求的方法,根据有一个链条的关联。形成了一个请求,可以找到所有这个链上的所有对象然后执行这个请求命令。

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就像官方说的方便设计,总体效率提升。但是工具的使用就是提高开发效率,还要验证效率有没有问题,所以深挖插件的源码功能是有必要的,我只是写一点看了源码的一些收获。具体里面的功能是复杂的,还需要后面不断的进行学习,并运用到项目中,不断优化效率。

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部