unity创建的文本框怎么改为无色

unity创建的文本框怎么改为无色,第1张

UGUI中同一文本框Text使用不同颜色
今天在 Unity3D 使用过程中遇到了一个问题,就是希望在同一个Text中实现多种不同的颜色。
使用的是 UGUI。
最初是在代码中直接更改Text颜色,但是这样Text中所有文字的颜色都会发生变化。
Text battleText;battleTextcolor = Colorred;但是因为不是一个大问题,觉得日后也很难遇到这种纯用文字描述的情况,最后使用了多个Text重叠的方式单独显示,以此把不同文字的颜色区分开来。
休息的时候看到了游戏中的战斗情况文字,发现这种同一段文字中不同部分使用不同颜色的情况还是挺常见。
例如:
战斗回顾中,伤害文字使用红色,回复文字使用绿色。
所以决定还是得好好研究一下。最后发现UGUI代码本身就支持颜色代码标签。
感觉自己学习得还是不够细心。

在text中需要空格的地方加入 <color=#FFFFFF00>缩进</color> 就可了,需要空几格就将“缩进”改为几个字

>1、UI DrawCall分析工具

最近只针对项目中主界面的UI进性DrawCall的优化,主要用到的工具就是Unity自带的Frame Debugger,我们项目使用的是Sprite Packer打图集,如果是从本地加载资源,如图1-1,首先要确保Project Settings中Sprite Packer Mode为Always Enabled,保证游戏运行时所有的图标打到对应的图集中。如果使用AssetBundle方式加载,打包的时候应该已经打成图集了,该项设置不设置就无所谓了。

Frame Debugger打开方式Window->Analysis->Frame Debugger(我用的Unity版本是201848),打开后界面如下:

点击后就会展示游戏中所有的DrawCall信息,如图1-3,Unity UI绘制调用的位置在CameraRender下Render的子组CanvasRenderSubBatch下,后边的68即为UI占用的DrawCall数量。Unity UI绘制调用的位置取决于Canvas的Render Mode,我们使用的Render Mode为Screen Space-Camera。如果Render Mode设置为Screen Space - Overlay,则Ui绘制的位置在CanvasRenderOverlay组中,如图1-4所示;如果Render Mode设置为World Space时也是在CameraRender下Render的子组中,虽然都是子Render,但是和Screen Space-Camera模式会在不同的子组中。
选中某个Draw Mesh右侧就会显示该详细信息,如图1-5,选中的是一个Image,其中1表示该Image渲染的渲染层级为203,2表示该组件使用的shader为UI/Default,3表示Image所在的图集为Common(Group 1)。

再看一个Text的详细信息,如图1-6,基本与Image相同,只是使用的纹理不同。
2、影响Draw Call的因素

(1) 针对Image,需要保证使用的在同一图集且同一个Group中,且使用的材质相同。

a、 如下图所示,一般的Image都不会设置Material即Material为None,此时使用的就是UGUI默认的材质,如图1-4中的2标记的位置,都是默认UI/Default,所以材质的问题一般不需要考虑;

b、 重点考虑的就是图集问题,这是比较麻烦的问题,需要根据使用的范围来规划图集。开始我们把所有主界面用到的都放到一个图集中,但是由于个数太多,而图集又有大小上限(我们项目中设置的为10241024),虽然会打到同一个图集中,但是会被分到不同的Group中。通过Frame Debugger查看即使在同一个图集中,不在同一个Group也不能合批。所以直接把所有放在一个图集中并不能解决问题,还要根据UI进行细分,同一个UI中使用的打到一个图集里,或几个UI中用到的图集打到一个图集中。好多个UI公用的单独放到一个公用的图集中。为了便于规划图集,我还写了个小工具统计每个在各个UI中的使用情况。统计结果如图2-2,每一行显示某个的引用次数,次数后紧跟引用该的UI。
[MenuItem("策划/UI/收集UI中引用情况")]

public static void GetSpriteReferCount()

{

            Dictionary<string, Dictionary<string, bool>> spriteToPrefab = new Dictionary<string, Dictionary<string, bool>>();

            List<string> allFullPath = MUEditorUtilityGetAllFullPathIn(UI_ASSET_DIR, "prefab");

            for (int i = 0; i < allFullPathCount; i++)

            {

                EditorUtilityDisplayProgressBar("检测", "正在收集UI中的引用情况……", i / (float)allFullPathCount);

                string assetPath = MUEditorUtilityFullPathToAssetPath(allFullPath[i]);

                GameObject uiGameObj = AssetDatabaseLoadAssetAtPath<GameObject>(assetPath);

                if (uiGameObj == null)

                {

                    continue;

                }

                Component[] allImageComponents = uiGameObjtransformGetComponentsInChildren(typeof(Image), true);

                for (int j = 0; j < allImageComponentsLength; j++)

                {

                    Image t = allImageComponents[j]GetComponent<Image>();

                    if (tsprite != null)

                    {

                        string spriteName = tspritename;

                        if (spriteToPrefabContainsKey(spriteName) == false)

                        {

                            spriteToPrefab[spriteName] = new Dictionary<string, bool>();

                        }

                        if (spriteToPrefab[spriteName]ContainsKey(uiGameObjname) == false)

                        {

                            spriteToPrefab[spriteName][uiGameObjname] = true;

                        }

                    }

                }

            }

            Dictionary<string, Dictionary<string, bool>> spriteToPrefab1 = spriteToPrefabOrderBy(o => oValueCount)ToDictionary(p => pKey, o => oValue);

            DirectoryInfo dirInfo = DirectoryCreateDirectory(ApplicationdataPath + "/Res/Gui");

            FileInfo[] files = dirInfoGetFiles("UI_Sprite_Refertxt");

            foreach (var file in files)

            {

                FileDelete(fileFullName);

            }

            using (FileStream fileStream = FileCreate(dirInfoFullName + "/UI_Sprite_Refertxt"))

            {

                string txt = "";

                string temp = "";

                foreach (KeyValuePair<string, Dictionary<string, bool>> kv1 in spriteToPrefab1)

                {

                    temp = kv1Key + ":";

                    //temp += " " + GetParentDir(kv1Key);

                    temp += "  " + kv1ValueCount;

                    foreach (KeyValuePair<string, bool> kv2 in kv1Value)

                    {

                        temp += "  " + kv2Key;

                    }

                    txt += temp;

                    txt += "\n";

                }

                StreamWriter writer = new StreamWriter(fileStream);

                writerWrite(txt);

                writerFlush();

                writerClose();

                fileStreamClose();

            }

            EditorUtilityClearProgressBar();

        }

c、 在打图集的过程中还遇到一个问题,同一图集中的一个,在总大小没有超过图集上限的情况下,却被打到了该图集的另一个Group中。使用Frame Debugger也看不出问题。然后我就用Sprite Packer在本地打一下图集看一下,这两个Group区别在哪儿。通过对比发现两个Group中的格式不一样,一个为RGBA Compressed DXT5,一个为RGB Compressed DXT1,如图2-3和2-4。
原来Unity打图集时只能将相同格式的打到同一Group中。查看被打到另一个Group中的,发现这张图没有Alpha通道,工程中所有平台的纹理Format都设置为Automatic,Alpha Source设置为Input Texture Alpha,即Unity会根据原图是否有Alpha通道自动设置纹理格式,如图2-5。

我们可以通过重写不同平台上的格式设置,保证该格式与其他格式一致,如图2-6。

(2) 针对Text,保证相邻的Text使用相同字体,相同材质,这个一般情况都可以做到。

(3) 保证可以合批的元素在同一个Canvas下。

为了防止某些动态元素(如倒计时、技能CD等)的改变导致整个UI的网格重建,一般采用动静分离的方式,将动态元素放在单独的Canvas下。这时可能误将一些本可以合批的静态元素放到了不同的Canvas下。我在优化时就遇到了这种情况。如图2-7所示,Image_Kuang和Image_Parent位于同一渲染层级,且他们挂的在同一图集里,但由于Image_Parent节点下有动态变化元素,所以单独挂了Canvas,导致这两个Image不能合批。解决方式就是将Image_Parent的Image移除挂到一个新建的与Image_Kuang位于同一Canvas的节点下,如图2-8所示,在Image_Kuang下单独建了一个Image_PosBack节点挂载Image。
(4) Mask和Rect Mask 2D会将内外元素分离导致不能合批。另外能用Rect Mask 2D解决的尽量不要用Mask,Mask除了使内外元素不能合批,本身也会占用2个DrawCall。Mask和Rect Mask 2D比较如下:

a、 Mask占用两个DrawCall,一个在底下设置Stencil Buffer,一个在顶上还原Stencil Buffer,Mask下的子元素夹在中间本身不占DrawCall;Rect Mask 2D本身不占DrawCall

b、 如果多个Mask绑定的Image组件,属于同一个Atlas,那么Mask之间的元素可以进行合并(包括Mask自己产生的2个DrawCall);否则不能合并如果RectMask2D上绑定了Image,那么多个RectMask2D的Image如果属于同一个Atlas可以合并

c、内外元素 无法合批无法合批

d、完全裁剪元素:Mask 依然占据DrawCall;Rect Mask 2D不占用DrawCall,也不参与Depth计算;

e、Hierarchy 中被分割元素:Mask 可以正常合批;Rect Mask 2D:如果Depth、Atlas与RectMask2D下的某元素相同,则无法合批。

f、裁剪掉的部分:Mask 还会影响其他元素的Depth计算,而它自己的也会受到其他元素的影响。Rect Mask 2D 依然参与Depth计算

g、 多个Mask内的UI节点间如果符合合批条件,可以合批。RectMask2D之间无法合并DrawCall。

(5) UI元素Position或者Rotation改变

a、 Position的Z值不为0,元素会被视为3DUI,不参与合批,如果父节点Z!=0,其下的子元素都无法合批。

b、 Rotation的X或Y修改,导致元素不在UI平面,则无法合批,原因和Position的Z值改变一样。
(6) UI元素重叠和层级深度

这个最终要的结果就是使多个元素的渲染层级相同,就达到合批目的了,如图1-4中1标记的位置。当然这一项的调整也是最耗时最需要耐心的,这就需要我们去分析每个UI中各个元素在Hierarchy中的层级。

下面拿一个例子说明一下,如图2-9所示,图中左侧红框内4个元素,其中Image_Back、Drop_Image、Btn_Image所用在一个图集中,Drop down使用的在其它图集中。这时所有的元素占用3个DrawCall,查看右侧Draw Mesh发现Image_Back和Drop_Image共占一个DrawCall,而Btn_Image和Dropdown分别单占一个DrawCall。

下面我们调整一下Btn_Image的位置,如图2-10所示,整体的Draw Call变成2,Image_Back、Drop_Image、Btn_Image三个元素共占一个DrawCall。Dropdown单独占一个DrawCall。这是因为开始时Dropdown夹在Drop_Image和Btn_Image中间,由于它属于另外的图集,破坏了Drop_Image和Btn_Image的合批。

Unity自带的Profiler工具中可以查看合批中断的原因。如图2-11所示,打开Profiler,滑动到最底部可以看到两个和UI相关的选项,一个UI,一个UI Details,选中任意一个,下边有全部Canvas的一个列表,点击展开任意一个Canvas,就可以看到该Canvas下所有的批处理信息,其中有一列Batch Breaking Reason显示了该批次不能与上一个批次合批处理的原因,合批被破坏的主要原因有两个:Different Texture:即使用的纹理不同,可能是不在同一个图集,也可能是Image和Text相邻导致;Different Material Instance:材质不同,一般由于自己给Image使用了自定义材质或者游戏中使用了Text Mesh Pro UGUI。另外GameObject Count为该批次处理对象的个数;GameObjects列列出了所有对象,可能由于对象太多只显示有几个Objects,这是可以双击这一行,会直接选中该批次处理的所有对象,如图2-12所示。

另外看到一个Cumulative Batch Count:累计批次数量。如图2-11,我们可以看到该列的总值为82,我们再看一下Frame Debugger中 Draw Mesh的个数,如图2-13为69。这两个数不一样,Frame Debugger中显示的是当前帧Batch个数,而Cumulative Batch Count是从开始游戏运行总的批次个数,在游戏过程中有些元素的改变导致批处理的变化,所以这两个数会不一样。

(7) 对于Alpha为0的Image,需要勾选其CanvasRender组件上的Cull Transparent Mesh选项,否则依然会产生DrawCall且容易打断合批。

(8)空Image

有时会使用空的Image来接受点击事件,空Image也会产生DrawCall。我们可以使用Empty4Raycast组件替代空Image。

相信很多刚接触UGUI的开发者,对于这套系统中RectTransform里的position,anchor,pivot都或多或少有些不熟悉,不知道这些是干嘛用的,为此,本篇文章就给大家介绍下这几个概念,不过主要还是会以Anchor和Pivot为主,position会带过介绍。

1、Pivot轴心

旋转、大小和缩放修改发生在主轴Pivot点周围,因此Pivot的位置会影响旋转、调整大小或缩放的结果。当工具栏Pivot/Center按钮设置为Pivot模式时,可以在场景视图中移动矩形变换的Pivot小圆圈。

如图:旋转 *** 作为绕着这个点旋转。

注:

Pivot是相对于自身的,(0,0)为自己左下角,(1,1)为自己右上角。(可以把这个UI看成这个点)

2、Anchors锚点

如果一个RectTransform的父物体也是RectTransform,那么子RectTransform可以以各种方式锚定到父RectTransform。

例如,子节点可以锚定在父节点的中心或其中一个角上。

锚定也允许孩子与父母的宽度或高度一起伸展。矩形的每个角都有一个固定的锚点偏移量,即矩形的左上角有一个固定的锚点偏移量,等等。这样,矩形的不同角就可以固定在父矩形的不同点上。

如:

3、Anchor presets锚点预设

在Inspector中,可以在Rect Transform组件的左上角找到锚预置按钮。单击该按钮将d出锚预置下拉菜单。从这里您可以快速地从一些最常见的锚定选项中进行选择。您可以将UI元素锚定到父元素的侧面或中间,或者与父元素大小一起拉伸。水平和垂直锚定是独立的。

锚预置按钮显示当前选择的预置选项(如果有的话)。如果将水平轴或垂直轴上的锚设置为与任何预设位置不同的位置,则会显示自定义选项。

Anchor Min对应场景视图中左下方的Anchor handle, Anchor Max对应右上方的handle。

矩形的position字段根据锚顶点是否在一起(产生固定的宽度和高度)或是否分开(导致矩形与父矩形一起拉伸)而不同。

方式1:当所有的锚柄在一起时,显示的字段是Pos X、Pos Y、宽度和高度。Pos X和Pos Y的值表示pivot相对于锚点的位置。

方式2:当锚被分开时,字段可以部分或完全改变为左、右、上、下。这些字段定义锚定义的矩形内的填充。如果锚水平分开,则使用左字段和右字段,如果锚垂直分开,则使用顶部和底部字段。

注意,在anchor或pivot字段中更改值通常会反向调整position值,以使矩形保持原位。在不需要这样做的情况下,通过单击检查器中的R按钮启用原始编辑模式。这使得anchor和pivot值能够在不改变任何其他值的情况下被改变。这可能会导致矩形在视觉上移动或调整大小,因为它的位置和大小取决于anchor和pivot值。

看下图预设布局,可以注意到:布局分为左侧、上侧和右下。

左和上只是方位标记,用啥要选择右下角部分;

右下部分的左上9个是一个点,所有锚柄在一起,大小不会受父物体影响,父物体大小变化子物体pivot到锚点位置保持不变; 如上面方式1

其他为2个点,最右下角的为四个点,大小会受父物体影响;如上面方式2

注意区分:

Pivot是相对于自身的,(0,0)为自己左下角,(1,1)为自己右上角。(可以把这个UI看成这个点)

Anchor为相对于父物体的,(0,0)为父物体左下角,(1,1)为父物体右上角。

4、Blue Print Mode(蓝图模式) 、 Raw Edit Mode(原始编辑模式)

参考链接: >

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13409819.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-30
下一篇 2023-07-30

发表评论

登录后才能评论

评论列表(0条)

保存