项目中有个新手引导,要求做一个圆圈,中间透明,四周黑色,取一定的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的一样,代码是一样的
文章原创,想要转载的请注明转载字样和本地址链接,谢谢
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/suifcd/article/details/46779657