363 lines
14 KiB
C#
363 lines
14 KiB
C#
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<Image>().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<string> 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<EventPoint> 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<EventPoint> 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<EventPoint> 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 并应用时间偏移
|
||
/// <summary>
|
||
/// 克隆一个 AnimatedFloat 对象,并根据偏移量调整其开始和结束时间。
|
||
/// </summary>
|
||
/// <param name="animatedFloat">要克隆的 AnimatedFloat 对象。</param>
|
||
/// <param name="offset">时间偏移量。</param>
|
||
/// <returns>克隆后的 AnimatedFloat 对象。</returns>
|
||
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<Color[]> 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<RectTransform>().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);
|
||
}
|
||
} |