这能叫例行更新吗

Signed-off-by: TRAfoer <lhf190@outlook.com>
This commit is contained in:
2026-02-09 23:10:55 +08:00
parent 77726bcb6c
commit a76f650998
40 changed files with 1323 additions and 866 deletions

View File

@@ -0,0 +1,363 @@
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);
}
}

View File

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

View File

@@ -0,0 +1,333 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using DG.Tweening.Core.Easing;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class FlexibleFloatTab : MonoBehaviour
{
public GraphicalFlexibleFloatWindow FatherWindow;
public List<EventPoint> eventPoints;
public RectTransform Area;
public RectTransform BeatArea;
public RectTransform XBeatArea;
public EventPoint eventPoint;
public GameObject BeatLine;
public Button TabButton;
public string Title;
public FlexibleFloat connectFloat;
public int BeatDeviver => FatherWindow.BeatDeviver;
public int BeatNextDeviver => FatherWindow.BeatNextDeviver;
public bool linked = false;//TODOTODO!
// 初始化函数
public void Initialize(FlexibleFloat flexibleFloat, string title)
{
Title = title;
ClearChildren(Area);
ClearChildren(BeatArea);
eventPoints = new List<EventPoint>();
connectFloat = flexibleFloat;
CreateBeatLines();
CreateEventPoints();
Area.localPosition = new Vector3(FatherWindow.songBeat * BeatDeviver, 0, 0);
}
// 清除子节点
private void ClearChildren(RectTransform parent)
{
for (int i = 0; i < parent.childCount; i++)
{
Destroy(parent.GetChild(i).gameObject);
}
}
// 创建节拍线
private void CreateBeatLines()
{
// 先清空BeatArea下的所有子对象防止重复生成
for (int i = BeatArea.childCount - 1; i >= 0; i--)
{
Destroy(BeatArea.GetChild(i).gameObject);
}
float maxX = 1400f + (3 * BeatDeviver);
int totalBeats = (int)(EditorManager.instance.songInformation.song.length / FatherWindow.timePerBeat);
for (int i = 0; i < totalBeats; i++)
{
float posX = BeatDeviver * i;
if (posX > maxX)
{
break;
}
GameObject u = Instantiate(BeatLine, BeatArea);
u.transform.localPosition = new Vector3(posX, 0, 0);
}
}
// 创建事件点
private void CreateEventPoints()
{
for (int i = 0; i <= connectFloat.animations.Count - 1; i++)
{
AnimatedFloat animatedFloat = connectFloat.animations[i];
EventPoint eventPoint = Instantiate(this.eventPoint, Area);
eventPoint.FatherTab = this;
eventPoint.Initialize(animatedFloat);
eventPoints.Add(eventPoint);
LinkEventPoints(i, eventPoint);
}
foreach (var i in eventPoints)
{
i.ReDraw(scalevalue);
}
}
// 更新函数
public void Update()
{
bool isOnEv = false;
foreach (var i in eventPoints)
{
isOnEv = RectTransformUtility.RectangleContainsScreenPoint(i.selectButton.GetComponent<RectTransform>(), Mouse.current.position.ReadValue());
if (isOnEv) break;
}
Vector3 newPosition = new Vector3(-FatherWindow.songBeat * BeatDeviver, 0, 0);
Area.localPosition = newPosition;
BeatArea.localPosition = newPosition;
while (true)
{
BeatArea.localPosition += new Vector3(BeatDeviver, 0, 0);
if (BeatArea.localPosition.x > ((-200f) - BeatDeviver))
{
break;
}
}
XBeatArea.localPosition = BeatArea.localPosition;
if (RectTransformUtility.RectangleContainsScreenPoint(TabButton.GetComponent<RectTransform>(), Mouse.current.position.ReadValue()))
if (!isOnEv && Mouse.current.leftButton.wasPressedThisFrame)
{
AddEvent();
}
}
// 添加事件
public void AddEvent()
{
if (Keyboard.current.ctrlKey.isPressed)
{
EventPoint eventPoint = Instantiate(this.eventPoint, Area);
eventPoint.FatherTab = this;
eventPoint.Initialize(new AnimatedFloat(GetBeat(),
GetBeat() + (float.Parse(FatherWindow.EventMultiplier.text) * FatherWindow.timePerBeat), 0, 0, AnimationCurveType.Linear));
eventPoints.Insert(FindInsertIndex(eventPoint.animatedFloat.startTime), eventPoint);
LinkNewEventPoint(eventPoint, linked);
SetEventPoint(eventPoint);
eventPoint.ReDraw(scalevalue);
eventPoint.selectButton.onClick.Invoke();
FatherWindow.ChangeValue();
connectFloat.Add(eventPoint.animatedFloat);
connectFloat.Sort();
}
// else
// {
// if (FatherWindow.ConnectedPoint != null) FatherWindow.ConnectedPoint.UpLoad();
// }
}
public void SpawnEvent(AnimatedFloat animatedFloat)
{
EventPoint eventPoint = Instantiate(this.eventPoint, Area);
eventPoint.FatherTab = this;
eventPoint.Initialize(animatedFloat);
eventPoints.Insert(FindInsertIndex(eventPoint.animatedFloat.startTime), eventPoint);
LinkNewEventPoint(eventPoint);
eventPoint.ReDraw(scalevalue);
connectFloat.Add(eventPoint.animatedFloat);
connectFloat.Sort();
}
public void SetEventPoint(EventPoint eventPoint)
{
if (eventPoint.LastEventPoint == null) return;
// 设置当前事件点的起始值为上一个事件点的结束值
eventPoint.animatedFloat.startValue = eventPoint.LastEventPoint.animatedFloat.endValue;
eventPoint.animatedFloat.animationCurveType = eventPoint.LastEventPoint.animatedFloat.animationCurveType;
eventPoint.ReDraw(scalevalue);
}
// 添加调用 EventPoint 类的接口
public void LinkEventPoints(int index, EventPoint eventPoint)
{
eventPoint.LinkEventPoints(eventPoints, index);
}
public void LinkNewEventPoint(EventPoint eventPoint, bool link = false)
{
eventPoint.LinkNewEventPoint(eventPoints, link, scalevalue);
}
public int FindInsertIndex(float startTime)
{
return EventPoint.FindInsertIndex(eventPoints, startTime);
}
// 获取节拍
public float GetBeat()
{
// 获取鼠标在 BeatArea 中的相对位置
Vector2 localMousePosition = Area.InverseTransformPoint(Mouse.current.position.ReadValue());
//Debug.Log(localMousePosition);
float mouseBeat = localMousePosition.x / BeatDeviver;
float far = 0f;
while (far < mouseBeat)
{
far += 1f / BeatNextDeviver;
}
far -= 1f / BeatNextDeviver;
return far * FatherWindow.timePerBeat;
}
public float scalevalue => FatherWindow.scalevalue;
// 曲线缩放
public void CurveScale(float value)
{
foreach (EventPoint i in eventPoints)
{
i.ReDraw(value);
}
}
// 改变X轴节拍
public void XbeatCnange(int num)
{
ClearChildren(XBeatArea);
for (int i = 1; i < num; i++)
{
foreach (Transform child in BeatArea)
{
GameObject newChild = Instantiate(child.gameObject, XBeatArea);
CanvasGroup canvasGroup = newChild.GetComponent<CanvasGroup>();
newChild.transform.localPosition = new Vector3(child.localPosition.x + ((float)BeatDeviver) / num * i, child.localPosition.y, child.localPosition.z);
if (canvasGroup == null)
{
canvasGroup = newChild.AddComponent<CanvasGroup>();
}
canvasGroup.alpha = 0.1f;
}
}
}
// 移除动画
public void remoceAnim(AnimatedFloat a)
{
if (connectFloat.animations.Contains(a))
{
connectFloat.animations.Remove(a);
}
}
/// <summary>
/// 从事件点列表中移除指定的事件点,并更新其前后连接关系。
/// </summary>
/// <param name="eventPoint">要移除的事件点。</param>
public void RemoveEventPoint(EventPoint eventPoint)
{
if (eventPoints.Contains(eventPoint))
{
// 更新前后事件点的连接关系
if (eventPoint.LastEventPoint != null)
{
eventPoint.LastEventPoint.NextEventPoint = eventPoint.NextEventPoint;
eventPoint.LastEventPoint.ReDraw(scalevalue);
}
if (eventPoint.NextEventPoint != null)
{
eventPoint.NextEventPoint.LastEventPoint = eventPoint.LastEventPoint;
eventPoint.NextEventPoint.ReDraw(scalevalue);
}
// 从列表中移除事件点
eventPoints.Remove(eventPoint);
// 从连接的动画中移除
connectFloat.animations.Remove(eventPoint.animatedFloat);
// 销毁事件点对象
Destroy(eventPoint.gameObject);
}
}
public IEnumerator Draging()
{
EventPoint.Locked = true;
while (Keyboard.current.uKey.isPressed)
{
bool changed = false;
var point = FatherWindow.ConnectedPoint;
if (Mouse.current.leftButton.isPressed)
{
point.animatedFloat.startTime = GetBeat();
changed = true;
}
else if (Mouse.current.rightButton.isPressed)
{
point.animatedFloat.endTime = GetBeat();
changed = true;
}
if (changed)
{
// 保证时间顺序
if (point.animatedFloat.startTime >= point.animatedFloat.endTime)
{
if (Mouse.current.leftButton.isPressed)
point.animatedFloat.endTime = point.animatedFloat.startTime + 0.1f;
else
point.animatedFloat.startTime = point.animatedFloat.endTime - 0.1f;
}
// 保证不超过下一个事件点
if (point.NextEventPoint != null && point.animatedFloat.endTime > point.NextEventPoint.animatedFloat.startTime)
{
if (Mouse.current.leftButton.isPressed)
point.animatedFloat.endTime = point.NextEventPoint.animatedFloat.startTime;
else
point.animatedFloat.startTime = point.NextEventPoint.animatedFloat.startTime - 0.1f;
}
point.Initialize(point.animatedFloat);
point.UpdateValue();
}
yield return null;
}
FatherWindow.ConnectedPoint.Refresh(true);
EventPoint.Locked = false;
}
public void CutEvent()
{
EventPoint eventPoint = FatherWindow.ConnectedPoint;
if (eventPoint == null) return;
for (int i = 0; i < BeatNextDeviver; i++)
{
float segmentStartTime = eventPoint.animatedFloat.startTime + (eventPoint.animatedFloat.endTime - eventPoint.animatedFloat.startTime) / BeatNextDeviver * i;
float segmentEndTime = eventPoint.animatedFloat.startTime + (eventPoint.animatedFloat.endTime - eventPoint.animatedFloat.startTime) / BeatNextDeviver * (i + 1);
connectFloat.Add(new AnimatedFloat(
segmentStartTime,
segmentEndTime,
AnimationCurveEvaluator.Evaluate(eventPoint.animatedFloat.animationCurveType, (segmentStartTime - eventPoint.animatedFloat.startTime) / (eventPoint.animatedFloat.endTime - eventPoint.animatedFloat.startTime)) * (eventPoint.animatedFloat.endValue - eventPoint.animatedFloat.startValue) + eventPoint.animatedFloat.startValue,
AnimationCurveEvaluator.Evaluate(eventPoint.animatedFloat.animationCurveType, (segmentEndTime - eventPoint.animatedFloat.startTime) / (eventPoint.animatedFloat.endTime - eventPoint.animatedFloat.startTime)) * (eventPoint.animatedFloat.endValue - eventPoint.animatedFloat.startValue) + eventPoint.animatedFloat.startValue,
AnimationCurveType.Linear));
}
RemoveEventPoint(eventPoint);
connectFloat.Sort();
Initialize(connectFloat, Title);
FatherWindow.ChangeValue();
}
}

View File

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

View File

@@ -0,0 +1,309 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using Ichni;
using Ichni.Editor;
using Ichni.RhythmGame;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public partial class GraphicalFlexibleFloatWindow : MovableWindow
{
public FlexibleFloatTab unitPrefab;
public IBaseElement connectedBaseElement;
public List<FlexibleFloatTab> unitList;
public UnityAction ApplyParameters;
public float songTime => EditorManager.instance.songInformation.songTime;
public float songBeat => EditorManager.instance.songInformation.songBeat;
public float beatmapStartTime => -EditorManager.instance.songInformation.delay;
public float timePerBeat => 60f / EditorManager.instance.songInformation.bpm;
public int BeatDeviver = 100;
public int BeatNextDeviver = 1;
public void Initialize(IBaseElement baseElement, string title, FlexibleFloat[] FlexibleFloats, string[] Subtitles)
{
InitializeWindow(title, null, new Vector3(1f, 1f, 1f));
scalevalue = 5;
this.connectedBaseElement = baseElement;
this.title.text = title;
unitList = new List<FlexibleFloatTab>();
closeButton.onClick.AddListener(Quit);
for (int i = 0; i <= FlexibleFloats.Length - 1; i++)
{
ClipBoard.Add(Subtitles[i], new List<AnimatedFloat>());
AddUnit(FlexibleFloats[i], Subtitles[i]);
}
ApplyParameters = () =>
{
for (int i = 0; i <= unitList.Count - 1; i++)
{
unitList[i].connectFloat.Sort();
}
};
XDeviverScale("1");
EvEndpointChangeButton.onClick.AddListener(EvEndpointStartChange);
GetComponent<RectTransform>().sizeDelta = new Vector2(1400, (FlexibleFloats.Length + 1) * 200 + 50);
}
public void AddUnit(FlexibleFloat flexibleFloat, string Subtitle)
{
flexibleFloat.Sort();
FlexibleFloatTab flexibleFloatTab = Instantiate(unitPrefab, windowRect);
flexibleFloatTab.FatherWindow = this;
unitList.Add(flexibleFloatTab);
flexibleFloatTab.Initialize(flexibleFloat, Subtitle);
}
public void Quit()
{
ApplyParameters();
//StartCoroutine(WindowAnim.HidePanel(gameObject, true));
this.transform.DOScale(Vector3.zero, 0.15f).SetEase(Ease.InCirc).OnComplete(() =>
{
Destroy(gameObject);
});
}
public float scalevalue;
public void CurveScale(string Rawvalue)
{
float value = float.Parse(Rawvalue);
scalevalue = value;
foreach (FlexibleFloatTab i in unitList)
{
i.CurveScale(value);
}
}
public void DeviverScale(string Rawvalue)
{
if (ConnectedPoint != null) ConnectedPoint.UpLoad();
BeatDeviver = int.Parse(Rawvalue);
ChangeValue();
for (int i = unitList.Count - 1; i >= 0; i--)
{
unitList[i].Initialize(unitList[i].connectFloat, unitList[i].Title);
}
XDeviverScale(BeatNextDeviver.ToString());
}
public void XDeviverScale(string Rawvalue)
{
BeatNextDeviver = int.Parse(Rawvalue);
foreach (FlexibleFloatTab i in unitList)
{
i.XbeatCnange(BeatNextDeviver);
}
}
}
public partial class GraphicalFlexibleFloatWindow
{
[Title("AnimEditor")]
public TMP_InputField StartText;
public TMP_InputField EndText;
public TMP_InputField StartValueText;
public TMP_InputField EndValueText;
public TMP_InputField EventMultiplier;
public EventPoint ConnectedPoint;
public TMP_Dropdown animationCurveTypeDropdown;
public GameObject VisibleArea;
/// <summary>
/// 移除当前连接的事件点,并更新 UI。
/// </summary>
public void RemoveConnectedPoint()
{
if (ConnectedPoint != null)
{
// 调用 FlexibleFloatTab 的 RemoveEventPoint 方法
ConnectedPoint.FatherTab.RemoveEventPoint(ConnectedPoint);
// 清空连接点并隐藏可见区域
ConnectedPoint = null;
VisibleArea.SetActive(false);
}
}
public void ChangeValue()
{
if (ConnectedPoint != null)
{
float startTime = float.Parse(StartText.text);
float endTime = float.Parse(EndText.text);
float startValue = float.Parse(StartValueText.text);
float endValue = float.Parse(EndValueText.text);
ConnectedPoint.animatedFloat.startTime = startTime;
ConnectedPoint.animatedFloat.endTime = endTime;
ConnectedPoint.animatedFloat.startValue = startValue;
ConnectedPoint.animatedFloat.endValue = endValue;
ConnectedPoint.animatedFloat.animationCurveType = (AnimationCurveType)animationCurveTypeDropdown.value;
ConnectedPoint.Initialize(ConnectedPoint.animatedFloat);
ConnectedPoint.ReDraw(scalevalue);
}
}
public Button EvEndpointChangeButton;
public void EvEndpointStartChange()
{
if (ConnectedPoint != null)
{
EndText.text = (ConnectedPoint.animatedFloat.startTime + 0.01).ToString();
ChangeValue();
EvEndpointChangeButton.GetComponent<Image>().color = new Color(1f, 0.5f, 0.5f, 1);
ConnectedPoint.FatherTab.TabButton.onClick.RemoveAllListeners();
ConnectedPoint.FatherTab.TabButton.onClick.AddListener(EvEndpointEndChange);
}
}
public void EvEndpointEndChange()
{
if (ConnectedPoint != null)
{
EvEndpointChangeButton.GetComponent<Image>().color = new Color(1f, 1f, 1f, 1);
float newendtime = ConnectedPoint.FatherTab.GetBeat();
if (newendtime > ConnectedPoint.animatedFloat.startTime)
{
if (ConnectedPoint.NextEventPoint != null && newendtime > ConnectedPoint.NextEventPoint.animatedFloat.startTime)
EndText.text = ConnectedPoint.NextEventPoint.animatedFloat.startTime.ToString();
else EndText.text = newendtime.ToString();
ChangeValue();
}
ConnectedPoint.FatherTab.TabButton.onClick.RemoveAllListeners();
}
}
public Dictionary<string, List<AnimatedFloat>> ClipBoard = new();
public void Update()
{
if (Keyboard.current.deleteKey.isPressed && ConnectedPoint != null)
{
RemoveConnectedPoint();
}
if (Keyboard.current.shiftKey.isPressed)
{
if (Keyboard.current.vKey.wasPressedThisFrame)
PasteClipboard(1f);
else if (Keyboard.current.bKey.wasPressedThisFrame)
PasteClipboard(-1f);
}
if (Keyboard.current.escapeKey.wasPressedThisFrame)
{
foreach (var key in ClipBoard.Keys.ToList())
{
ClipBoard[key] = new List<AnimatedFloat>();
}
foreach (FlexibleFloatTab i in unitList)
{
foreach (EventPoint j in i.eventPoints)
{
j.LeftSide.sizeDelta = new Vector2(15, j.EvDrawimage.rectTransform.sizeDelta.y);
}
}
updateClipBoardMuM();
}
if (ConnectedPoint != null && RectTransformUtility.RectangleContainsScreenPoint(GetComponent<RectTransform>(), Mouse.current.position.ReadValue()))
{
if (Keyboard.current.aKey.wasPressedThisFrame)
{
ConnectedPoint.animatedFloat.endValue *= -1;
ConnectedPoint.animatedFloat.startValue *= -1;
ConnectedPoint.Refresh();
}
else if (Keyboard.current.sKey.wasPressedThisFrame)
{
float value = ConnectedPoint.animatedFloat.startValue;
ConnectedPoint.animatedFloat.startValue = ConnectedPoint.animatedFloat.endValue;
ConnectedPoint.animatedFloat.endValue = value;
ConnectedPoint.Refresh();
}
else if (Keyboard.current.uKey.wasPressedThisFrame)
{
try
{
ConnectedPoint.FatherTab.StartCoroutine(ConnectedPoint.FatherTab.Draging());
}
catch (System.Exception)
{
EventPoint.Locked = false;
}
}
else if (Keyboard.current.lKey.wasPressedThisFrame)
{
ConnectedPoint.FatherTab.CutEvent();
}
}
}
public void PasteClipboard(float valuescale = 1f)
{
// 获取当前时间线的节拍位置
float time = unitList[0].GetBeat();
float MinCopyTime = float.MaxValue;
// 遍历剪贴板中的所有动画数据MinCopyTime = float.MaxValue;
foreach (var list in ClipBoard.Values)
{
foreach (var animatedFloat in list)
{
if (animatedFloat.startTime < MinCopyTime)
{
MinCopyTime = animatedFloat.startTime;
}
}
}
foreach (var key in ClipBoard.Keys)
{
foreach (var animatedFloat in ClipBoard[key])
{
// 克隆动画数据并应用时间偏移
AnimatedFloat newFloat = EventPoint.CloneWithOffset(animatedFloat, time - MinCopyTime);
newFloat.startValue *= valuescale;
newFloat.endValue *= valuescale;
// 在对应的 FlexibleFloatTab 中生成事件点
unitList.Find(x => x.Title == key).SpawnEvent(newFloat);
}
}
}
}
public partial class GraphicalFlexibleFloatWindow
{//以后显示类写这里,别在叠大粪了
public TMP_Text ClipBoardMuM;
public void updateClipBoardMuM()
{
int mum = 0;
foreach (var key in ClipBoard.Keys)
{
mum += ClipBoard[key].Count();
}
ClipBoardMuM.text = "ClipBoard: " + mum.ToString();
}
}

View File

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