FairyGUI 投影 图片,文本,组件

FairyGUI 中,文本控件自带了投影的功能,我们可以在设置中设置投影的偏移以及颜色。但是我们的UI同学想给图片等也添加投影的效果,就无从实现了。然后就丢给我们程序帮忙解决=。=

需求

可以给组件,图片等添加投影,文字投影需要可以设置透明度(目前不行)。

 

思路

首先自己莫得水平去改FairyGUI Editor编辑器,那就得从unity那下手。如何让unity知道哪些组件我们是想设置投影的,并且获得投影的相关参数。观察发现每个控件的设置中,都有一个自定义数据的设置,我们可以通过在自定义数据中输入一些关键字,然后在Unity解析的时候,进行处理,从而得知该控件是否需要投影以及相关参数。

接着,知道参数后,如何实现投影的效果,一开始给每个需要投影的GObject的GameObject添加一个UnityEngine.UI.Shadow的Component,发现并没什么软用。所以通过原本自带的文本投影的功能,去查看了下他的实现方法,找到相关代码如下:

//TextField.cs
public void OnPopulateMesh(VertexBuffer vb)
{
	....

	bool hasShadow = _shadowOffset.x != 0 || _shadowOffset.y != 0;
	......

	if (allocCount != count)
	{
		VertexBuffer vb2 = VertexBuffer.Begin();
		List<Vector3> vertList2 = vb2.vertices;
Y_5_2 || UNITY_5_3_OR_NEWER
		List<Vector4> uvList2 = vb2.uv0;

		List<Vector2> uvList2 = vb2.uv0;

		List<Color32> colList2 = vb2.colors;

		Color32 strokeColor = _strokeColor;
		......

		if (hasShadow)
		{
			for (int i = 0; i < count; i++)
			{
				Vector3 vert = vertList[i];
				Vector4 u = uvList[i];

				uvList2.Add(u);
				vertList2.Add(new Vector3(vert.x + _shadowOffset.x, vert.y - _shadowOffset.y, 0));
				colList2.Add(strokeColor);
			}
		}

		vb.Insert(vb2);
		vb2.End();
	}

	vb.AddTriangles();
    ......
}

大致就是依样画葫芦,将原始文本的原始顶点都进行偏移(投影偏移),然后用投影的颜色绘制出文本,然后再绘制原始文本叠加在上面,从而实现投影的功能。其中,我们只要修改strokeColor的布尔值,就可以达到投影透明的效果。

 

实现

思路就是TextField的投影实现方式,对于TextField,我们只需要修改strokeColor.a的值即可,对于GImage的Image,我们需自己添加类似的代码实现投影的绘制。

需要修改的文件有五个,GComponent,GImage,GObject,GTextField,NGraphics。由于这些都是FairyGUI的文件,直接改动的话之后要是更新了,容易导致覆盖,所以我们可以把这些类都改为partial class然后把大部分的逻辑代码都写在外面。

首先,我要解析我们设定的自定义数据,我定的规则如下ShadowOffset:5,5|ShadowAlpha:0.5|ShadowColor:00FF00,| 分割的键值对。新建一个GObject.cs文件,进行自定义数据的解析

using UnityEngine;
using System;

namespace FairyGUI
{
    public partial class GObject : EventDispatcher
	{
        bool mIsCustomShadowOffset = false;
        Vector2 mCustomShadowOffset = Vector2.zero;
        public bool IsCustomShadowOffset
        {
            get { return mIsCustomShadowOffset; }
        }
        public Vector2 CustomShadowOffset
        {
            get { return mCustomShadowOffset; }
        }

        bool mIsCustomShadowColor = false;
        Color mCustomShadowColor = Color.black;
        public bool IsCustomShadowColor
        {
            get { return mIsCustomShadowColor; }
        }
        public Color CustomShadowColor
        {
            get { return mCustomShadowColor; }
        }

        bool mIsCustomShadowAlpha = false;
        float mCustomShadowAlpha = 1f;
        public bool IsCustomShadowAlpha
        {
            get { return mIsCustomShadowAlpha; }
        }
        public float CustomShadowAlpha
        {
            get { return mCustomShadowAlpha; }
        }

        //call in AnalyUserDefineData
        public virtual void CustomAction()
        {

        }

        //call in Setup_AfterAdd
        public void AnalyUserDefineData(object data)
        {
            if (data != null && !"".Equals(data.ToString()))
            {
                string[] args = data.ToString().Split('|');
                foreach(string arg in args)
                {
                    string[] keyvalue = arg.Split(':');
                    if (keyvalue.Length != 2)
                    {
                        continue;
                    }
                    if (keyvalue[0].Equals("ShadowOffset"))
                    {
                        mIsCustomShadowOffset = true;
                        string[] array = keyvalue[1].Split(',');
                        mCustomShadowOffset = new Vector2(float.Parse(array[0]), float.Parse(array[1]));
                    }
                    if (keyvalue[0].Equals("ShadowColor"))
                    {
                        mIsCustomShadowColor = true;
                        mCustomShadowColor = GetColorByHex(keyvalue[1]);
                    }
                    if (keyvalue[0].Equals("ShadowAlpha"))
                    {
                        mIsCustomShadowAlpha = true;
                        mCustomShadowAlpha = float.Parse(keyvalue[1]);
                    }
                }

                if (mIsCustomShadowAlpha && mIsCustomShadowColor)
                {
                    mCustomShadowColor.a = mCustomShadowAlpha;
                }

                CustomAction();
            }
        }

        //format:FF000
        Color GetColorByHex(string v)
        {
            if(v.Length == 6)
            {
                try
                {
                    float r = Convert.ToInt32($"{v[0]}{v[1]}", 16) / 255.0f;
                    float g = Convert.ToInt32($"{v[2]}{v[3]}", 16) / 255.0f;
                    float b = Convert.ToInt32($"{v[4]}{v[5]}", 16) / 255.0f;
                    return new Color(r, g, b);
                }
                catch
                {
                    return Color.black;
                }
            }
            return Color.black;
        }
    }
}

其中CustomAction在解析数据后操作,具体实现方式会在后面的GImage和GTextField中实现,主要是将解析出来的信息,再次赋值给子类的其他数据。

然后在FairyGUI的GObject的Setup_AfterAdd方法的最后进行调用

AnalyUserDefineData(this.data);

这样就可以获取到每个GObject的投影信息了。拿到投影信息后,我们就要去修改组件的绘制过程了,首先从最简单的文本信息添加投影透明度开始。

新建一个GTextField.cs文件,然后修改GTextField.strokeColor即可。如下:

using UnityEngine;

namespace FairyGUI
{
    public partial class GTextField : GObject, ITextColorGear
    {
        //call in CustomAction
        void InitCustomSetting()
        {
            if (IsCustomShadowOffset)
            {
                
                this.shadowOffset = CustomShadowOffset;
            }
            if (IsCustomShadowColor)
            {
                this.strokeColor = CustomShadowColor;
            }
            else
            {
                if (IsCustomShadowAlpha)
                {
                    Color c = this.strokeColor;
                    c.a = CustomShadowAlpha;
                    this.strokeColor = c;
                }
            }
        }

        public override void CustomAction()
        {
            InitCustomSetting();
        }
    }
}

效果如下

我们在FairyGUI中设置两个带投影的文本,第一个绿色投影,第二个红色投影,其中第二个的自定义数据为ShadowAlpha:0.5|ShadowColor:00FF00

发布后在Unity的效果如下(color和alpha都生效了)

接着是比较复杂的图片投影的处理,现在只处理了九宫格图和普通图片的投影效果,具体代码大家自己看下,这边就贴下改动代码。

首先创建NGraphics.cs文件,用于纪录投影信息(文本的有这些字段如GTextField.shadowOffset和GTextField.strokeColor),图片的需要我们自己创建

using System.Collections.Generic;
using UnityEngine;

namespace FairyGUI
{
    public partial class NGraphics : IMeshFactory
    {
        bool mIsCustomShadowOffset = false;
        Vector2 mCustomShadowOffset = Vector2.zero;
        Color mCustomShadowColor = Color.black;

        //call in GImage CustomAction
        public void InitCustomShadow(Vector2 offset, Color c)
        {
            mIsCustomShadowOffset = true;
            mCustomShadowOffset = offset;
            mCustomShadowColor = c;
        }

        //call in NGraphics OnPopulateMesh
        //call in Image SliceFill
        public bool AddCustomShadow(VertexBuffer vb)
        {
            if (mIsCustomShadowOffset)
            {
                VertexBuffer vb2 = VertexBuffer.Begin();
                List<Vector3> vertList2 = vb2.vertices;
#if UNITY_5_2 || UNITY_5_3_OR_NEWER
                List<Vector4> uvList2 = vb2.uv0;
#else
                List<Vector2> uvList2 = vb2.uv0;
#endif
                List<Color32> colList2 = vb2.colors;

                for (int i = 0; i < vb.vertices.Count; i++)
                {
                    Vector3 vert = vb.vertices[i];
                    Vector4 u = vb.uv0[i];

                    uvList2.Add(u);
                    vertList2.Add(new Vector3(vert.x + mCustomShadowOffset.x, vert.y - mCustomShadowOffset.y, 0));
                    colList2.Add(mCustomShadowColor);
                }
                vb.Insert(vb2);
                vb2.End();
                return true;
            }
            return false;
        }
    }
}

然后创建GImage.cs,将GObject的信息传递到NGraphics中,即调用上面的InitCustomShadow方法。

namespace FairyGUI
{
    public partial class GImage : GObject, IColorGear
    {
        public override void CustomAction()
        {
            if (IsCustomShadowOffset)
            {
                _content.graphics.InitCustomShadow(CustomShadowOffset, CustomShadowColor);
            }
        }
    }
}

然后我们需要在两个地方添加投影的逻辑,即调用NGraphics的AddCustomShadow方法。普通图片在NGraphics的OnPopulateMesh方法中调用

public partial class NGraphics : IMeshFactory
{
    ...

    public void OnPopulateMesh(VertexBuffer vb)
    {
        Rect rect = texture.GetDrawRect(vb.contentRect);

        vb.AddQuad(rect, vb.vertexColor, vb.uvRect);

        AddCustomShadow(vb);

        vb.AddTriangles();
        vb._isArbitraryQuad = vertexMatrix != null;
    }
}

九宫格图片在Image的SliceFill方法中调用

public class Image : DisplayObject, IMeshFactory
{
		public void SliceFill(VertexBuffer vb)
		{
				for (int pi = 0; pi < 9; pi++)
				{
					...
				}

                if (graphics.AddCustomShadow(vb))
                {
                    vb.AddTriangles(TRIANGLES_9_GRID);
                    vb.AddTriangles(TRIANGLES_9_GRID, 16);
                }
                else
                {
                    vb.AddTriangles(TRIANGLES_9_GRID);
                }

                vb.AddTriangles();
		}
}

效果图如下(紫色的添加了投影的设置 ShadowAlpha:0.5|ShadowColor:00FF00|ShadowOffset:5,5)

最后除了图片和文本外,可能一些自定义的组件我们也需要投影,但是组件内部有很多的元素,一个个添加可能会太麻烦,所以我们可以在GComponent中,若父组件有设置投影信息,而子组件没有,则自动继承下去。

新建一个GComponent.cs文件,里面添加一个方法,用于递归继承自定义数据(GComponent的子组件也可能是GComponent)

using System;
#if FAIRYGUI_TOLUA
using LuaInterface;
#endif

namespace FairyGUI
{
    /// <summary>
    /// Component
    /// </summary>
    public partial class GComponent : GObject
    {
        //call in ConstructFromResource, after child.Setup_BeforeAdd(buffer, curPos);
        void AnalyUserDefineDataToChild(GObject obj)
        {
            if (obj.data != null)
            {
                GComponent com = obj as GComponent;
                if (com != null)
                {
                    GObject[] array = com.GetChildren();
                    for (int j = 0; j < array.Length; j++)
                    {
                        if (array[j].data == null)
                        {
                            GComponent childCom = array[j] as GComponent;
                            if (childCom != null)
                            {
                                array[j].data = obj.data;
                                //if child is GComponent,for example GList, recursion 
                                AnalyUserDefineDataToChild(array[j]);
                            }
                            else
                            {
                                array[j].AnalyUserDefineData(obj.data);
                            }
                        }
                    }
                }
            }
        }
    }
}

最后我们在GComponent的ConstructFromResource方法中调用即可。

public partial class GComponent : GObject
{
	.....

	internal void ConstructFromResource(List<GObject> objectPool, int poolIndex)
	{
		......

		child.underConstruct = true;
		child.Setup_BeforeAdd(buffer, curPos);

        AnalyUserDefineDataToChild(child);

        child.InternalSetParent(this);
		_children.Add(child);

		buffer.position = curPos + dataLen;

		......
    }

	......
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值