关闭

NGUI九宫格反向切割拉伸

标签: unityNGUI九宫格slice反向
1198人阅读 评论(0) 收藏 举报
分类:

项目中有个新手引导,要求做一个圆圈,中间透明,四周黑色,取一定的Alpha值,由于游戏设定分辨率为1136*640,只是一个圆圈,如果使用大图的话未免浪费,而且由于新手引导是有策划配置修改,用大图的话也不是很灵活,一开始想到使用小图拼接加Anchor的方式,拼出来后电脑上一看,还不错,导包,放到手机上,各种缝隙。

没办法,此路不通,换个思路吧。

想到了NGUI中的九宫格切割sliced,想想自己可不可以这样做呢,不多说,试一下,结果刚好反掉了,我要的是中间不动,四周拉伸的效果,但是NGUI的是中间拉伸,四边不动试着调了下border,不行。

能不能改成中见不到,四周拉伸的效果呢。

以前逛过NGUI官方论坛,作者还是很热心的,基本每帖必回,本着不重复造轮子的原则,去看看,应该不会只有我一个人有这样的想法吧。

还真找到了帖子,但是先别高兴,作者说自己搞,这就是NGUI为什么开源的原因。心瞬间凉了,往下看,提问者说自己写好了,有点希望啊,但是由于项目原因不能公布。能不能不要这么打击我。。。

好吧,自己动手,丰衣足食。

查下NGUI的源代码,看看是如何实现的,能不能改动,代码如下

/// <summary>
    /// Sliced sprite fill function is more complicated as it generates 9 quads instead of 1.
    /// </summary>

    public virtual void SlicedFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
    {
        Vector4 br = border * pixelSize;

        if (br.x == 0f && br.y == 0f && br.z == 0f && br.w == 0f)
        {
            SimpleFill(verts, uvs, cols);
            return;
        }

        Color32 c = drawingColor;
        Vector4 v = drawingDimensions;

        mTempPos[0].x = v.x;
        mTempPos[0].y = v.y;
        mTempPos[3].x = v.z;
        mTempPos[3].y = v.w;

        if (mFlip == Flip.Horizontally || mFlip == Flip.Both)
        {
            mTempPos[1].x = mTempPos[0].x + br.z;
            mTempPos[2].x = mTempPos[3].x - br.x;

            mTempUVs[3].x = mOuterUV.xMin;
            mTempUVs[2].x = mInnerUV.xMin;
            mTempUVs[1].x = mInnerUV.xMax;
            mTempUVs[0].x = mOuterUV.xMax;
        }
        else
        {
            mTempPos[1].x = mTempPos[0].x + br.x;
            mTempPos[2].x = mTempPos[3].x - br.z;

            mTempUVs[0].x = mOuterUV.xMin;
            mTempUVs[1].x = mInnerUV.xMin;
            mTempUVs[2].x = mInnerUV.xMax;
            mTempUVs[3].x = mOuterUV.xMax;
        }

        if (mFlip == Flip.Vertically || mFlip == Flip.Both)
        {
            mTempPos[1].y = mTempPos[0].y + br.w;
            mTempPos[2].y = mTempPos[3].y - br.y;

            mTempUVs[3].y = mOuterUV.yMin;
            mTempUVs[2].y = mInnerUV.yMin;
            mTempUVs[1].y = mInnerUV.yMax;
            mTempUVs[0].y = mOuterUV.yMax;
        }
        else
        {
            mTempPos[1].y = mTempPos[0].y + br.y;
            mTempPos[2].y = mTempPos[3].y - br.w;

            mTempUVs[0].y = mOuterUV.yMin;
            mTempUVs[1].y = mInnerUV.yMin;
            mTempUVs[2].y = mInnerUV.yMax;
            mTempUVs[3].y = mOuterUV.yMax;
        }

        for (int x = 0; x < 3; ++x)
        {
            int x2 = x + 1;

            for (int y = 0; y < 3; ++y)
            {
                if (centerType == AdvancedType.Invisible && x == 1 && y == 1) continue;

                int y2 = y + 1;

                verts.Add(new Vector3(mTempPos[x].x, mTempPos[y].y));
                verts.Add(new Vector3(mTempPos[x].x, mTempPos[y2].y));
                verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y2].y));
                verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y].y));

                uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y].y));
                uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y2].y));
                uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y2].y));
                uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y].y));

                cols.Add(c);
                cols.Add(c);
                cols.Add(c);
                cols.Add(c);
            }
        }
    }

这段代码是UIBasicSprite.cs里面的代码,也是九宫格切割的关键代码,看了下,关键是如何取顶点,大家可以看下自己切割图片,共有顶点数十六个,我们其中四个顶点是固定的就是图片的四个顶点,还有十二个根据用户定义的border和图片大小dimions。知道了原理,OK,画图,开干。

。。。。。。

画了几张图,简单的计算了下,然后写入代码,调试。

直接上代码吧

代码改自UITexture.cs,由于一些权限问题,修改了部分源代码,这个行为不太好。全部复制,只改了上面提到的函数

//----------------------------------------------
//       UITextureCustom     UITextureCustomInspector
// 与NGUI图片中的九宫格(四边不动,缩放中间)相反,此脚本所在的图片精灵,四边缩放,中间不动
//使用此脚本,需将UIBasicSprite里的mInnerUV,mOuterUV,drawingColor等权限设为proteced,
//将函数SlicedFill设为虚函数,将函数SimpleFill权限设为protected
//  author:lin
// 只要有自然,人就没有自暴自弃的理由
//----------------------------------------------

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// If you don't have or don't wish to create an atlas, you can simply use this script to draw a texture.
/// Keep in mind though that this will create an extra draw call with each UITexture present, so it's
/// best to use it only for backgrounds or temporary visible widgets.
/// </summary>

[ExecuteInEditMode]
[AddComponentMenu("NGUI/UI/NGUI TextureCustom")]
public class UITextureCustom : UIBasicSprite
{
    [HideInInspector][SerializeField] Rect mRect = new Rect(0f, 0f, 1f, 1f);
    [HideInInspector][SerializeField] Texture mTexture;
    [HideInInspector][SerializeField] Material mMat;
    [HideInInspector][SerializeField] Shader mShader;
    [HideInInspector][SerializeField] Vector4 mBorder = Vector4.zero;

    [System.NonSerialized] int mPMA = -1;

    /// <summary>
    /// Texture used by the UITexture. You can set it directly, without the need to specify a material.
    /// </summary>

    public override Texture mainTexture
    {
        get
        {
            if (mTexture != null) return mTexture;
            if (mMat != null) return mMat.mainTexture;
            return null;
        }
        set
        {
            if (mTexture != value)
            {
                if (drawCall != null && drawCall.widgetCount == 1 && mMat == null)
                {
                    mTexture = value;
                    drawCall.mainTexture = value;
                }
                else
                {
                    RemoveFromPanel();
                    mTexture = value;
                    mPMA = -1;
                    MarkAsChanged();
                }
            }
        }
    }

    /// <summary>
    /// Material used by the widget.
    /// </summary>

    public override Material material
    {
        get
        {
            return mMat;
        }
        set
        {
            if (mMat != value)
            {
                RemoveFromPanel();
                mShader = null;
                mMat = value;
                mPMA = -1;
                MarkAsChanged();
            }
        }
    }

    /// <summary>
    /// Shader used by the texture when creating a dynamic material (when the texture was specified, but the material was not).
    /// </summary>

    public override Shader shader
    {
        get
        {
            if (mMat != null) return mMat.shader;
            if (mShader == null) mShader = Shader.Find("Unlit/Transparent Colored");
            return mShader;
        }
        set
        {
            if (mShader != value)
            {
                if (drawCall != null && drawCall.widgetCount == 1 && mMat == null)
                {
                    mShader = value;
                    drawCall.shader = value;
                }
                else
                {
                    RemoveFromPanel();
                    mShader = value;
                    mPMA = -1;
                    mMat = null;
                    MarkAsChanged();
                }
            }
        }
    }

    /// <summary>
    /// Whether the texture is using a premultiplied alpha material.
    /// </summary>

    public override bool premultipliedAlpha
    {
        get
        {
            if (mPMA == -1)
            {
                Material mat = material;
                mPMA = (mat != null && mat.shader != null && mat.shader.name.Contains("Premultiplied")) ? 1 : 0;
            }
            return (mPMA == 1);
        }
    }


    /// <summary>
    /// Sprite's border. X = left, Y = bottom, Z = right, W = top.
    /// </summary>

    public override Vector4 border
    {
        get
        {
            return mBorder;
        }
        set
        {
            if (mBorder != value)
            {
                mBorder = value;
                MarkAsChanged();
            }
        }
    }

    /// <summary>
    /// UV rectangle used by the texture.
    /// </summary>

    public Rect uvRect
    {
        get
        {
            return mRect;
        }
        set
        {
            if (mRect != value)
            {
                mRect = value;
                MarkAsChanged();
            }
        }
    }

    /// <summary>
    /// Widget's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
    /// This function automatically adds 1 pixel on the edge if the texture's dimensions are not even.
    /// It's used to achieve pixel-perfect sprites even when an odd dimension widget happens to be centered.
    /// </summary>

    public override Vector4 drawingDimensions
    {
        get
        {
            Vector2 offset = pivotOffset;

            float x0 = -offset.x * mWidth;
            float y0 = -offset.y * mHeight;
            float x1 = x0 + mWidth;
            float y1 = y0 + mHeight;

            if (mTexture != null && mType != UISprite.Type.Tiled)
            {
                int w = mTexture.width;
                int h = mTexture.height;
                int padRight = 0;
                int padTop = 0;

                float px = 1f;
                float py = 1f;

                if (w > 0 && h > 0 && (mType == UISprite.Type.Simple || mType == UISprite.Type.Filled))
                {
                    if ((w & 1) != 0) ++padRight;
                    if ((h & 1) != 0) ++padTop;

                    px = (1f / w) * mWidth;
                    py = (1f / h) * mHeight;
                }

                if (mFlip == UISprite.Flip.Horizontally || mFlip == UISprite.Flip.Both)
                {
                    x0 += padRight * px;
                }
                else x1 -= padRight * px;

                if (mFlip == UISprite.Flip.Vertically || mFlip == UISprite.Flip.Both)
                {
                    y0 += padTop * py;
                }
                else y1 -= padTop * py;
            }

            Vector4 br = border;

            float fw = br.x + br.z;
            float fh = br.y + br.w;
            float vx = Mathf.Lerp(x0, x1 - fw, mDrawRegion.x);
            float vy = Mathf.Lerp(y0, y1 - fh, mDrawRegion.y);
            float vz = Mathf.Lerp(x0 + fw, x1, mDrawRegion.z);
            float vw = Mathf.Lerp(y0 + fh, y1, mDrawRegion.w);

            return new Vector4(vx, vy, vz, vw);
        }
    }

    /// <summary>
    /// Adjust the scale of the widget to make it pixel-perfect.
    /// </summary>

    public override void MakePixelPerfect ()
    {
        base.MakePixelPerfect();
        if (mType == Type.Tiled) return;

        Texture tex = mainTexture;
        if (tex == null) return;

        if (mType == Type.Simple || mType == Type.Filled || !hasBorder)
        {
            if (tex != null)
            {
                int w = tex.width;
                int h = tex.height;

                if ((w & 1) == 1) ++w;
                if ((h & 1) == 1) ++h;

                width = w;
                height = h;
            }
        }
    }

    /// <summary>
    /// Virtual function called by the UIPanel that fills the buffers.
    /// </summary>

    public override void OnFill (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
    {
        Texture tex = mainTexture;
        if (tex == null) return;

        Rect outer = new Rect(mRect.x * tex.width, mRect.y * tex.height, tex.width * mRect.width, tex.height * mRect.height);
        Rect inner = outer;
        Vector4 br = border;
        inner.xMin += br.x;
        inner.yMin += br.y;
        inner.xMax -= br.z;
        inner.yMax -= br.w;

        float w = 1f / tex.width;
        float h = 1f / tex.height;

        outer.xMin *= w;
        outer.xMax *= w;
        outer.yMin *= h;
        outer.yMax *= h;

        inner.xMin *= w;
        inner.xMax *= w;
        inner.yMin *= h;
        inner.yMax *= h;
        int offset = verts.size;
        Fill(verts, uvs, cols, outer, inner);

        if (onPostFill != null)
            onPostFill(this, offset, verts, uvs, cols);
    }

    public override void SlicedFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
    {
        Vector4 br = border * pixelSize;

        if (br.x == 0f && br.y == 0f && br.z == 0f && br.w == 0f)
        {
            SimpleFill(verts, uvs, cols);
            return;
        }

        Color32 c = drawingColor;
       // Color32 c = Color.white;

        Vector4 v = drawingDimensions;

        mTempPos[0].x = v.x;
        mTempPos[0].y = v.y;
        mTempPos[3].x = v.z;
        mTempPos[3].y = v.w;

        /// <summary>
    /// Sprite's border. X = left, Y = bottom, Z = right, W = top.
    /// </summary>
        Vector4 constentSize = Vector4.zero;
        constentSize.x = (Mathf.Abs(mTempPos[3].x - mTempPos[0].x) - (mTexture.width - br.x - br.z)) * (br.x / (float)(br.x + br.z));
        constentSize.y = (Mathf.Abs(mTempPos[3].y - mTempPos[0].y) - (mTexture.height - br.y - br.w)) * (br.y / (float)(br.y + br.w));
        constentSize.z = (Mathf.Abs(mTempPos[3].x - mTempPos[0].x) - (mTexture.width - br.x - br.z)) * (br.z / (float)(br.x + br.z));
        constentSize.w = (Mathf.Abs(mTempPos[3].y - mTempPos[0].y) - (mTexture.height - br.y - br.w)) * (br.w / (float)(br.y + br.w));

        if (mFlip == Flip.Horizontally || mFlip == Flip.Both)
        {
            //mTempPos[1].x = mTempPos[0].x + br.z;
            //mTempPos[2].x = mTempPos[3].x - br.x;
            mTempPos[1].x = mTempPos[0].x + constentSize.z;
            mTempPos[2].x = mTempPos[3].x - constentSize.x;

            mTempUVs[3].x = mOuterUV.xMin;
            mTempUVs[2].x = mInnerUV.xMin;
            mTempUVs[1].x = mInnerUV.xMax;
            mTempUVs[0].x = mOuterUV.xMax;
        }
        else
        {
            //mTempPos[1].x = mTempPos[0].x + br.x;
            //mTempPos[2].x = mTempPos[3].x - br.z;
            mTempPos[1].x = mTempPos[0].x + constentSize.x;
            mTempPos[2].x = mTempPos[3].x - constentSize.z;

            mTempUVs[0].x = mOuterUV.xMin;
            mTempUVs[1].x = mInnerUV.xMin;
            mTempUVs[2].x = mInnerUV.xMax;
            mTempUVs[3].x = mOuterUV.xMax;
        }

        if (mFlip == Flip.Vertically || mFlip == Flip.Both)
        {
            //mTempPos[1].y = mTempPos[0].y + br.w;
            //mTempPos[2].y = mTempPos[3].y - br.y;
            mTempPos[1].y = mTempPos[0].y + constentSize.w;
            mTempPos[2].y = mTempPos[3].y - constentSize.y;

            mTempUVs[3].y = mOuterUV.yMin;
            mTempUVs[2].y = mInnerUV.yMin;
            mTempUVs[1].y = mInnerUV.yMax;
            mTempUVs[0].y = mOuterUV.yMax;
        }
        else
        {
            //mTempPos[1].y = mTempPos[0].y + br.y;
            //mTempPos[2].y = mTempPos[3].y - br.w;
            mTempPos[1].y = mTempPos[0].y + constentSize.y;
            mTempPos[2].y = mTempPos[3].y - constentSize.w;

            mTempUVs[0].y = mOuterUV.yMin;
            mTempUVs[1].y = mInnerUV.yMin;
            mTempUVs[2].y = mInnerUV.yMax;
            mTempUVs[3].y = mOuterUV.yMax;
        }

        for (int x = 0; x < 3; ++x)
        {
            int x2 = x + 1;

            for (int y = 0; y < 3; ++y)
            {
                if (centerType == AdvancedType.Invisible && x == 1 && y == 1) continue;

                int y2 = y + 1;
                //Debug.Log("------------------------>");
                verts.Add(new Vector3(mTempPos[x].x, mTempPos[y].y));
                verts.Add(new Vector3(mTempPos[x].x, mTempPos[y2].y));
                verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y2].y));
                verts.Add(new Vector3(mTempPos[x2].x, mTempPos[y].y));
                //Debug.Log(mTempPos[x].x + " " + mTempPos[y].y);
                //Debug.Log(mTempPos[x].x + " " + mTempPos[y2].y);
                //Debug.Log(mTempPos[x2].x + " " + mTempPos[y2].y);
                //Debug.Log(mTempPos[x2].x + " " + mTempPos[y].y);

                uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y].y));
                uvs.Add(new Vector2(mTempUVs[x].x, mTempUVs[y2].y));
                uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y2].y));
                uvs.Add(new Vector2(mTempUVs[x2].x, mTempUVs[y].y));

                cols.Add(c);
                cols.Add(c);
                cols.Add(c);
                cols.Add(c);
            }
        }
    }
}

下面是对应的编辑器代码,ctrl+d,哈哈

//----------------------------------------------
//       UITextureCustom     
// 与NGUI图片中的九宫格(四边不动,缩放中间)相反,此脚本所在的图片精灵,四边缩放,中间不动
//  author:lin
// 只要有自然,人就没有自暴自弃的理由
//----------------------------------------------

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

/// <summary>
/// Inspector class used to edit UITextures.
/// </summary>

[CanEditMultipleObjects]
[CustomEditor(typeof(UITextureCustom), true)]
public class UITextureCustomInspector : UIBasicSpriteEditor
{
    UITextureCustom mTex;

    protected override void OnEnable ()
    {
        base.OnEnable();
        mTex = target as UITextureCustom;
    }

    protected override bool ShouldDrawProperties ()
    {
        if (target == null) return false;
        SerializedProperty sp = NGUIEditorTools.DrawProperty("Texture", serializedObject, "mTexture");
        NGUIEditorTools.DrawProperty("Material", serializedObject, "mMat");

        if (sp != null) NGUISettings.texture = sp.objectReferenceValue as Texture;

        if (mTex != null && (mTex.material == null || serializedObject.isEditingMultipleObjects))
        {
            NGUIEditorTools.DrawProperty("Shader", serializedObject, "mShader");
        }

        EditorGUI.BeginDisabledGroup(mTex == null || mTex.mainTexture == null || serializedObject.isEditingMultipleObjects);

        NGUIEditorTools.DrawRectProperty("UV Rect", serializedObject, "mRect");

        EditorGUI.EndDisabledGroup();
        return true;
    }

    /// <summary>
    /// Allow the texture to be previewed.
    /// </summary>

    public override bool HasPreviewGUI ()
    {
        return (Selection.activeGameObject == null || Selection.gameObjects.Length == 1) &&
            (mTex != null) && (mTex.mainTexture as Texture2D != null);
    }

    /// <summary>
    /// Draw the sprite preview.
    /// </summary>

    public override void OnPreviewGUI (Rect rect, GUIStyle background)
    {
        Texture2D tex = mTex.mainTexture as Texture2D;

        if (tex != null)
        {
            Rect tc = mTex.uvRect;
            tc.xMin *= tex.width;
            tc.xMax *= tex.width;
            tc.yMin *= tex.height;
            tc.yMax *= tex.height;
            NGUIEditorTools.DrawSprite(tex, rect, mTex.color, tc, mTex.border);
        }
    }
}

OK,怎么用,很简单,和UITexture一样,挂上去,sliced,设置border,size,其实还可以配合scale有更换的体验哦。

要改UISprite.cs的一样,代码是一样的

文章原创,想要转载的请注明转载字样和本地址链接,谢谢

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:88206次
    • 积分:1336
    • 等级:
    • 排名:千里之外
    • 原创:34篇
    • 转载:79篇
    • 译文:0篇
    • 评论:12条