using System; using System.Collections; using System.Collections.Generic; using Ichni.RhythmGame; using UniRx; using UnityEngine; using UnityEngine.Serialization; namespace Ichni.Editor { public partial class TimePointerModule : MonoBehaviour { private Timeline timeline => EditorManager.instance.uiManager.timeline; private SongInformation songInformation => EditorManager.instance.songInformation; public GameObject timePointerPrefab; public List timePointerList; public RectTransform timePointerArea; public RectTransform visibleTimePointerArea; public RectTransform moveTabPoint;//用于显示timeline上的tab public RectTransform mainTimePointer; public float intervalUnit; public float timePointerInterval; public float sizeNegative, sizePositive; public int negativePointerAmount; // 负方向指示线的数量 public int positivePointerAmount, totalPointerAmount; /// /// delay时间区间中,(-delay, 0)的距离偏移量 /// public float delayDistanceOffset; public float leftSideSongTime, rightSideSongTime, songTimeDistance; private void Start() { Observable.NextFrame().Subscribe(_ => { timePointerList = new List(); Initialize(songInformation.delay, songInformation.bpm); }); } private void Update() { if (EditorManager.instance.musicPlayer.isPlaying) { SetRange(songInformation.songTime); } timePointerList.ForEach(pointer => { bool isActive = pointer.time >= leftSideSongTime && pointer.time <= rightSideSongTime; pointer.gameObject.SetActive(isActive); }); if (OnePointer != null) moveTabPoint.localPosition = new Vector3(timePointerArea.localPosition.x + OnePointer.transform.localPosition.x - timePointerInterval, 0, 0); foreach (var i in moveTabPoint.transform.GetComponentsInChildren()) { if (i.Time >= songInformation.songTime) { i.transform.localScale = new Vector3(1, 1, 1); } else { i.transform.localScale = new Vector3(0, 0, 0); } } } /// /// 初始化所有Timeline指示线 /// /// /// public void Initialize(float delay, float bpm) { timePointerInterval = 80; ClearPointers(); int beatDivider = 1; intervalUnit = (60f / bpm) / beatDivider * 1000; sizeNegative = delay * beatDivider / timeline.timePerBeat; // 计算负方向指示线的数量 negativePointerAmount = Mathf.CeilToInt(sizeNegative); sizePositive = songInformation.song.length * beatDivider / timeline.timePerBeat; positivePointerAmount = Mathf.CeilToInt(sizePositive); totalPointerAmount = negativePointerAmount + positivePointerAmount; timePointerArea.sizeDelta = new Vector2(timePointerInterval * (sizeNegative + sizePositive), 60f); delayDistanceOffset = timePointerInterval * (negativePointerAmount - sizeNegative); leftSideSongTime = timeline.beatmapStartTime; rightSideSongTime = timeline.timePerBeat * (visibleTimePointerArea.rect.width / timePointerInterval); songTimeDistance = rightSideSongTime; for (int i = -negativePointerAmount; i <= positivePointerAmount; i++) { CreatePointer(beatDivider, i); } //ChangeSongTimeDistance(0); SetRange(timeline.beatmapStartTime); } } public partial class TimePointerModule { /// /// 设置Timeline的显示区间,区间宽度使用当前的区间宽度 /// /// 开始时间,结束时间即(开始时间+区间宽度) public void SetRange(float startTime) { startTime = Mathf.Clamp(startTime, timeline.beatmapStartTime, songInformation.song.length); timePointerArea.anchoredPosition = new Vector2((timePointerArea.sizeDelta.x / 2) - (startTime + songInformation.delay) / timeline.timePerBeat * timePointerInterval, 0); float proportion = mainTimePointer.anchoredPosition.x / visibleTimePointerArea.rect.width; leftSideSongTime = startTime - songTimeDistance * proportion; rightSideSongTime = startTime + songTimeDistance * (1 - proportion); } /// /// 生成指示线 /// /// 细分X分音符 /// TimePointer OnePointer = null; private void CreatePointer(int beatDivider, int index) { TimePointer pointer = Instantiate(timePointerPrefab, timePointerArea).GetComponent(); timePointerList.Add(pointer); pointer.index = index; pointer.GetComponent().anchoredPosition = new Vector2((index + negativePointerAmount) * timePointerInterval + 15f - delayDistanceOffset, 0); pointer.time = index * intervalUnit / 1000f; pointer.intervalUnitText.text = Mathf.RoundToInt(index * intervalUnit).ToString(); if (index == 0) { OnePointer = timePointerList[timePointerList.Count - 1]; } if (beatDivider > 1) { } } /// /// 更新指示线位置 /// public void UpdatePointers() { // 计算延迟距离偏移量 delayDistanceOffset = timePointerInterval * (negativePointerAmount - sizeNegative); // 更新指示线区域的大小 timePointerArea.sizeDelta = new Vector2(timePointerInterval * totalPointerAmount, 55f); // 更新每个指示线的位置 foreach (var pointer in timePointerList) { pointer.GetComponent().anchoredPosition = new Vector2((pointer.index + negativePointerAmount) * timePointerInterval + 15f - delayDistanceOffset, 0); } } /// /// 清楚所有指示线 /// private void ClearPointers() { foreach (var pointer in timePointerList) { Destroy(pointer.gameObject); } timePointerList.Clear(); } /// /// 缩放时间线的展示时间宽度 /// /// 增减值 public void ChangeSongTimeDistance(float value) { float oldDistance = songTimeDistance; float changedDistance = songTimeDistance + value; float songLength = songInformation.song.length; if (changedDistance < 1 || changedDistance > songLength) { return; } float finalDistance = 0, finalValue = 0; float superfluousDistance = changedDistance - songLength; if (superfluousDistance > 0) { finalDistance = songLength; finalValue = value - superfluousDistance; } else { finalDistance = changedDistance; finalValue = value; } songTimeDistance = finalDistance; float proportion = mainTimePointer.anchoredPosition.x / visibleTimePointerArea.rect.width; leftSideSongTime -= finalValue * (proportion); rightSideSongTime += finalValue * (1 - proportion); if (leftSideSongTime < -songInformation.delay) { rightSideSongTime += Mathf.Abs(leftSideSongTime); leftSideSongTime = -songInformation.delay; } else if (rightSideSongTime > songLength) { leftSideSongTime -= (rightSideSongTime - songLength); rightSideSongTime = songLength; } timePointerInterval = timePointerInterval / finalDistance * oldDistance; UpdatePointers(); //UpdateListItems(); SetRange(leftSideSongTime); } } }