在一張圖裏摳個洞出來,可以仿照Image的Sliced模式來做
public class ImageWithHole : Image
{
public Vector2 Center = Vector2.zero;
public float Height = 200;
public float Width = 100;
static readonly Vector2[] s_VertScratch = new Vector2[4];
static readonly Vector2[] s_UVScratch = new Vector2[4];
protected override void OnPopulateMesh(VertexHelper toFill)
{
Vector4 outer, inner, padding;
if (sprite != null)
{
outer = UnityEngine.Sprites.DataUtility.GetOuterUV(sprite);
inner = UnityEngine.Sprites.DataUtility.GetInnerUV(sprite);
padding = UnityEngine.Sprites.DataUtility.GetPadding(sprite);
}
else
{
outer = Vector4.zero;
inner = Vector4.zero;
padding = Vector4.zero;
}
Rect rect = GetPixelAdjustedRect();
padding = padding / pixelsPerUnit;
s_VertScratch[0] = new Vector2(padding.x, padding.y);
s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);
s_VertScratch[0].x += rect.x;
s_VertScratch[0].y += rect.y;
s_VertScratch[3].x += rect.x;
s_VertScratch[3].y += rect.y;
s_VertScratch[1].x = Center.x - Width / 2;
s_VertScratch[1].y = Center.y - Height / 2;
s_VertScratch[2].x = Center.x + Width / 2;
s_VertScratch[2].y = Center.y + Height / 2;
s_UVScratch[0] = new Vector2(outer.x, outer.y);
s_UVScratch[1] = new Vector2(inner.x, inner.y);
s_UVScratch[2] = new Vector2(inner.z, inner.w);
s_UVScratch[3] = new Vector2(outer.z, outer.w);
toFill.Clear();
for (int x = 0; x < 3; ++x)
{
int x2 = x + 1;
for (int y = 0; y < 3; ++y)
{
if (x == 1 && y == 1)
continue;
int y2 = y + 1;
AddQuad(toFill,
new Vector2(s_VertScratch[x].x, s_VertScratch[y].y),
new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y),
color,
new Vector2(s_UVScratch[x].x, s_UVScratch[y].y),
new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y));
}
}
}
private Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect)
{
Rect originalRect = rectTransform.rect;
for (int axis = 0; axis <= 1; axis++)
{
float borderScaleRatio;
if (originalRect.size[axis] != 0)
{
borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis];
border[axis] *= borderScaleRatio;
border[axis + 2] *= borderScaleRatio;
}
float combinedBorders = border[axis] + border[axis + 2];
if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0)
{
borderScaleRatio = adjustedRect.size[axis] / combinedBorders;
border[axis] *= borderScaleRatio;
border[axis + 2] *= borderScaleRatio;
}
}
return border;
}
static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax)
{
int startIndex = vertexHelper.currentVertCount;
vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y));
vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y));
vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y));
vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y));
vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
}
}
上個效果圖:
以上效果只摳了直角四邊形,顯然活潑跳躍的策劃很不滿足,於是要求我做個能圓角的,這樣可以契合圓角UI,於是就有了以下代碼:
public float Radius = 0;
[Range(1, 20)]
public int TriangleNum = 0;
private void RoundRect(VertexHelper vh)
{
var color32 = color;
Vector4 v = new Vector4(
-Width / 2,
-Height / 2,
Width / 2,
Height / 2
);
Vector4 uv = overrideSprite != null ? UnityEngine.Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
float tw = v.z - v.x;
float th = v.w - v.y;
float uvScaleX = (uv.z - uv.x) / tw;
float uvScaleY = (uv.w - uv.y) / th;
float uvCenterX = (uv.x + uv.z) * 0.5f;
float uvCenterY = (uv.y + uv.w) * 0.5f;
//對radius的值做限制,必須在0-較小的邊的1/2的範圍內
float radius = Radius;
if (radius > (v.z - v.x) / 2)
radius = (v.z - v.x) / 2;
if (radius > (v.w - v.y) / 2)
radius = (v.w - v.y) / 2;
if (radius < 0)
radius = 0;
float pos0 = 0;
float pos1 = 0;
//開始構造四個角
List<Vector2> vCenterList = new List<Vector2>();
List<int> vCenterVertList = new List<int>();
//右上角的圓心
pos0 = v.z - radius + Center.x;
pos1 = v.w - radius + Center.y;
vCenterList.Add(new Vector2(pos0, pos1));
vCenterVertList.Add(25);
//左上角的圓心
pos0 = v.x + radius + Center.x;
pos1 = v.w - radius + Center.y;
vCenterList.Add(new Vector2(pos0, pos1));
vCenterVertList.Add(6);
//左下角的圓心
//左上角的圓心
pos0 = v.x + radius + Center.x;
pos1 = v.y + radius + Center.y;
vCenterList.Add(new Vector2(pos0, pos1));
vCenterVertList.Add(2);
//右下角的圓心
pos0 = v.z - radius + Center.x;
pos1 = v.y + radius + Center.y;
vCenterList.Add(new Vector2(pos0, pos1));
vCenterVertList.Add(14);
//每個三角形的頂角
float degreeDelta = (float)(Mathf.PI / 2 / TriangleNum);
//當前的角度
float curDegree = 0;
for (int i = 0; i < vCenterVertList.Count; i++)
{
int preVertNum = vh.currentVertCount;
for (int j = 0; j <= TriangleNum; j++)
{
float cosA = Mathf.Cos(curDegree);
float sinA = Mathf.Sin(curDegree);
pos0 = vCenterList[i].x + cosA * radius;
pos1 = vCenterList[i].y + sinA * radius;
Vector3 vPosition = new Vector3(pos0, pos1);
Vector2 uvPosition = new Vector2(pos0 * uvScaleX + uvCenterX, pos1 * uvScaleY + uvCenterY);
vh.AddVert(vPosition, color32, uvPosition);
curDegree += degreeDelta;
}
curDegree -= degreeDelta;
for (int j = 0; j <= TriangleNum - 1; j++)
{
vh.AddTriangle(vCenterVertList[i], preVertNum + j + 1, preVertNum + j);
}
}
}
這段加上以後,可以玩新花樣: