在白色方块写shader并且挂载
登录后复制
Shader "Custom/NewSurfaceShader"
{
SubShader
{
ZWrite on
ZTest Always
Pass{
Color(1,1,1,1)
}
}
}
看到的效果是这样的
如果3D物体用OnMouseDown()方法的话可能会UI (IPointerClickHandler接口) 和3D物体都会被触发
如果吧3D物体上添加一个IPointerClickHandler方法接口 并且在MainCamera上挂载PhysicsRaycaster脚本
方法写在OnPointerClick接口实现的方法就避免了
如果还想让他一起触发的话就要写代码到UI层了
登录后复制
public void OnPointerClick(PointerEventData eventData)
{
ChangeColor();
ExcuteAll(eventData);
}
public void ExcuteAll(PointerEventData eventData)
{
//点击的目标物体
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, results);
foreach (RaycastResult result in results)
{
//如果被点击的物体和我们的UI不一样
if (result.gameObject != gameObject)
{
ExecuteEvents.Execute(result.gameObject, eventData, ExecuteEvents.pointerClickHandler);
}
}
}
UI的另一种写法
登录后复制
void Start()
{
_raycaster = FindObjectOfType<GraphicRaycaster>();
}
void Update()
{
if (Input.GetMouseButtonDown(0) && IsUI())
{
///TODO 改变颜色
}
}
public bool IsUI()
{
PointerEventData data = new PointerEventData(EventSystem.current);
data.position = Input.mousePosition;
data.pressPosition = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
_raycaster.Raycast(data, results);
return results.Count > 0;
}
新建代码OnCircletImage 挂载在Canvas下面的空物体上打开代码继承Image 。
重写父类的 PopulateMesh 方法
以为UV是四维数组 xyzw 理解是话是从下面的图片理解的
要保证传入的点是顺时针方向 i ,0 ,i+1
登录后复制
using UnityEngine.UI;
using UnityEngine.Sprites;
using UnityEngine;
#region 圆圈遮住效果
// public class CircletImage : Image
// {
// [SerializeField]
// // 多少份三角形 拼成的圆形
// int segements = 100;
// //显示部分占圆形的百分比
// [SerializeField]
// float showPercent = 0.5f;
// //需要绘制的顶点面片数据都存在了vh
// protected override void OnPopulateMesh(VertexHelper vh)
// {
// vh.Clear();
// float width = rectTransform.rect.width;
// float height = rectTransform.rect.height;
// int realsegments = (int)(segements * showPercent);
// //先 引入 using UnityEngine.Sprites; 命名空间 再获取图片的外层的UV
// //最好使用父类的overrideSprite 不使用sprite 具体因为啥我也不知道
// Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
// float uvWidth = (uv.z - uv.x);
// float uvHeight = (uv.w - uv.y);
// //获取UI中心
// Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
// //求出于组件的宽高比
// Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);
// //单个三角形的弧度
// float radian = (2 * Mathf.PI) / segements;
// //获取半径
// float radius = width * 0.5f;
// //有了弧度 有了半径 就能求出 顶点的坐标 通过 Sin Cos 函数
// //生成 顺时针 生成三角形 0 是中心点
// Vector2 posTemp = Vector2.zero;
// UIVertex origin = new UIVertex();
// origin.color = color;
// origin.position = posTemp;
// // 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
// origin.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
// //添加顶点
// vh.AddVert(origin);
// //获取顶点的个数
// int vertexCont = realsegments + 1;
// float curRadian = 0;
// for (int i = 0; i < vertexCont; i++)
// {
// //获取当前的顶点坐标
// float x = Mathf.Cos(curRadian) * radius;
// float y = Mathf.Sin(curRadian) * radius;
// //累加 三角形弧度
// curRadian += radian;
// UIVertex vertexTemp = new UIVertex();
// vertexTemp.color = color;
// // if (i < vertexCont)
// // {
// // vertexTemp.color = color;
// // }
// // else
// // {
// // vertexTemp.color = new Color32(60,60,60,255);
// // }
// posTemp = new Vector2(x, y);
// vertexTemp.position = posTemp;
// // 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
// vertexTemp.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
// vh.AddVert(vertexTemp);
// }
// int id = 1;
// for (int i = 0; i < realsegments; i++)
// {
// //生成 顺时针 生成三角形 0 是中心点 传入三个顶点 三个顶点是i , 0,i+1
// vh.AddTriangle(id, 0, id + 1);
// id++;
// }
// }
// }
#endregion
#region CD 效果
public class CircletImage : Image
{
[SerializeField]
// 多少份三角形 拼成的圆形
int segements = 100;
//显示部分占圆形的百分比
[SerializeField]
float showPercent = 0f;
//需要绘制的顶点面片数据都存在了vh
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
float width = rectTransform.rect.width;
float height = rectTransform.rect.height;
int realsegments = (int)(segements * showPercent);
//先 引入 using UnityEngine.Sprites; 命名空间 再获取图片的外层的UV
//最好使用父类的overrideSprite 不使用sprite 具体因为啥我也不知道
Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
float uvWidth = (uv.z - uv.x);
float uvHeight = (uv.w - uv.y);
//获取UI中心
Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
//求出于组件的宽高比
Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);
//单个三角形的弧度
float radian = (2 * Mathf.PI) / segements;
//获取半径
float radius = width * 0.5f;
//有了弧度 有了半径 就能求出 顶点的坐标 通过 Sin Cos 函数
//生成 顺时针 生成三角形 0 是中心点
Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
Vector2 vertPos = Vector2.zero;
UIVertex origin = new UIVertex();
byte temp = (byte)(255 * showPercent);
origin.color = new Color32(temp, temp, temp, 255);
origin.position = originPos;
// 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
origin.uv0 = new Vector2(vertPos.x * convertRatio.x + uvCenter.x, vertPos.y * convertRatio.y + uvCenter.y);
//添加顶点
vh.AddVert(origin);
//获取顶点的个数
int vertexCont = realsegments + 1;
float curRadian = 0;
Vector2 posTemp;
for (int i = 0; i < segements + 1; i++)
{
//获取当前的顶点坐标
float x = Mathf.Cos(curRadian) * radius;
float y = Mathf.Sin(curRadian) * radius;
//累加 三角形弧度
curRadian += radian;
UIVertex vertexTemp = new UIVertex();
if (i < vertexCont)
{
vertexTemp.color = color;
if (showPercent == 0)
{
vertexTemp.color = new Color32(60, 60, 60, 255);
}
}
else
{
vertexTemp.color = new Color32(60, 60, 60, 255);
}
posTemp = new Vector2(x, y);
vertexTemp.position = posTemp + originPos;
// 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
vertexTemp.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
vh.AddVert(vertexTemp);
}
int id = 1;
for (int i = 0; i < segements; i++)
{
//生成 顺时针 生成三角形 0 是中心点 传入三个顶点 三个顶点是i , 0,i+1
vh.AddTriangle(id, 0, id + 1);
id++;
}
}
}
#endregion
登录后复制
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.Sprites;
using UnityEngine;
#region 圆圈遮住效果
// public class CircletImage : Image
// {
// [SerializeField]
// // 多少份三角形 拼成的圆形
// int segements = 100;
// //显示部分占圆形的百分比
// [SerializeField]
// float showPercent = 0.5f;
// //需要绘制的顶点面片数据都存在了vh
// protected override void OnPopulateMesh(VertexHelper vh)
// {
// vh.Clear();
// float width = rectTransform.rect.width;
// float height = rectTransform.rect.height;
// int realsegments = (int)(segements * showPercent);
// //先 引入 using UnityEngine.Sprites; 命名空间 再获取图片的外层的UV
// //最好使用父类的overrideSprite 不使用sprite 具体因为啥我也不知道
// Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
// float uvWidth = (uv.z - uv.x);
// float uvHeight = (uv.w - uv.y);
// //获取UI中心
// Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
// //求出于组件的宽高比
// Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);
// //单个三角形的弧度
// float radian = (2 * Mathf.PI) / segements;
// //获取半径
// float radius = width * 0.5f;
// //有了弧度 有了半径 就能求出 顶点的坐标 通过 Sin Cos 函数
// //生成 顺时针 生成三角形 0 是中心点
// Vector2 posTemp = Vector2.zero;
// UIVertex origin = new UIVertex();
// origin.color = color;
// origin.position = posTemp;
// // 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
// origin.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
// //添加顶点
// vh.AddVert(origin);
// //获取顶点的个数
// int vertexCont = realsegments + 1;
// float curRadian = 0;
// for (int i = 0; i < vertexCont; i++)
// {
// //获取当前的顶点坐标
// float x = Mathf.Cos(curRadian) * radius;
// float y = Mathf.Sin(curRadian) * radius;
// //累加 三角形弧度
// curRadian += radian;
// UIVertex vertexTemp = new UIVertex();
// vertexTemp.color = color;
// // if (i < vertexCont)
// // {
// // vertexTemp.color = color;
// // }
// // else
// // {
// // vertexTemp.color = new Color32(60,60,60,255);
// // }
// posTemp = new Vector2(x, y);
// vertexTemp.position = posTemp;
// // 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
// vertexTemp.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
// vh.AddVert(vertexTemp);
// }
// int id = 1;
// for (int i = 0; i < realsegments; i++)
// {
// //生成 顺时针 生成三角形 0 是中心点 传入三个顶点 三个顶点是i , 0,i+1
// vh.AddTriangle(id, 0, id + 1);
// id++;
// }
// }
// }
#endregion
#region CD 效果
public class CircletImage : Image
{
[SerializeField]
// 多少份三角形 拼成的圆形
int segements = 100;
//显示部分占圆形的百分比
[SerializeField]
float showPercent = 0f;
// 顶点缓存列表
private List<Vector3> _vertexList=new List<Vector3>();
//需要绘制的顶点面片数据都存在了vh
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
float width = rectTransform.rect.width;
float height = rectTransform.rect.height;
int realsegments = (int)(segements * showPercent);
//先 引入 using UnityEngine.Sprites; 命名空间 再获取图片的外层的UV
//最好使用父类的overrideSprite 不使用sprite 具体因为啥我也不知道
Vector4 uv = overrideSprite != null ? DataUtility.GetOuterUV(overrideSprite) : Vector4.zero;
float uvWidth = (uv.z - uv.x);
float uvHeight = (uv.w - uv.y);
//获取UI中心
Vector2 uvCenter = new Vector2(uvWidth * 0.5f, uvHeight * 0.5f);
//求出于组件的宽高比
Vector2 convertRatio = new Vector2(uvWidth / width, uvHeight / height);
//单个三角形的弧度
float radian = (2 * Mathf.PI) / segements;
//获取半径
float radius = width * 0.5f;
//有了弧度 有了半径 就能求出 顶点的坐标 通过 Sin Cos 函数
//生成 顺时针 生成三角形 0 是中心点
Vector2 originPos = new Vector2((0.5f - rectTransform.pivot.x) * width, (0.5f - rectTransform.pivot.y) * height);
Vector2 vertPos = Vector2.zero;
UIVertex origin = new UIVertex();
byte temp = (byte)(255 * showPercent);
origin.color = new Color32(temp, temp, temp, 255);
origin.position = originPos;
// 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
origin.uv0 = new Vector2(vertPos.x * convertRatio.x + uvCenter.x, vertPos.y * convertRatio.y + uvCenter.y);
//添加顶点
vh.AddVert(origin);
//获取顶点的个数
int vertexCont = realsegments + 1;
float curRadian = 0;
Vector2 posTemp;
for (int i = 0; i < segements + 1; i++)
{
//获取当前的顶点坐标
float x = Mathf.Cos(curRadian) * radius;
float y = Mathf.Sin(curRadian) * radius;
//累加 三角形弧度
curRadian += radian;
UIVertex vertexTemp = new UIVertex();
if (i < vertexCont)
{
vertexTemp.color = color;
if (showPercent == 0)
{
vertexTemp.color = new Color32(60, 60, 60, 255);
}
}
else
{
vertexTemp.color = new Color32(60, 60, 60, 255);
}
posTemp = new Vector2(x, y);
vertexTemp.position = posTemp + originPos;
// 换算UV坐标对应到Image中的位置 因为牵扯到Pivot 的0.5
vertexTemp.uv0 = new Vector2(posTemp.x * convertRatio.x + uvCenter.x, posTemp.y * convertRatio.y + uvCenter.y);
vh.AddVert(vertexTemp);
_vertexList.Add(posTemp + originPos);
}
int id = 1;
for (int i = 0; i < segements; i++)
{
//生成 顺时针 生成三角形 0 是中心点 传入三个顶点 三个顶点是i , 0,i+1
vh.AddTriangle(id, 0, id + 1);
id++;
}
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint);
return IsValid(localPoint);
}
private bool IsValid(Vector2 localPoint)
{
//点击的次数为基数的时候 代表 在内的
return GetCrossPointNum(localPoint, _vertexList) % 2 == 1;
}
private int GetCrossPointNum(Vector2 localPoint, List<Vector3> vertexList)
{
int count = 0;
Vector3 vert1 = Vector3.zero;
Vector3 vert2 = Vector3.zero;
int vertCount = vertexList.Count;
for (int i = 0; i < vertCount; i++)
{
vert1 = vertexList[i];
vert2 = vertexList[(i + 1) % vertCount];
if (isYinRang(localPoint, vert1, vert2))
{
if (localPoint.x < GetX(vert1, vert2, localPoint.y))
{
count++;
}
}
}
return count;
}
private bool isYinRang(Vector2 localPoint, Vector3 vert1, Vector3 vert2)
{
if (vert1.y > vert2.y)
{
return localPoint.y < vert1.y && localPoint.y > vert2.y;
}
else
{
return localPoint.y < vert2.y && localPoint.y > vert1.y;
}
}
private float GetX(Vector3 vert1, Vector3 vert2, float y)
{
float k = (vert1.y - vert2.y) / (vert1.x - vert2.x);
return vert1.x + (y - vert1.y) / k;
}
}
#endregion
自己拖动 PolygonCollider2D 的碰撞框大小。。 再加上Button组件就能看到变化啦
登录后复制
using UnityEngine;
using UnityEngine.UI;
public class CustomImage : Image
{
private PolygonCollider2D _polygon;
private PolygonCollider2D Polygion
{
get
{
if (_polygon == null)
{
_polygon = GetComponent<PolygonCollider2D>();
}
return _polygon;
}
}
public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
{
Vector3 localPoint;
RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, screenPoint, eventCamera, out localPoint);
//判断这个点是否在 2D物体的上方
return Polygion.OverlapPoint(localPoint);
}
}
登录后复制
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
public class CustomImageEditor : Editor
{
private const int UI_LAYER = 5;
[MenuItem("GameObject/UI/CustomImage", priority = 0)]
private static void AddImage()
{
Transform canvasTrans = GetCanvasTrans();
Transform image = AddCunstomImage();
if (Selection.activeGameObject != null && Selection.activeGameObject.layer == UI_LAYER)
{
image.SetParent(Selection.activeGameObject.transform);
}
else
{
image.SetParent(canvasTrans);
}
image.localPosition = Vector3.zero;
}
private static Transform GetCanvasTrans()
{
Canvas canvas = GameObject.FindObjectOfType<Canvas>();
if (canvas == null)
{
GameObject canvasObj = new GameObject("Canvas");
SteLayer(canvasObj);
canvasObj.AddComponent<RectTransform>();
canvasObj.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
canvasObj.AddComponent<CanvasScaler>();
canvasObj.AddComponent<GraphicRaycaster>();
return canvasObj.transform;
}
return canvas.transform;
}
private static Transform AddCunstomImage()
{
GameObject image = new GameObject("Image");
SteLayer(image);
image.AddComponent<RectTransform>();
image.AddComponent<PolygonCollider2D>();
image.AddComponent<CustomImage>();
return image.transform;
}
private static void SteLayer(GameObject go)
{
go.layer = UI_LAYER;
}
}
直接上代码
通过Resources 获取一共的图片 在对其进行加载
登录后复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LoopList : MonoBehaviour
{
//单个Item 高度
private float _itemHeight;
//这个是中间间隔的宽度
public float OffsetY;
//生成在父物体下 content
public RectTransform _content;
private List<LoopListItem> _items = new List<LoopListItem>();
private List<LoopListItemModel> _models = new List<LoopListItemModel>();
private void Start()
{
//模拟数据获取
GetModel();
_content = GetComponent<ScrollRect>().content;
// _content = transform.Find("Viewport/Content").GetComponent<RectTransform>();
GameObject itemPrefab = Resources.Load<GameObject>("Item");
_itemHeight = itemPrefab.GetComponent<RectTransform>().rect.height;
int num = GetShowItemNum(_itemHeight, OffsetY);
Debug.Log(" " + num);
SpwanItme(num, itemPrefab);
SetContentSize();
transform.GetComponent<ScrollRect>().onValueChanged.AddListener(OnValueChange);
}
//需要生成的数量 列表的高度 / 单个列表的高度 +中间间隔 取最大值 +1
private int GetShowItemNum(float itemHeight, float offset)
{
float height = GetComponent<RectTransform>().rect.height;
return Mathf.CeilToInt(height / (itemHeight + offset)) + 1;
}
///生成了多少个
private void SpwanItme(int num, GameObject itemPrefab)
{
GameObject tmep = null;
LoopListItem itemTmep = null;
for (int i = 0; i < num; i++)
{
tmep = Instantiate(itemPrefab, _content);
itemTmep = tmep.AddComponent<LoopListItem>();
itemTmep.AddGetDataListener(GetData);
itemTmep.Init(i, OffsetY, num);
_items.Add(itemTmep);
}
}
private LoopListItemModel GetData(int index)
{
//非法数据
if (index < 0 || index >= _models.Count)
{
// Sprite go = Resources.Load<Sprite>("Icon/ButtonCameraCycleUpSprite");
Debug.Log(" 非法数据");
return new LoopListItemModel();
}
Debug.Log(" 不是非法数据");
return _models[index];
}
public void GetModel()
{
///遍历文件夹 加载Sprite
foreach (Sprite sprite in Resources.LoadAll<Sprite>("Icon"))
{
_models.Add(new LoopListItemModel(sprite, sprite.name));
Debug.Log(" sprite.name " + sprite.name);
}
}
public void SetContentSize()
{
float y = _models.Count * _itemHeight + (_models.Count - 1) * OffsetY;
_content.sizeDelta = new Vector2(_content.sizeDelta.x, y);
}
//当有滑动改变时
private void OnValueChange(Vector2 pos)
{
foreach (var item in _items)
{
item.OnValueChange();
}
}
}
登录后复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoopListItemModel
{
public Sprite Icon;
public string Describe;
public LoopListItemModel()
{
}
public LoopListItemModel(Sprite icon, string describe)
{
this.Icon = icon;
this.Describe = describe;
}
}
登录后复制
using System;
using UnityEngine;
using UnityEngine.UI;
public class LoopListItem : MonoBehaviour
{
public int _id;
private RectTransform _rect;
public RectTransform Rect
{
get
{
if (_rect == null)
{
_rect = GetComponent<RectTransform>();
}
return _rect;
}
}
private Image _icon;
public Image Icon
{
get
{
if (_icon == null)
{
_icon = transform.Find("LOGO").GetComponent<Image>();
}
return _icon;
}
}
private Text _des;
public Text Des
{
get
{
if (_des == null)
{
_des = GetComponentInChildren<Text>();
}
return _des;
}
}
private Func<int, LoopListItemModel> _getData = null;
private float _offset;
private int _showItemNum;
private RectTransform _content;
private LoopListItemModel _model;
//间距
public void Init(int id, float OffsetY, int showNumber)
{
this._id = -1;
_content = transform.parent.GetComponent<RectTransform>();
this._offset = OffsetY;
this._showItemNum = showNumber;
ChangeID(id);
}
public void AddGetDataListener(Func<int, LoopListItemModel> getData)
{
_getData = getData;
}
// 界面滑动之后 更新
public void OnValueChange()
{
int _startID, _endID = 0;
UpdateIDRange(out _startID, out _endID);
JudgeSelfID(_startID, _endID);
}
private void UpdateIDRange(out int _startID, out int _endID)
{
_startID = Mathf.FloorToInt(_content.anchoredPosition.y / (Rect.rect.height + _offset));
_endID = _startID + _showItemNum - 1;
}
private void JudgeSelfID(int _startID, int _endID)
{
int _offset = 0;
if (_id < _startID)
{
_offset = _startID - _id - 1;
ChangeID(_endID - _offset);
}
else if (_id > _endID)
{
_offset = _id - _endID - 1;
ChangeID(_startID + _offset);
}
}
private void ChangeID(int id)
{
if (_id != id && JudeIdValid(id))
{
_id = id;
_model = _getData(id);
Icon.sprite = _model.Icon;
Des.text = _model.Describe;
SetPosition();
}
}
private bool JudeIdValid(int id)
{
return !_getData(id).Equals(new LoopListItemModel());
}
private void SetPosition()
{
Rect.anchoredPosition = new Vector2(0, -_id * (Rect.rect.height + _offset));
}
}
如果想让Particle System 显示在UI前
UI的中 特效的遮住
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删