248 lines
8.9 KiB
C#
248 lines
8.9 KiB
C#
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<TimePointer> 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;
|
||
/// <summary>
|
||
/// delay时间区间中,(-delay, 0)的距离偏移量
|
||
/// </summary>
|
||
public float delayDistanceOffset;
|
||
|
||
public float leftSideSongTime, rightSideSongTime, songTimeDistance;
|
||
|
||
private void Start()
|
||
{
|
||
Observable.NextFrame().Subscribe(_ =>
|
||
{
|
||
timePointerList = new List<TimePointer>();
|
||
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<SubTab>())
|
||
{
|
||
if (i.Time >= songInformation.songTime)
|
||
{
|
||
i.transform.localScale = new Vector3(1, 1, 1);
|
||
}
|
||
else
|
||
{
|
||
i.transform.localScale = new Vector3(0, 0, 0);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化所有Timeline指示线
|
||
/// </summary>
|
||
/// <param name="delay"></param>
|
||
/// <param name="bpm"></param>
|
||
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
|
||
{
|
||
/// <summary>
|
||
/// 设置Timeline的显示区间,区间宽度使用当前的区间宽度
|
||
/// </summary>
|
||
/// <param name="startTime">开始时间,结束时间即(开始时间+区间宽度)</param>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成指示线
|
||
/// </summary>
|
||
/// <param name="beatDivider">细分X分音符</param>
|
||
/// <param name="index"></param>
|
||
TimePointer OnePointer = null;
|
||
private void CreatePointer(int beatDivider, int index)
|
||
{
|
||
TimePointer pointer = Instantiate(timePointerPrefab, timePointerArea).GetComponent<TimePointer>();
|
||
timePointerList.Add(pointer);
|
||
pointer.index = index;
|
||
|
||
pointer.GetComponent<RectTransform>().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)
|
||
{
|
||
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新指示线位置
|
||
/// </summary>
|
||
public void UpdatePointers()
|
||
{
|
||
// 计算延迟距离偏移量
|
||
delayDistanceOffset = timePointerInterval * (negativePointerAmount - sizeNegative);
|
||
|
||
// 更新指示线区域的大小
|
||
timePointerArea.sizeDelta = new Vector2(timePointerInterval * totalPointerAmount, 55f);
|
||
|
||
// 更新每个指示线的位置
|
||
foreach (var pointer in timePointerList)
|
||
{
|
||
pointer.GetComponent<RectTransform>().anchoredPosition =
|
||
new Vector2((pointer.index + negativePointerAmount) * timePointerInterval + 15f - delayDistanceOffset, 0);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清楚所有指示线
|
||
/// </summary>
|
||
private void ClearPointers()
|
||
{
|
||
foreach (var pointer in timePointerList)
|
||
{
|
||
Destroy(pointer.gameObject);
|
||
}
|
||
timePointerList.Clear();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 缩放时间线的展示时间宽度
|
||
/// </summary>
|
||
/// <param name="value">增减值</param>
|
||
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);
|
||
}
|
||
}
|
||
} |