改改改

重大bug修复:track删除pathnode后不能正确更新

Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
2025-07-10 20:40:03 +08:00
parent 43fae3a34a
commit 135f61a857
24 changed files with 34730 additions and 21708 deletions

View File

@@ -326,5 +326,77 @@ namespace Ichni.Editor
}
}
}
public static void swapDisplacement()
{
Displacement displacement = inspector.connectedGameElement as Displacement;
if (displacement == null)
{
LogWindow.Log("Please select a Displacement first!", Color.red);
return;
}
foreach (var anim in displacement.positionX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in displacement.positionY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in displacement.positionZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
public static void swapSwirl()
{
Swirl swirl = inspector.connectedGameElement as Swirl;
if (swirl == null)
{
LogWindow.Log("Please select a Swirl first!", Color.red);
return;
}
foreach (var anim in swirl.eulerAngleX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in swirl.eulerAngleY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in swirl.eulerAngleZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
public static void swapScale()
{
Scale scale = inspector.connectedGameElement as Scale;
if (scale == null)
{
LogWindow.Log("Please select a Scale first!", Color.red);
return;
}
foreach (var anim in scale.scaleX.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in scale.scaleY.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
foreach (var anim in scale.scaleZ.animations)
{
anim.endValue = -anim.endValue;
anim.startValue = -anim.startValue;
}
}
}
}

View File

@@ -12,11 +12,11 @@ namespace Ichni.Editor
public abstract class DynamicUIElement : MonoBehaviour
{
Inspector Inspector => EditorManager.instance.uiManager.inspector;
public TMP_Text title;
public CanvasGroup canvasGroup;
public IBaseElement connectedBaseElement;
/// <summary>
/// 参数名,通过反射获取饿修改对应变量的值
/// </summary>
@@ -24,6 +24,7 @@ namespace Ichni.Editor
public virtual void Initialize(IBaseElement baseElement, string title, string parameterName)
{
if (canvasGroup == null) canvasGroup = gameObject.AddComponent<CanvasGroup>();
this.connectedBaseElement = baseElement;
this.parameterName = parameterName;
if (title != string.Empty)
@@ -50,7 +51,7 @@ namespace Ichni.Editor
public abstract DynamicUIElement AddListenerFunction(UnityAction action);
}
public interface IHaveAutoUpdate
{
public bool isAutoUpdate { get; set; }
@@ -59,12 +60,12 @@ namespace Ichni.Editor
public void UpdateContent()
{
if(isAutoUpdate && isReceiving)
if (isAutoUpdate && isReceiving)
{
ApplyContent();
}
}
public void ApplyContent();
}
}

View File

@@ -212,5 +212,16 @@ namespace Ichni.Editor
subcontainer.dynamicUIElements.Add(stringListDropdown);
return stringListDropdown;
}
// 新增HSV色盘生成方法
public HsvDrawer GenerateHsvDrawer(IBaseElement baseElement, DynamicUISubcontainer subcontainer, string title, string parameterName)
{
HsvDrawer hsvDrawer = Object
.Instantiate(EditorManager.instance.basePrefabs.hsvDrawer, subcontainer.rect)
.GetComponent<HsvDrawer>();
hsvDrawer.Initialize(baseElement, title, parameterName);
subcontainer.dynamicUIElements.Add(hsvDrawer);
return hsvDrawer;
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Ichni.Editor
public Button clipSaveButton;
public Button clipLoadButton;
public Button beatmapToolsButton;
[Title("Windows")]
public GeneralSecondaryWindow clipManagementWindow;
@@ -40,17 +40,17 @@ namespace Ichni.Editor
beatmapToolsButton.onClick.AddListener(GenerateBeatmapToolsWindow);
}
}
public partial class ToolBar
{
private void GenerateEscapeConfirmWindow()
{
GeneralSecondaryWindow escapeConfirmWindow =
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
escapeConfirmWindow.Initialize("Confirm Escape");
var container = escapeConfirmWindow.GenerateContainer();
var clipSettings = container.GenerateSubcontainer(3);
var applyClipButton = escapeConfirmWindow.GenerateButton(clipSettings, "Yes", () =>
@@ -62,15 +62,15 @@ namespace Ichni.Editor
escapeConfirmWindow.closeButton.onClick.Invoke();
});
}
private void GenerateReloadConfirmWindow()
{
GeneralSecondaryWindow escapeConfirmWindow =
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
escapeConfirmWindow.Initialize("Confirm Reload");
var container = escapeConfirmWindow.GenerateContainer();
var clipSettings = container.GenerateSubcontainer(3);
var applyClipButton = escapeConfirmWindow.GenerateButton(clipSettings, "Yes", () =>
@@ -82,7 +82,7 @@ namespace Ichni.Editor
escapeConfirmWindow.closeButton.onClick.Invoke();
});
}
private void GenerateSaveClipWindow()
{
GameElement currentElement = EditorManager.instance.operationManager.currentSelectedElements[0];
@@ -100,11 +100,11 @@ namespace Ichni.Editor
}
GeneralSecondaryWindow saveClipWindow =
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
clipManagementWindow = saveClipWindow;
saveClipWindow.Initialize("Save Clip: " + currentElement.elementName, () => clipManagementWindow = null);
var container = saveClipWindow.GenerateContainer();
var clipSettings = container.GenerateSubcontainer(3);
var clipNameInputField = saveClipWindow.GenerateInputField(clipSettings, "Clip Name", currentElement.elementName);
@@ -117,13 +117,13 @@ namespace Ichni.Editor
private void GenerateLoadClipWindow()
{
GameElement currentElement = EditorManager.instance.operationManager.currentSelectedElements[0];
if (currentElement == null)
{
LogWindow.Log("No Game Element selected.", Color.red);
return;
}
GameElement loadTarget = currentElement == EditorManager.instance ? null : currentElement.parentElement;
if (clipManagementWindow != null)
@@ -131,7 +131,7 @@ namespace Ichni.Editor
LogWindow.Log("Clip Management Window already exists.", Color.red);
return;
}
GeneralSecondaryWindow loadClipWindow =
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
@@ -146,12 +146,12 @@ namespace Ichni.Editor
EditorManager.instance.projectManager.beatmapClipManager.LoadClip(clipNameInputField.GetValue<string>());
});
}
private void GenerateMergeWindow()
{
GeneralSecondaryWindow mergeWindow = Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
mergeWindow.Initialize("Merge Beatmap");
var container = mergeWindow.GenerateContainer();
@@ -169,11 +169,11 @@ namespace Ichni.Editor
private void GenerateBeatmapToolsWindow()
{
GeneralSecondaryWindow beatmapToolsWindow =
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
Instantiate(EditorManager.instance.basePrefabs.generalSecondaryWindow,
EditorManager.instance.uiManager.mainPage.mainCanvas.GetComponent<RectTransform>()).GetComponent<GeneralSecondaryWindow>();
beatmapToolsWindow.Initialize("Beatmap Tools", () => clipManagementWindow = null);
var container = beatmapToolsWindow.GenerateContainer("Note Tools");
var beatmapToolsSettings = container.GenerateSubcontainer(3);
var applyTimeOnNameButton = beatmapToolsWindow.GenerateButton(beatmapToolsSettings, "Apply Time On Note Name", () =>
@@ -183,31 +183,32 @@ namespace Ichni.Editor
List<Stay> allStays = allNotes.FindAll(x => x is Stay).ConvertAll(x => x as Stay);
List<Hold> allHolds = allNotes.FindAll(x => x is Hold).ConvertAll(x => x as Hold);
List<Flick> allFlicks = allNotes.FindAll(x => x is Flick).ConvertAll(x => x as Flick);
foreach (var tap in allTaps.Where(tap => tap.elementName == "New Tap" || Regex.IsMatch(tap.elementName, @"Tap \(\d+\)")))
{
tap.elementName = "Tap (" + tap.exactJudgeTime + ")";
tap.Refresh();
}
foreach (var stay in allStays.Where(stay => stay.elementName == "New Stay" || Regex.IsMatch(stay.elementName, @"Stay \(\d+\)")))
{
stay.elementName = "Stay (" + stay.exactJudgeTime + ")";
stay.Refresh();
}
foreach (var hold in allHolds.Where(hold => hold.elementName == "New Hold" || Regex.IsMatch(hold.elementName, @"Hold \(\d+-\d+\)")))
{
hold.elementName = "Hold (" + hold.exactJudgeTime + "-" + hold.holdEndTime + ")";
hold.Refresh();
}
foreach (var flick in allFlicks.Where(flick => flick.elementName == "New Flick" || Regex.IsMatch(flick.elementName, @"Flick \(\d+\)")))
{
flick.elementName = "Flick (" + flick.exactJudgeTime + ")";
flick.Refresh();
}
});
}
}
}

View File

@@ -66,7 +66,7 @@ namespace Ichni.RhythmGame
this.baseColorDirtyMark = false;
this.emissionColorDirtyMark = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveColorSubmodule).colorSubmodule = this;
@@ -88,7 +88,7 @@ namespace Ichni.RhythmGame
this.baseColorDirtyMark = false;
this.emissionColorDirtyMark = false;
if (!HaveSameSubmodule)
{
(attachedGameElement as IHaveColorSubmodule).colorSubmodule = this;
@@ -106,15 +106,21 @@ namespace Ichni.RhythmGame
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
var container = inspector.GenerateContainer("Color");
var subcontainer = container.GenerateSubcontainer(1, 300f);
if ((attachedGameElement as IHaveColorSubmodule).haveBaseColor)
{
var baseColor = inspector.GenerateBaseColorPicker(this, subcontainer, "Base Color", nameof(originalBaseColor));
baseColor.AddListenerFunction(Refresh);
// var baseColor = inspector.GenerateBaseColorPicker(this, subcontainer, "Base Color", nameof(originalBaseColor));
// baseColor.AddListenerFunction(Refresh);
// 新增HSV轮盘
var hsvDrawer = inspector.GenerateHsvDrawer(this, subcontainer, "HSV", nameof(originalBaseColor));
hsvDrawer.AddListenerFunction(Refresh);
if (attachedGameElement.childElementList.Exists(x => x is BaseColorChange))
{
baseColor.title.text += " (Occupied by Animation)";
baseColor.canvasGroup.interactable = false;
// baseColor.title.text += " (Occupied by Animation)";
// baseColor.canvasGroup.interactable = false;
hsvDrawer.title.text += " (Occupied by Animation)";
hsvDrawer.canvasGroup.interactable = false;
}
}
@@ -123,7 +129,7 @@ namespace Ichni.RhythmGame
var emissionColor = inspector.GenerateEmissionColorPicker(this, subcontainer, "Emission Color",
nameof(emissionEnabled), nameof(originalEmissionColor), nameof(originalEmissionIntensity));
emissionColor.AddListenerFunction(Refresh);
if (attachedGameElement.childElementList.Exists(x => x is EmissionColorChange))
{
emissionColor.title.text += " (Occupied by Animation)";
@@ -147,7 +153,7 @@ namespace Ichni.RhythmGame
public ColorSubmodule colorSubmodule { get; set; }
public virtual bool haveBaseColor => true;
public virtual bool haveEmissionColor => false;
public void SetColorObserver()
{
GameElement attachedGameElement = colorSubmodule.attachedGameElement;
@@ -158,7 +164,7 @@ namespace Ichni.RhythmGame
{
return;
}
bool willRefresh = false;
if (colorSubmodule.baseColorDirtyMark)
@@ -167,14 +173,14 @@ namespace Ichni.RhythmGame
colorSubmodule.baseColorDirtyMark = false;
willRefresh = true;
}
if (colorSubmodule.emissionColorDirtyMark)
{
//在动画物体中改变currentColor
colorSubmodule.emissionColorDirtyMark = false;
willRefresh = true;
}
if (willRefresh)
{
attachedGameElement.Refresh();
@@ -209,13 +215,13 @@ namespace Ichni.RhythmGame
public override void ExecuteBM()
{
attachedElement = GameElement_BM.GetElement(attachedElementGuid);
(attachedElement as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attachedElement,
(attachedElement as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attachedElement,
originalBaseColor, emissionEnabled, originalEmissionColor, originalEmissionIntensity);
}
public override void DuplicateBM(GameElement attached)
{
(attached as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attached,
(attached as IHaveColorSubmodule).colorSubmodule = new ColorSubmodule(attached,
originalBaseColor, emissionEnabled, originalEmissionColor, originalEmissionIntensity);
}
}

View File

@@ -79,6 +79,7 @@ namespace Ichni.RhythmGame
public void OnDestroy()
{
track.trackPathSubmodule.pathNodeList.Remove(this);
track.trackPathSubmodule.SetPathPoints();
track.Refresh();
print("PathNode " + elementName + " destroyed.");
}

View File

@@ -98,14 +98,11 @@ namespace Ichni.RhythmGame
SetUpSplineComputer(trackSpaceType, trackSamplingType);
foreach (var pathNode in pathNodeList)
{
SetPathNode(pathNode);
}
ClosePath();
path.Rebuild(true);
}
public void SortPathnodeInChildren()//emm待用吧
{
Debug.Log("TrackSort");
@@ -127,6 +124,14 @@ namespace Ichni.RhythmGame
public partial class TrackPathSubmodule
{
public void SetPathPoints()
{
path.SetPoints(new SplinePoint[0]);
foreach (var pathNode in pathNodeList)
{
SetPathNode(pathNode);
}
}
public override void SaveBM()
{
matchedBM = new TrackPathSubmodule_BM(attachedGameElement, this);

View File

@@ -44,11 +44,13 @@ namespace Ichni.RhythmGame
this.materialThemeBundleName = materialThemeBundleName;
this.materialName = materialName;
Material mat = ThemeBundleManager.instance.GetObject<Material>(materialThemeBundleName, materialName);
if (mat != null)
if (mat == null)
{
renderMaterial = mat;
meshRenderer.material = renderMaterial;
mat = EditorManager.instance.basePrefabs.defaultTrackMaterial;
}
renderMaterial = mat;
meshRenderer.material = renderMaterial;
}
public override void Refresh()
@@ -136,7 +138,7 @@ namespace Ichni.RhythmGame
{
if (enableEmission)
{
meshRenderer.material.EnableKeyword("_EMISSION_ON");
meshRenderer.material.EnableKeyword("_EMISSION_ON");
}
else
{
@@ -193,7 +195,7 @@ namespace Ichni.RhythmGame
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
public bool zWrite; // 新增
public TrackRendererSubmoduleAutoOrient_BM()
{
@@ -207,7 +209,7 @@ namespace Ichni.RhythmGame
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
}
public override void ExecuteBM()
@@ -273,7 +275,7 @@ namespace Ichni.RhythmGame
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
public bool zWrite; // 新增
public TrackRendererSubmodulePathGenerator_BM()
{
@@ -287,6 +289,7 @@ namespace Ichni.RhythmGame
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
}
public override void ExecuteBM()
@@ -372,7 +375,7 @@ namespace Ichni.RhythmGame
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
public bool zWrite; // 新增
public int sideCount;
public TrackRendererSubmoduleTubeGenerator_BM()
@@ -387,6 +390,7 @@ namespace Ichni.RhythmGame
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
sideCount = trackRendererSubmodule.sideCount;
}
@@ -453,7 +457,7 @@ namespace Ichni.RhythmGame
public string materialName;
public bool enableEmission;
public float emissionIntensity;
public bool zWrite;
public bool zWrite; // 新增
public TrackRendererSubmoduleSurface_BM()
{
@@ -467,6 +471,7 @@ namespace Ichni.RhythmGame
materialName = trackRendererSubmodule.materialName;
enableEmission = trackRendererSubmodule.enableEmission;
emissionIntensity = trackRendererSubmodule.emissionIntensity;
zWrite = trackRendererSubmodule.zWrite; // 新增
}
public override void ExecuteBM()

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7418d8f37ad03114a8009e73d016d9d5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,276 @@
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;
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.value = 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;
}
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;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81a06df931b999c4e9a0ac510cb0f3ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -13,7 +13,7 @@ namespace Ichni.RhythmGame
[Title("基础预制体")] public GameObject emptyObject;
public GameObject elementFolder;
public GameObject gameCamera;
[Title("Track相关")] public GameObject track;
public GameObject trackDisplay;
@@ -29,7 +29,7 @@ namespace Ichni.RhythmGame
public GameObject stayNote;
public GameObject holdNote;
public GameObject flickNote;
[Title("Note 判定UI")] public GameObject fullscreenNearTimeHint;
public GameObject areaHint;
public GameObject triggerHint;
@@ -57,7 +57,8 @@ namespace Ichni.RhythmGame
public GameObject stringListDropdown;
public GameObject baseColorPicker;
public GameObject emissionColorPicker;
public GameObject hsvDrawer;
[Title("DynamicUI相关-Composite")] public GameObject generalSecondaryWindow;
public GameObject compositeParameterWindow;
public GameObject inputFieldUnit;
@@ -69,7 +70,7 @@ namespace Ichni.RhythmGame
public GameObject gradientColorKeyUnit;
public GameObject gradientAlphaKeyUnit;
public GameObject stringIntPairUnit;
[Title("图形化动画编辑器")] public GameObject graphicalFlexibleFloatWindow;
//采音器