using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using DG.Tweening; using Ichni; using Ichni.RhythmGame; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; public partial class EventPoint : MonoBehaviour { public AnimatedFloat animatedFloat; public EventPoint LastEventPoint; public EventPoint NextEventPoint; public Image EvDrawimage; public Image OvDrawimage; public RectTransform LeftSide; public RectTransform RightSide; public Button selectButton; public RawImage CurveCanvas; public FlexibleFloatTab FatherTab; public TMP_Text ViewText; public static bool Locked = false; public int BeatDeviver => FatherTab.BeatDeviver; public void Initialize(AnimatedFloat animatedFloat) { this.animatedFloat = animatedFloat; transform.localPosition = new Vector3( animatedFloat.startTime / EditorManager.instance.timeline.timePerBeat * BeatDeviver, 0, 0 ); RightSide.localPosition = new Vector3( (animatedFloat.endTime - animatedFloat.startTime) / EditorManager.instance.timeline.timePerBeat * BeatDeviver, 0, 0); EvDrawimage.rectTransform.sizeDelta = new Vector2(RightSide.localPosition.x - LeftSide.localPosition.x, EvDrawimage.rectTransform.sizeDelta.y); EvDrawimage.transform.localPosition = new Vector3(EvDrawimage.rectTransform.sizeDelta.x / 2, 0, 0); OvDrawimage.transform.localPosition = RightSide.localPosition; CurveCanvas.rectTransform.sizeDelta = new Vector2(EvDrawimage.rectTransform.sizeDelta.x, EvDrawimage.rectTransform.sizeDelta.y); } public float value => FatherTab.scalevalue; public void Refresh(bool changePos = false) { if (changePos) { Initialize(animatedFloat); } UpdateValue(); ReDraw(value); } public void SelectButtonClick()//unity内:当按钮按下时 { if (Locked) return; if (Keyboard.current.leftShiftKey.isPressed) { if (FatherTab.FatherWindow.ClipBoard[FatherTab.Title].Contains(animatedFloat)) { FatherTab.FatherWindow.ClipBoard[FatherTab.Title].Remove(animatedFloat); LeftSide.sizeDelta = new Vector2(15, EvDrawimage.rectTransform.sizeDelta.y); } else { FatherTab.FatherWindow.ClipBoard[FatherTab.Title].Add(animatedFloat); LeftSide.sizeDelta = EvDrawimage.rectTransform.sizeDelta; } FatherTab.FatherWindow.updateClipBoardMuM(); } else UpLoad(); } public void UpLoad() { FatherTab.FatherWindow.animationCurveTypeDropdown.onValueChanged.RemoveAllListeners(); // 如果当前点是已连接点,则取消连接并隐藏可见区域 if (FatherTab.FatherWindow.ConnectedPoint == this) { FatherTab.FatherWindow.VisibleArea.SetActive(false); FatherTab.FatherWindow.ConnectedPoint = null; EvDrawimage.color = new Color(EvDrawimage.color.r, 0.3019607843137255f, EvDrawimage.color.b, 0.5f); FatherTab.FatherWindow.StartText.text = ""; FatherTab.FatherWindow.EndText.text = ""; FatherTab.FatherWindow.StartValueText.text = ""; FatherTab.FatherWindow.EndValueText.text = ""; return; } // 如果有已连接点,则重置其颜色 if (FatherTab.FatherWindow.ConnectedPoint != null) { FatherTab.FatherWindow.EvEndpointChangeButton.GetComponent().color = new Color(1f, 1f, 1f, 1); FatherTab.FatherWindow.ConnectedPoint.EvDrawimage.color = new Color( FatherTab.FatherWindow.ConnectedPoint.EvDrawimage.color.r, 0.3019607843137255f, FatherTab.FatherWindow.ConnectedPoint.EvDrawimage.color.b, 0.5f ); } UpdateValue(); } public void UpdateValue() { // 设置新的连接点并更新UI FatherTab.FatherWindow.ConnectedPoint = this; EvDrawimage.color = new Color(EvDrawimage.color.r, 0.75f, EvDrawimage.color.b, 1f); FatherTab.FatherWindow.animationCurveTypeDropdown.onValueChanged.RemoveAllListeners(); // 更新下拉选项 FatherTab.FatherWindow.animationCurveTypeDropdown.ClearOptions(); List enumNameList = System.Enum.GetNames(typeof(AnimationCurveType)).ToList(); FatherTab.FatherWindow.VisibleArea.SetActive(true); FatherTab.FatherWindow.animationCurveTypeDropdown.AddOptions(enumNameList); FatherTab.FatherWindow.animationCurveTypeDropdown.value = (int)animatedFloat.animationCurveType; // 更新文本 FatherTab.FatherWindow.StartText.text = animatedFloat.startTime.ToString(); FatherTab.FatherWindow.EndText.text = animatedFloat.endTime.ToString(); FatherTab.FatherWindow.StartValueText.text = animatedFloat.startValue.ToString(); FatherTab.FatherWindow.EndValueText.text = animatedFloat.endValue.ToString(); FatherTab.FatherWindow.animationCurveTypeDropdown.onValueChanged.AddListener(value => FatherTab.FatherWindow.ChangeValue()); } // 添加静态方法:查找插入索引 public static int FindInsertIndex(List eventPoints, float startTime) { int low = 0; int high = eventPoints.Count - 1; while (low <= high) { int mid = (low + high) / 2; if (eventPoints[mid].animatedFloat.startTime < startTime) { low = mid + 1; } else { high = mid - 1; } } return low; } // 添加实例方法:连接事件点 public void LinkEventPoints(List eventPoints, int index) { if (index - 1 >= 0) { LastEventPoint = eventPoints[index - 1]; LastEventPoint.NextEventPoint = this; } else { LastEventPoint = null; } if (index == eventPoints.Count - 1) { NextEventPoint = null; } } // 添加实例方法:连接新事件点 public void LinkNewEventPoint(List eventPoints, bool link, float scalevalue) { int index = eventPoints.IndexOf(this); if (index - 1 >= 0) { LastEventPoint = eventPoints[index - 1]; LastEventPoint.NextEventPoint = this; LastEventPoint.ReDraw(scalevalue); } if (index + 1 < eventPoints.Count) { NextEventPoint = eventPoints[index + 1]; if (link) animatedFloat.endTime = NextEventPoint.animatedFloat.startTime; Initialize(animatedFloat); NextEventPoint.LastEventPoint = this; } } // 添加静态方法:克隆 AnimatedFloat 并应用时间偏移 /// /// 克隆一个 AnimatedFloat 对象,并根据偏移量调整其开始和结束时间。 /// /// 要克隆的 AnimatedFloat 对象。 /// 时间偏移量。 /// 克隆后的 AnimatedFloat 对象。 public static AnimatedFloat CloneWithOffset(AnimatedFloat animatedFloat, float offset) { return new AnimatedFloat( animatedFloat.startTime + offset, animatedFloat.endTime + offset, animatedFloat.startValue, animatedFloat.endValue, animatedFloat.animationCurveType ); } } public partial class EventPoint//显示? { public IEnumerator GenerateTextureCoroutine(int width, int height, float value) { Task task = Task.Run(() => GenerateTextureColors(width, height, value)); while (!task.IsCompleted) { yield return null; // 等待下一帧 } Color[] textureColors = task.Result; Texture2D Texture = new Texture2D(width, height); Texture.SetPixels(textureColors); Texture.Apply(); CurveCanvas.texture = Texture; // CurveCanvas.color = new Color(1, 1, 1, 0); // CurveCanvas.DOColor(new Color(1, 1, 1, 1), 0.2f).SetEase(Ease.InOutSine); } public Color[] GenerateTextureColors(int width, int height, float value) { Color[] pixels = new Color[width * height]; // 初始化所有像素为透明 for (int i = 0; i < pixels.Length; i++) { pixels[i] = new Color(0, 0, 0, 0); } int LastEventPointY = 0; for (int i = 0; i < width; i++) { float t = (float)i / width; int f = (int)( (height / 2) + (animatedFloat.startValue * value + ((animatedFloat.endValue - animatedFloat.startValue) * AnimationCurveEvaluator.Evaluate(animatedFloat.animationCurveType, t) * value)) ); // 绘制垂直线段 - 保留超出边界的红色标记 if (LastEventPointY < f) { for (int j = LastEventPointY; j < f; j++) { // 检查是否超出边界 bool isOutOfBounds = j < 0 || j >= height; // 计算实际坐标(循环调整) int actualY = j; while (actualY < 0) actualY += height; while (actualY >= height) actualY -= height; int index = actualY * width + i; if (index >= 0 && index < pixels.Length) { // 根据是否超出边界设置颜色 pixels[index] = isOutOfBounds ? Color.red : Color.green; } } } else { for (int j = LastEventPointY; j > f; j--) { // 检查是否超出边界 bool isOutOfBounds = j < 0 || j >= height; // 计算实际坐标(循环调整) int actualY = j; while (actualY < 0) actualY += height; while (actualY >= height) actualY -= height; int index = actualY * width + i; if (index >= 0 && index < pixels.Length) { // 根据是否超出边界设置颜色 pixels[index] = isOutOfBounds ? Color.red : Color.green; } } } // 绘制当前点 - 保留超出边界的红色标记 bool isFOutOfBounds = f < 0 || f >= height; int actualF = f; while (actualF < 0) actualF += height; while (actualF >= height) actualF -= height; int currentIndex = actualF * width + i; if (currentIndex >= 0 && currentIndex < pixels.Length) { // 根据是否超出边界设置颜色 pixels[currentIndex] = isFOutOfBounds ? Color.red : Color.green; } LastEventPointY = f; } return pixels; } public void ReDraw(float value) { int width = (int)CurveCanvas.rectTransform.sizeDelta.x / 5; int height = (int)CurveCanvas.rectTransform.sizeDelta.y / 5; // 获取颜色数组(可在多线程环境中调用) // 在主线程中创建和设置纹理(Unity对象操作必须在主线程) StartCoroutine(GenerateTextureCoroutine(width, height, value)); // 其余的非纹理相关代码保持不变 if (NextEventPoint != null) { OvDrawimage.transform.localPosition = new Vector3(RightSide.transform.localPosition.x, animatedFloat.endValue * value * 5, 0); OvDrawimage.rectTransform.sizeDelta = new Vector2((NextEventPoint.animatedFloat.startTime - animatedFloat.endTime) / EditorManager.instance.uiManager.timeline.timePerBeat * FatherTab.BeatDeviver, OvDrawimage.rectTransform.sizeDelta.y); OvDrawimage.color = new Color(0, 1, 0, 1); while (OvDrawimage.transform.localPosition.y > 100) { OvDrawimage.color = new Color(1, 0, 0, 0.3f); OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y - 200, OvDrawimage.transform.localPosition.z); } while (OvDrawimage.transform.localPosition.y < -100) { OvDrawimage.color = new Color(1, 0, 0, 0.3f); OvDrawimage.transform.localPosition = new Vector3(OvDrawimage.transform.localPosition.x, OvDrawimage.transform.localPosition.y + 200, OvDrawimage.transform.localPosition.z); } } else { OvDrawimage.rectTransform.sizeDelta = new Vector2(0, OvDrawimage.rectTransform.sizeDelta.y); } selectButton.transform.localPosition = EvDrawimage.transform.localPosition; selectButton.GetComponent().sizeDelta = EvDrawimage.rectTransform.sizeDelta; ViewText.text = animatedFloat.startTime.ToString("0.00") + "s" + "\n" + animatedFloat.startValue.ToString("0.0") + "\n" + animatedFloat.endValue.ToString("0.0") + "\n" + animatedFloat.endTime.ToString("0.00") + "s" + "\n" + animatedFloat.animationCurveType.ToString(); ViewText.color = new Color(1, 1, 1, EvDrawimage.rectTransform.sizeDelta.x < 100 ? 0 : 1); } }