UGUI—拾色面板
作者:追风剑情 发布于:2019-11-8 17:16 分类:Unity3d
一、工程截图
首先准备一张色带图
所有UI组件都设置成居中
CircleImage是小圆圈图片(用的是RawImage组件)
UIColorPicker.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
/// <summary>
/// 拾色器
/// </summary>
public class UIColorPicker : UIBehaviour, IPointerDownHandler, IBeginDragHandler, IDragHandler
{
public new Camera uicamera;
public RawImage circleImage;
public RawImage pickImage;
public GameObject rectPickImage;
[SerializeField]
private Color pickColor;
//红绿蓝三基色所在角度
private readonly float redAngle = 0;
private readonly float greenAngle = 120;
private readonly float blueAngle = 240;
private bool canDrag = false;
private UIRectPickImage m_RectPickImage;
[Serializable]
// 定义按钮OnChangeValue事件类
public class OnChangeValueEvent : UnityEvent { }
// 防止序列化变量重命名后丢失引用
[FormerlySerializedAs("onChangeValue")]
[SerializeField]
private OnChangeValueEvent m_OnChangeValue = new OnChangeValueEvent();
protected override void Awake()
{
base.Awake();
m_RectPickImage = rectPickImage.AddComponent<UIRectPickImage>();
m_RectPickImage.uicamera = uicamera;
SetColor(pickColor);
}
public void OnPointerDown(PointerEventData eventData)
{
Vector2 screenPoint = eventData.pressPosition;
Vector2 localPoint = ScreenPointToLocal(eventData.pressPosition);
// 鼠标是否击在色环上
if (InCircleRound(localPoint))
PickColor(screenPoint);
}
public void OnBeginDrag(PointerEventData eventData)
{
// 鼠标必须要点在色环上才能拖动
Vector2 localPoint = ScreenPointToLocal(eventData.pressPosition);
canDrag = InCircleRound(localPoint);
}
public void OnDrag(PointerEventData eventData)
{
if (!canDrag)
return;
Vector2 screenPoint = eventData.position;
PickColor(screenPoint);
}
// 判断坐标是否在色环上
private bool InCircleRound(Vector2 localPoint)
{
float length = localPoint.magnitude;
float radius_out = circleImage.rectTransform.sizeDelta.x / 2; //外半径
float radius_in = radius_out - pickImage.rectTransform.sizeDelta.x; //内半径
return length >= radius_in && length <= radius_out;
}
// 纠正坐标,使小圆圈绕圆形轨迹运动
private Vector2 AdjustPosition(Vector2 localPostion)
{
float R1 = circleImage.rectTransform.sizeDelta.x / 2;
float R2 = pickImage.rectTransform.sizeDelta.x / 2;
float length = R1 - R2;
Vector2 normal = localPostion.normalized;
localPostion = normal * length;
return localPostion;
}
// 获取小圆圈所在角度
public float GetAngle(Vector2 localPostion)
{
float angle = Vector2.Angle(Vector2.right, localPostion);
if (localPostion.y < 0)
angle = 360 - angle;
return angle;
}
// 设置小圆圈坐标
public void SetPickPosition(Vector2 localPostion)
{
pickImage.rectTransform.anchoredPosition = localPostion;
}
// 根据小圆圈所在坐标计算颜色
private Color ReadPickColor(Vector2 localPostion)
{
Color c = Color.white;
float t;
float angle = GetAngle(localPostion);
if (angle >= redAngle && angle <= greenAngle)
{
t = angle / 120;
c = Color.Lerp(Color.red, Color.green, t);
}
else if(angle > greenAngle && angle <= blueAngle)
{
t = (angle - 120) / 120;
c = Color.Lerp(Color.green, Color.blue, t);
}
else if (angle > blueAngle && angle <= 360)
{
t = (angle - 240) / 120;
c = Color.Lerp(Color.blue, Color.red, t);
}
//颜色提到最亮
float max = Mathf.Max(Mathf.Max(c.r, c.g), c.b);
c *= 1/max;
return c;
}
// 通过鼠标所在屏蔽坐标取色
private void PickColor(Vector2 screenPoint)
{
Vector2 localPoint = ScreenPointToLocal(screenPoint);
localPoint = AdjustPosition(localPoint);
SetPickPosition(localPoint);
pickColor = ReadPickColor(localPoint);
m_RectPickImage.SetPickColor(pickColor);
}
// 屏幕坐标转本地坐标
private Vector2 ScreenPointToLocal(Vector2 screenPoint)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(circleImage.rectTransform, screenPoint, uicamera, out localPoint);
return localPoint;
}
// 计算色环内矩形区大小
public Rect CalculateInRect()
{
float radius_out = circleImage.rectTransform.sizeDelta.x / 2; //外半径
float radius_in = radius_out - pickImage.rectTransform.sizeDelta.x; //内半径
float half_width = Mathf.Sqrt(radius_in * radius_in / 2);//勾股定理计算内矩形半宽
Rect rect = new Rect();
rect.x = rect.y = 0;
rect.width = rect.height = half_width * 2;
return rect;
}
// 矩形拾色后回调
public void SetPickColor(Color pickColor)
{
this.pickColor = pickColor;
}
// 获取拾色器的当前颜色
public Color GetPickColor()
{
return m_RectPickImage.GetPickColor();
}
// 向拾取器设置颜色
public void SetColor(Color color)
{
this.pickColor = color;
Color c = color;
// 找出最小分量
float min = Mathf.Min(Mathf.Min(c.r, c.g), c.b);
//颜色提到最亮
float max = Mathf.Max(Mathf.Max(c.r, c.g), c.b);
c *= 1 / max;
float angle = 0;
// 蓝色 (介于红-绿之间)
if (Mathf.Approximately(color.b, min))
{
//0-60度之间 g=[0, 1]; 60-120度之间 r=[1, 0]
if (c.r >= 1)
angle = Mathf.Lerp(0, 60, c.g);
else
angle = Mathf.Lerp(60, 120, 1 - c.r);
}
// 绿色 (介于蓝-红之间)
else if (Mathf.Approximately(color.g, min))
{
//240-300度之间 r=[0, 1]; 300-360度之间 b=[1, 0]
if (c.b >= 1)
angle = Mathf.Lerp(240, 300, c.r);
else
angle = Mathf.Lerp(300, 360, 1 - c.b);
}
// 红色 (介于绿-蓝之间)
else if (Mathf.Approximately(color.r, min))
{
//120-180度之间 b=[0, 1]; 180-240度之间 g=[1, 0]
if (c.g >= 1)
angle = Mathf.Lerp(120, 180, c.b);
else
angle = Mathf.Lerp(180, 240, 1 - c.g);
}
float rad = angle * Mathf.Deg2Rad;
float x = Mathf.Acos(rad);
float y = Mathf.Asin(rad);
Vector2 localPoint = new Vector2(x, y);
localPoint = AdjustPosition(localPoint);
SetPickPosition(localPoint);
pickColor = ReadPickColor(localPoint);
m_RectPickImage.SetColor(color);
}
}
// 中间矩形取色区
public class UIRectPickImage : RawImage, IDragHandler, IPointerDownHandler
{
public new Camera uicamera;
private UIColorPicker picker;
private Color pickColor = Color.red;
private RawImage circleImage;
protected override void Awake()
{
base.Awake();
picker = transform.parent.GetComponent<UIColorPicker>();
Rect rect = picker.CalculateInRect();
rectTransform.sizeDelta = new Vector2(rect.width - 40, rect.height - 40);
Transform tran = transform.Find("CircleImage");
if (tran != null)
{
circleImage = tran.GetComponent<RawImage>();
}
}
public void OnPointerDown(PointerEventData eventData)
{
Vector2 screenPoint = eventData.pressPosition;
PickColor(screenPoint);
}
public void OnDrag(PointerEventData eventData)
{
Vector2 screenPoint = eventData.position;
PickColor(screenPoint);
}
protected override void OnPopulateMesh(VertexHelper vh)
{
Texture tex = mainTexture;
vh.Clear();
if (tex != null)
{
var r = GetPixelAdjustedRect();
var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
var scaleX = tex.width * tex.texelSize.x;
var scaleY = tex.height * tex.texelSize.y;
{
var color32 = color;
vh.AddVert(new Vector3(v.x, v.y), Color.black, new Vector2(uvRect.xMin * scaleX, uvRect.yMin * scaleY));
vh.AddVert(new Vector3(v.x, v.w), Color.white, new Vector2(uvRect.xMin * scaleX, uvRect.yMax * scaleY));
vh.AddVert(new Vector3(v.z, v.w), this.pickColor, new Vector2(uvRect.xMax * scaleX, uvRect.yMax * scaleY));
vh.AddVert(new Vector3(v.z, v.y), Color.black, new Vector2(uvRect.xMax * scaleX, uvRect.yMin * scaleY));
vh.AddTriangle(0, 1, 2);
vh.AddTriangle(2, 3, 0);
}
}
}
// 色环拾色后调用
public void SetPickColor(Color pickColor)
{
this.pickColor = pickColor;
this.SetVerticesDirty();
}
// 获取拾色器的当前颜色
public Color GetPickColor()
{
return ReadPickColor(circleImage.rectTransform.anchoredPosition);
}
// 外部设值时调用
public void SetColor(Color color)
{
SetPickColor(color);
Color c = color;
float max = Mathf.Max(Mathf.Max(c.r, c.g), c.b);
float min = Mathf.Min(Mathf.Min(c.r, c.g), c.b);
//x控制亮度值
float x = (1 - min / max) * rectTransform.sizeDelta.x - rectTransform.sizeDelta.x / 2;
//y控制暗度值
float y = max * rectTransform.sizeDelta.y - rectTransform.sizeDelta.y / 2;
Vector2 localPoint = new Vector2(x, y);
SetPickPosition(localPoint);
}
// 根据小圆圈所在坐标计算颜色
private Color ReadPickColor(Vector2 localPostion)
{
float w = rectTransform.sizeDelta.x;
float h = rectTransform.sizeDelta.y;
// 将坐标原点移到左下角
float x = localPostion.x + w / 2;
float y = localPostion.y + h / 2;
// 对坐标归一化
x = x / w;
y = y / h;
Color c = Color.Lerp(Color.white, this.pickColor, x);
// 颜色提到最亮
float max = Mathf.Max(Mathf.Max(c.r, c.g), c.b);
c *= 1 / max;
// 根据y坐标计算亮度值
c *= y;
c.a = 1;
return c;
}
// 通过鼠标所在屏蔽坐标取色
private void PickColor(Vector2 screenPoint)
{
Vector2 localPoint = ScreenPointToLocal(screenPoint);
localPoint = AdjustPosition(localPoint);
SetPickPosition(localPoint);
Color c = ReadPickColor(localPoint);
picker.SetPickColor(c);
}
// 屏幕坐标转本地坐标
private Vector2 ScreenPointToLocal(Vector2 screenPoint)
{
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, uicamera, out localPoint);
return localPoint;
}
// 校正坐标,确保坐标在矩形区内
private Vector2 AdjustPosition(Vector2 localPostion)
{
float R = rectTransform.sizeDelta.x / 2;
localPostion.x = Mathf.Clamp(localPostion.x, -R, R);
localPostion.y = Mathf.Clamp(localPostion.y, -R, R);
return localPostion;
}
// 设置小圆圈坐标
public void SetPickPosition(Vector2 localPostion)
{
if (circleImage == null)
return;
circleImage.rectTransform.anchoredPosition = localPostion;
}
}
标签: Unity3d
日历
最新文章
随机文章
热门文章
分类
存档
- 2025年11月(1)
- 2025年9月(3)
- 2025年7月(4)
- 2025年6月(5)
- 2025年5月(1)
- 2025年4月(5)
- 2025年3月(4)
- 2025年2月(3)
- 2025年1月(1)
- 2024年12月(5)
- 2024年11月(5)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
- Open CASCADE
- CascadeStudio
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号











