@@ -77,6 +77,65 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
return _previewRoot;
|
||||
}
|
||||
}
|
||||
private float CurrentSongTime => CoreServices.TimeProvider?.SongTime ?? EditorManager.instance.songInformation.songTime;
|
||||
|
||||
private bool TryGetTrackContext(out SplineComputer spline, out TrackTimeSubmodule trackTime)
|
||||
{
|
||||
spline = null;
|
||||
trackTime = null;
|
||||
|
||||
if (TrackedTrack?.trackPathSubmodule?.path == null) return false;
|
||||
if (TrackedTrack.trackTimeSubmodule == null) return false;
|
||||
|
||||
spline = TrackedTrack.trackPathSubmodule.path;
|
||||
trackTime = TrackedTrack.trackTimeSubmodule;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetBeatRange(out float beatStart, out float beatEnd)
|
||||
{
|
||||
beatStart = 0f;
|
||||
beatEnd = 0f;
|
||||
|
||||
if (!TryGetTrackContext(out _, out TrackTimeSubmodule trackTime)) return false;
|
||||
|
||||
var beatManager = EditorManager.instance.songInformation.beatManager;
|
||||
switch (trackTime)
|
||||
{
|
||||
case TrackTimeSubmoduleMovable movable:
|
||||
beatStart = beatManager.GetBeatFromTime(movable.trackStartTime);
|
||||
beatEnd = beatManager.GetBeatFromTime(movable.trackEndTime);
|
||||
return true;
|
||||
case TrackTimeSubmoduleStatic stat:
|
||||
float songTime = CurrentSongTime;
|
||||
beatStart = beatManager.GetBeatFromTime(songTime);
|
||||
beatEnd = beatManager.GetBeatFromTime(songTime + stat.trackTotalTime);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetTrackPercent(float noteTime, TrackTimeSubmodule trackTime, out float trackPercent)
|
||||
{
|
||||
trackPercent = 0f;
|
||||
|
||||
switch (trackTime)
|
||||
{
|
||||
case TrackTimeSubmoduleMovable movable:
|
||||
trackPercent = Mathf.Clamp01(movable.GetTrackPercentRaw(noteTime));
|
||||
return true;
|
||||
case TrackTimeSubmoduleStatic stat:
|
||||
float startMove = noteTime - stat.trackTotalTime;
|
||||
float percent = AnimationCurveEvaluator.Evaluate(
|
||||
stat.animationCurveType,
|
||||
(CurrentSongTime - startMove) / stat.trackTotalTime);
|
||||
trackPercent = 1f - Mathf.Clamp01(percent);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class NotePreviewData : MonoBehaviour
|
||||
{
|
||||
@@ -101,9 +160,8 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
});
|
||||
|
||||
}
|
||||
public void Refresh(SplineComputer spline, TrackTimeSubmoduleMovable trackTime, float horizonWidth)
|
||||
public void Refresh(SplineComputer spline, float trackPercent, float horizonWidth)
|
||||
{
|
||||
float trackPercent = Mathf.Clamp01(trackTime.GetTrackPercentRaw(noteTime));
|
||||
SplineSample sample = spline.Evaluate(trackPercent);
|
||||
Vector3 sideOffset = sample.rotation * (noteBase1.noteVisual != null ? noteBase1.noteVisual.transformSubmodule.originalPosition : Vector3.zero);
|
||||
Vector3 worldPos = sample.position;
|
||||
@@ -155,15 +213,17 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
}
|
||||
}
|
||||
// 刷新所有预览
|
||||
SplineComputer spline = TrackedTrack.trackPathSubmodule.path;
|
||||
var trackTime = TrackedTrack.trackTimeSubmodule as TrackTimeSubmoduleMovable;
|
||||
if (!TryGetTrackContext(out SplineComputer spline, out TrackTimeSubmodule trackTime)) return;
|
||||
foreach (var preview in NotePreviews.Values)
|
||||
{
|
||||
if (preview != null)
|
||||
{
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
preview.Refresh(spline, trackTime, horizonWidth);
|
||||
if (TryGetTrackPercent(preview.noteTime, trackTime, out float trackPercent))
|
||||
{
|
||||
preview.Refresh(spline, trackPercent, horizonWidth);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -256,16 +316,16 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
if (!_isEnabled) return;
|
||||
|
||||
// 获取数据源
|
||||
SplineComputer splineComputer = TrackedTrack.trackPathSubmodule.path;
|
||||
var trackTime = TrackedTrack.trackTimeSubmodule as TrackTimeSubmoduleMovable;
|
||||
float beatStart = EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackStartTime);
|
||||
float beatEnd = EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackEndTime);
|
||||
if (!TryGetTrackContext(out SplineComputer splineComputer, out TrackTimeSubmodule trackTime)) return;
|
||||
if (!TryGetBeatRange(out float beatStart, out float beatEnd)) return;
|
||||
int beatDiver = Mathf.Max(1, BeatDiver);
|
||||
float beatStep = 1f / beatDiver;
|
||||
|
||||
// 2. 批量生成
|
||||
for (float b = beatStart - 1; b <= beatEnd + 1f / BeatDiver; b += 1f / BeatDiver)
|
||||
for (float b = beatStart - 1; b <= beatEnd + beatStep; b += beatStep)
|
||||
{
|
||||
float timeAtBeat = EditorManager.instance.songInformation.beatManager.GetTimeFromBeat(b);
|
||||
float trackPercent = Mathf.Clamp01(trackTime.GetTrackPercentRaw(timeAtBeat));
|
||||
if (!TryGetTrackPercent(timeAtBeat, trackTime, out float trackPercent)) continue;
|
||||
|
||||
CalculateLinePositions(splineComputer.Evaluate(trackPercent), out Vector3 p0, out Vector3 p1);
|
||||
|
||||
@@ -275,7 +335,9 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
Color color = (Mathf.Abs(b - Mathf.Round(b)) <= 0.01f) ? Color.green : Color.cyan;
|
||||
SetupLineRenderer(lr, p0, p1, color);
|
||||
|
||||
float bi = (trackPercent >= 1f) ? EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackEndTime) : b;
|
||||
float bi = trackTime is TrackTimeSubmoduleMovable movable && trackPercent >= 1f
|
||||
? EditorManager.instance.songInformation.beatManager.GetBeatFromTime(movable.trackEndTime)
|
||||
: b;
|
||||
Beats.Add(bi < 0 ? 0f : bi);
|
||||
BeatLines.Add(lr);
|
||||
}
|
||||
@@ -292,19 +354,19 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
return;
|
||||
}
|
||||
|
||||
SplineComputer splineComputer = TrackedTrack.trackPathSubmodule.path;
|
||||
var trackTime = TrackedTrack.trackTimeSubmodule as TrackTimeSubmoduleMovable;
|
||||
float beatStart = EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackStartTime);
|
||||
float beatEnd = EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackEndTime);
|
||||
if (!TryGetTrackContext(out SplineComputer splineComputer, out TrackTimeSubmodule trackTime)) return;
|
||||
if (!TryGetBeatRange(out float beatStart, out float beatEnd)) return;
|
||||
int beatDiver = Mathf.Max(1, BeatDiver);
|
||||
float beatStep = 1f / beatDiver;
|
||||
|
||||
int index = 0;
|
||||
// 重置 Beats 列表以匹配新的位置
|
||||
Beats.Clear();
|
||||
|
||||
for (float b = beatStart - 1; b <= beatEnd + 1f / BeatDiver; b += 1f / BeatDiver)
|
||||
for (float b = beatStart - 1; b <= beatEnd + beatStep; b += beatStep)
|
||||
{
|
||||
float timeAtBeat = EditorManager.instance.songInformation.beatManager.GetTimeFromBeat(b);
|
||||
float trackPercent = Mathf.Clamp01(trackTime.GetTrackPercentRaw(timeAtBeat));
|
||||
if (!TryGetTrackPercent(timeAtBeat, trackTime, out float trackPercent)) continue;
|
||||
|
||||
// 如果超出范围,跳过更新(除非你想一直显示)
|
||||
// 这里沿用你 UpdateBeatLine 的逻辑
|
||||
@@ -325,7 +387,9 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
|
||||
Color color = (Mathf.Abs(b - Mathf.Round(b)) <= 0.01f) ? Color.green : Color.cyan;
|
||||
SetupLineRenderer(lr, p0, p1, color, false);
|
||||
float bi = (trackPercent >= 1f) ? EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackEndTime) : b;
|
||||
float bi = trackTime is TrackTimeSubmoduleMovable movable && trackPercent >= 1f
|
||||
? EditorManager.instance.songInformation.beatManager.GetBeatFromTime(movable.trackEndTime)
|
||||
: b;
|
||||
Beats.Add(bi < 0 ? 0f : bi);
|
||||
index++;
|
||||
}
|
||||
@@ -559,10 +623,11 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
return null;
|
||||
}
|
||||
fastNoteTracker.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
|
||||
fastNoteTracker.IsEnabled = isEnabled;
|
||||
fastNoteTracker.showNotePreview = showNotePreview;
|
||||
fastNoteTracker.horizonWidth = horizonWidth;
|
||||
fastNoteTracker.BeatDiver = beatDiver;
|
||||
fastNoteTracker.BeatDiver = Mathf.Max(1, beatDiver);
|
||||
fastNoteTracker._isEnabled = isEnabled;
|
||||
fastNoteTracker._showNotePreview = showNotePreview;
|
||||
fastNoteTracker.Refresh();
|
||||
return fastNoteTracker;
|
||||
}
|
||||
|
||||
@@ -615,12 +680,12 @@ namespace Ichni.RhythmGame.Beatmap
|
||||
|
||||
public override GameElement DuplicateBM(GameElement attached)
|
||||
{
|
||||
return FastNoteTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, attached);
|
||||
return FastNoteTracker.GenerateElement(elementName, Guid.NewGuid(), tags, false, attached, IsEnabled, showNotePreview, horizonWidth, beatDiver);
|
||||
}
|
||||
|
||||
public override void ExecuteBM()
|
||||
{
|
||||
FastNoteTracker.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid));
|
||||
FastNoteTracker.GenerateElement(elementName, elementGuid, tags, false, GetElement(attachedElementGuid), IsEnabled, showNotePreview, horizonWidth, beatDiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Ichni.RhythmGame
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Note Info")
|
||||
.InputField(nameof(exactJudgeTime), "exactJudgeTime")
|
||||
.OnChanged(() => UpdateNoteInTrack(CoreServices.TimeProvider.SongTime))
|
||||
.OnChanged(HandleExactJudgeTimeChanged)
|
||||
.Mark("ExactJudgeTime")
|
||||
.Button("Save Note Prefab", () =>
|
||||
{
|
||||
@@ -81,6 +81,14 @@ namespace Ichni.RhythmGame
|
||||
.EnabledIf(() => noteVisual == null)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private void HandleExactJudgeTimeChanged()
|
||||
{
|
||||
float songTime = CoreServices.TimeProvider?.SongTime ?? EditorManager.instance.songInformation.songTime;
|
||||
UpdateNoteInTrack(songTime);
|
||||
Refresh();
|
||||
CoreServices.UpdateScheduler?.NoteScheduler.ManualTick(songTime);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,10 +99,14 @@ namespace Ichni.RhythmGame
|
||||
CommandManager.ExecuteCreate(() => TrackHeadPoint.GenerateElement("New Track Head Point", Guid.NewGuid(), new List<string>(), true, this, false, Vector3.zero));
|
||||
})
|
||||
.EnabledIf(() => trackTimeSubmodule is TrackTimeSubmoduleMovable)
|
||||
.Button("Tap", () => CommandManager.ExecuteCreate(() => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Stay", () => CommandManager.ExecuteCreate(() => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f)))
|
||||
.Button("Hold", () => CommandManager.ExecuteCreate(() => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f)))
|
||||
.Button("Flick", () => CommandManager.ExecuteCreate(() => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>())))
|
||||
.Button("Tap", () => CommandManager.ExecuteCreate(() => PrepareGeneratedNote(Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, GetDefaultNoteGenerateTime()))))
|
||||
.Button("Stay", () => CommandManager.ExecuteCreate(() => PrepareGeneratedNote(Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, GetDefaultNoteGenerateTime()))))
|
||||
.Button("Hold", () => CommandManager.ExecuteCreate(() =>
|
||||
{
|
||||
float startTime = GetDefaultNoteGenerateTime();
|
||||
return PrepareGeneratedNote(Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, startTime, startTime + 1f));
|
||||
}))
|
||||
.Button("Flick", () => CommandManager.ExecuteCreate(() => PrepareGeneratedNote(Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, GetDefaultNoteGenerateTime(), new List<Vector2>()))))
|
||||
.Button("Particle Tracker", () =>
|
||||
{
|
||||
CommandManager.ExecuteCreate(() => ParticleTracker.GenerateElement("New Particle Tracker", Guid.NewGuid(), new List<string>(), true, this,
|
||||
@@ -233,6 +237,17 @@ namespace Ichni.RhythmGame
|
||||
#endregion
|
||||
|
||||
#region [工具方法] Tool Methods
|
||||
private static float GetDefaultNoteGenerateTime()
|
||||
{
|
||||
return CoreServices.TimeProvider?.SongTime ?? EditorManager.instance.songInformation.songTime;
|
||||
}
|
||||
|
||||
private static T PrepareGeneratedNote<T>(T note) where T : NoteBase
|
||||
{
|
||||
note.noteVisual?.transformSubmodule?.Refresh();
|
||||
return note;
|
||||
}
|
||||
|
||||
[Button("Test GetAllNotes")]
|
||||
public List<NoteBase> GetAllNotes()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Ichni.RhythmGame
|
||||
public GameCamera gameCamera;
|
||||
public SceneCamera sceneCamera => EditorManager.instance.cameraManager.sceneCamera;
|
||||
|
||||
public float farClipRange = 1000f;
|
||||
public float farClipRange = 2000f;
|
||||
#endregion
|
||||
|
||||
#region [生命周期] Lifecycle & Factory
|
||||
|
||||
@@ -67,7 +67,10 @@ namespace Ichni
|
||||
finishTime = finishTime
|
||||
};
|
||||
_isDirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterNote(note, activationTime, finishTime);
|
||||
}
|
||||
|
||||
/// <summary>手动触发排序(若需要在注册大批 Note 后一次性完成)</summary>
|
||||
|
||||
Reference in New Issue
Block a user