283 lines
9.4 KiB
C#
283 lines
9.4 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using Ichni;
|
||
using Ichni.Editor;
|
||
using Ichni.RhythmGame;
|
||
using UnityEngine;
|
||
using UnityEngine.Events;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.UI;
|
||
|
||
public partial class HsvDrawer
|
||
{
|
||
[Header("Color Wheel Settings")]
|
||
public int textureSize = 256; // 纹理尺寸
|
||
public float saturation = 1f; // 最大饱和度
|
||
public float value = 1f; // 明度
|
||
|
||
[Header("Color Picker Settings")]
|
||
public RectTransform pickerIndicator; // 取色器指示器
|
||
public Color currentColor = Color.white; // 当前选中的颜色
|
||
public Slider valueSlider; // 亮度拖动条
|
||
public Slider alphaSlider; // 透明度拖动条
|
||
public RawImage previewImage; // 颜色预览窗
|
||
|
||
private Texture2D _texture;
|
||
public RawImage _rawImage;
|
||
private RectTransform _rectTransform;
|
||
|
||
|
||
public bool isEmission = false;
|
||
public GameObject emissionObj;
|
||
public InputField emissionInput;
|
||
|
||
public DynamicUIBaseColorPicker baseColorPicker;
|
||
void Start()
|
||
{
|
||
_rectTransform = _rawImage.GetComponent<RectTransform>(); // 初始化
|
||
CreateColorWheelTexture();
|
||
ApplyTextureToRawImage();
|
||
|
||
if (valueSlider != null)
|
||
{
|
||
valueSlider.minValue = 0f;
|
||
valueSlider.maxValue = 1f;
|
||
valueSlider.value = value;
|
||
valueSlider.onValueChanged.AddListener(OnValueSliderChanged);
|
||
}
|
||
if (alphaSlider != null)
|
||
{
|
||
alphaSlider.minValue = 0f;
|
||
alphaSlider.maxValue = 1f;
|
||
alphaSlider.onValueChanged.AddListener(OnAlphaSliderChanged);
|
||
}
|
||
if (previewImage != null)
|
||
{
|
||
previewImage.color = currentColor;
|
||
}
|
||
}
|
||
|
||
void OnValueSliderChanged(float newValue)
|
||
{
|
||
value = newValue;
|
||
CreateColorWheelTexture();
|
||
ApplyTextureToRawImage();
|
||
// 刷新当前颜色
|
||
if (pickerIndicator != null)
|
||
UpdateCurrentColor(pickerIndicator.localPosition);
|
||
}
|
||
|
||
void OnAlphaSliderChanged(float newAlpha)
|
||
{
|
||
// 只更新透明度
|
||
currentColor.a = newAlpha;
|
||
if (previewImage != null)
|
||
previewImage.color = currentColor;
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
// 鼠标点击色轮区域即可拖动
|
||
if (Mouse.current.leftButton.wasPressedThisFrame && RectTransformUtility.RectangleContainsScreenPoint(_rectTransform, Mouse.current.position.ReadValue()))
|
||
{
|
||
StartCoroutine(DraggingColorPicker());
|
||
}
|
||
}
|
||
IEnumerator DraggingColorPicker()
|
||
{
|
||
|
||
while (Mouse.current.leftButton.isPressed)
|
||
{
|
||
Vector2 localPosition;
|
||
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rectTransform, Mouse.current.position.ReadValue(), null, out localPosition);
|
||
|
||
// 计算中心和最大半径
|
||
Vector2 center = _rectTransform.rect.center;
|
||
float maxRadius = _rectTransform.rect.width / 2f;
|
||
Vector2 offset = localPosition - center;
|
||
float distance = offset.magnitude;
|
||
|
||
// 如果超出圆形区域,则贴边
|
||
if (distance > maxRadius)
|
||
{
|
||
offset = offset.normalized * maxRadius;
|
||
localPosition = center + offset;
|
||
}
|
||
|
||
if (pickerIndicator != null)
|
||
pickerIndicator.localPosition = localPosition;
|
||
|
||
UpdateCurrentColor(localPosition);
|
||
|
||
yield return null; // 等待下一帧
|
||
}
|
||
}
|
||
void CreateColorWheelTexture()
|
||
{
|
||
// 创建方形纹理
|
||
_texture = new Texture2D(textureSize, textureSize, TextureFormat.RGBA32, false);
|
||
_texture.wrapMode = TextureWrapMode.Clamp;
|
||
|
||
Vector2 center = new Vector2(textureSize / 2f, textureSize / 2f);
|
||
float maxRadius = textureSize / 2f;
|
||
|
||
// 遍历所有像素
|
||
for (int y = 0; y < textureSize; y++)
|
||
{
|
||
for (int x = 0; x < textureSize; x++)
|
||
{
|
||
Vector2 pixelPos = new Vector2(x, y);
|
||
Vector2 offset = pixelPos - center;
|
||
float distance = offset.magnitude;
|
||
|
||
// 在圆形区域内绘制
|
||
if (distance <= maxRadius)
|
||
{
|
||
// 计算角度(0-360°)
|
||
float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg;
|
||
if (angle < 0) angle += 360;
|
||
|
||
// 计算饱和度(基于半径比例)
|
||
float sat = Mathf.Clamp01(distance / maxRadius) * saturation;
|
||
|
||
// HSV转RGB
|
||
Color color = Color.HSVToRGB(angle / 360f, sat, value);
|
||
_texture.SetPixel(x, y, color);
|
||
}
|
||
else
|
||
{
|
||
// 圆形外透明
|
||
_texture.SetPixel(x, y, Color.clear);
|
||
}
|
||
}
|
||
}
|
||
|
||
_texture.Apply(); // 应用像素更改
|
||
}
|
||
|
||
void ApplyTextureToRawImage()
|
||
{
|
||
if (_rawImage == null)
|
||
_rawImage = GetComponent<RawImage>();
|
||
|
||
_rawImage.texture = _texture;
|
||
_rawImage.color = Color.white; // 确保显示原始颜色
|
||
}
|
||
void UpdateCurrentColor(Vector2 localPosition)
|
||
{
|
||
Vector2 center = _rectTransform.rect.center;
|
||
Vector2 offset = localPosition - center;
|
||
float maxRadius = _rectTransform.rect.width / 2f;
|
||
|
||
// 计算半径比例(饱和度)
|
||
float distance = offset.magnitude;
|
||
float sat = Mathf.Clamp01(distance / maxRadius) * saturation;
|
||
|
||
// 计算角度(色调)
|
||
float angle = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg;
|
||
if (angle < 0) angle += 360;
|
||
|
||
// 计算颜色
|
||
float alpha = alphaSlider != null ? alphaSlider.value : 1f;
|
||
currentColor = Color.HSVToRGB(angle / 360f, sat, value);
|
||
currentColor.a = alpha;
|
||
|
||
// 更新取色器颜色(使其与背景有对比度)
|
||
if (pickerIndicator != null)
|
||
{
|
||
var img = pickerIndicator.GetComponent<Image>();
|
||
if (img != null)
|
||
img.color = (value > 0.5f) ? Color.black : Color.white;
|
||
}
|
||
// 若有亮度滑块,保持同步
|
||
if (valueSlider != null && valueSlider.value != value)
|
||
{
|
||
valueSlider.SetValueWithoutNotify(value);
|
||
}
|
||
// 若有透明度滑块,保持同步
|
||
if (alphaSlider != null && alphaSlider.value != alpha)
|
||
{
|
||
alphaSlider.SetValueWithoutNotify(alpha);
|
||
}
|
||
// 更新预览窗
|
||
if (previewImage != null)
|
||
{
|
||
previewImage.color = currentColor;
|
||
}
|
||
if (baseColorPicker != null)
|
||
{
|
||
// 同步到BaseColorPicker
|
||
baseColorPicker.SliderChangeWithoutNofication(currentColor);
|
||
}
|
||
ApplyParameters();
|
||
}
|
||
|
||
|
||
}
|
||
public partial class HsvDrawer : DynamicUIElement
|
||
{
|
||
private void ApplyParameters()
|
||
{
|
||
Color newValue = currentColor;
|
||
connectedBaseElement.GetType().GetField(parameterName).SetValue(connectedBaseElement, newValue);
|
||
connectedBaseElement.Refresh();
|
||
}
|
||
|
||
// 新增:同步connectedBaseElement的color到色盘
|
||
public void SyncFromBaseElement()
|
||
{
|
||
if (connectedBaseElement == null || string.IsNullOrEmpty(parameterName)) return;
|
||
Color color = (Color)connectedBaseElement.GetType().GetField(parameterName).GetValue(connectedBaseElement);
|
||
currentColor = color;
|
||
|
||
// 解析HSV
|
||
Color.RGBToHSV(color, out float h, out float s, out float v);
|
||
value = v;
|
||
if (valueSlider != null)
|
||
valueSlider.SetValueWithoutNotify(v);
|
||
if (alphaSlider != null)
|
||
alphaSlider.SetValueWithoutNotify(color.a);
|
||
|
||
// 计算picker位置
|
||
if (_rectTransform == null)
|
||
_rectTransform = _rawImage.GetComponent<RectTransform>();
|
||
Vector2 center = _rectTransform.rect.center;
|
||
float maxRadius = _rectTransform.rect.width / 2f;
|
||
float angle = h * 360f * Mathf.Deg2Rad;
|
||
float radius = s * maxRadius;
|
||
Vector2 offset = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * radius;
|
||
Vector2 pickerPos = center + offset;
|
||
if (pickerIndicator != null)
|
||
pickerIndicator.localPosition = pickerPos;
|
||
|
||
// 更新色盘和预览
|
||
CreateColorWheelTexture();
|
||
ApplyTextureToRawImage();
|
||
if (previewImage != null)
|
||
previewImage.color = currentColor;
|
||
}
|
||
public override void Initialize(IBaseElement baseElement, string title, string parameterName)
|
||
{
|
||
base.Initialize(baseElement, title, parameterName);
|
||
SyncFromBaseElement();
|
||
}
|
||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||
{
|
||
|
||
valueSlider.onValueChanged.AddListener(_ => action());
|
||
|
||
alphaSlider.onValueChanged.AddListener(_ => action());
|
||
valueSlider.onValueChanged.AddListener(_ => UpdateCurrentColor(pickerIndicator.localPosition));
|
||
|
||
alphaSlider.onValueChanged.AddListener(_ => UpdateCurrentColor(pickerIndicator.localPosition));
|
||
// 拖动色盘时也触发
|
||
// 这里通过在 UpdateCurrentColor 里调用 action
|
||
// 但由于没有事件,这里可以考虑用委托或事件,但为兼容性直接调用
|
||
// 可以在 UpdateCurrentColor 末尾加一行(如果需要多次触发):
|
||
// action?.Invoke();
|
||
// 但一般只需响应滑块即可
|
||
return this;
|
||
}
|
||
}
|
||
|