@@ -28,6 +28,7 @@ namespace Ichni
|
||||
public BackgroundController backgroundController;
|
||||
public GridController gridController;
|
||||
public CameraManager cameraManager;
|
||||
public NoteManager noteManager;
|
||||
public Ichni.Editor.PostProcessingManager postProcessingManager;
|
||||
public Canvas judgeHintCanvas;
|
||||
public Canvas inspectorCanvas;
|
||||
@@ -59,7 +60,7 @@ namespace Ichni
|
||||
isLoaded = false;
|
||||
projectManager = new ProjectManager();
|
||||
operationManager = new OperationManager();
|
||||
|
||||
noteManager = new NoteManager();
|
||||
if (!ES3.FileExists(Application.streamingAssetsPath + "/EditorSettings.es3"))
|
||||
{
|
||||
editorSettings = new EditorSettings(300, 3, 100, 100, 60);
|
||||
@@ -120,6 +121,7 @@ namespace Ichni
|
||||
private void Update()
|
||||
{
|
||||
if (isLoaded) projectManager.autoSaveManager.UpdateAutoSave();
|
||||
noteManager.UpdateNote();
|
||||
}
|
||||
|
||||
public void LoadProject(string projectName)
|
||||
|
||||
@@ -14,10 +14,9 @@ namespace Ichni.Editor
|
||||
public partial class InputListener : MonoBehaviour
|
||||
{
|
||||
public static InputListener instance;
|
||||
private PointerEventData pointerEventData;
|
||||
private bool isPointerOverUI;
|
||||
public bool isPointerOverUI;
|
||||
public TMP_Text hoveredUIText;
|
||||
public GameObject hoveredUI;
|
||||
//public GameObject hoveredUI;
|
||||
public EventSystem eventSystem;
|
||||
public List<GraphicRaycaster> graphicRaycasters;
|
||||
private List<SelectionConnector> lastHitConnectors = new List<SelectionConnector>();
|
||||
@@ -47,7 +46,7 @@ namespace Ichni.Editor
|
||||
if (currentMousePosition != lastMousePosition || frameCount % uiCheckFrameInterval == 0)
|
||||
{
|
||||
lastMousePosition = currentMousePosition;
|
||||
isPointerOverUI = IsPointerOverUI(out hoveredUI);
|
||||
isPointerOverUI = IsPointerOverUI();
|
||||
}
|
||||
SceneCameraOperation();
|
||||
MusicPlayerOperation();
|
||||
@@ -308,68 +307,34 @@ namespace Ichni.Editor
|
||||
{
|
||||
private TMP_Text UIText => EditorManager.instance.UIText;
|
||||
|
||||
public bool IsPointerOverUI(out GameObject hoveredUI)
|
||||
{
|
||||
hoveredUI = null;
|
||||
// 类级别缓存
|
||||
private PointerEventData EventData;
|
||||
private List<RaycastResult> raycastResults = new List<RaycastResult>();
|
||||
|
||||
public bool IsPointerOverUI()
|
||||
{
|
||||
if (Mouse.current == null) return false;
|
||||
|
||||
pointerEventData = new PointerEventData(eventSystem)
|
||||
if (EventData == null)
|
||||
{
|
||||
position = Mouse.current.position.ReadValue()
|
||||
};
|
||||
EventData = new PointerEventData(eventSystem);
|
||||
}
|
||||
EventData.position = Mouse.current.position.ReadValue();
|
||||
|
||||
List<RaycastResult> allResults = new List<RaycastResult>();
|
||||
raycastResults.Clear(); // 复用列表
|
||||
EventSystem.current.RaycastAll(EventData, raycastResults);
|
||||
|
||||
// 使用EventSystem的RaycastAll来确保检测所有UI
|
||||
EventSystem.current.RaycastAll(pointerEventData, allResults);
|
||||
|
||||
// 或者手动检测所有GraphicRaycaster
|
||||
foreach (var raycaster in FindObjectsOfType<GraphicRaycaster>())
|
||||
for (int i = 0; i < raycastResults.Count; i++)
|
||||
{
|
||||
if (!raycaster.enabled || !raycaster.gameObject.activeInHierarchy)
|
||||
continue;
|
||||
|
||||
List<RaycastResult> results = new List<RaycastResult>();
|
||||
raycaster.Raycast(pointerEventData, results);
|
||||
allResults.AddRange(results);
|
||||
var result = raycastResults[i];
|
||||
if (result.gameObject != null &&
|
||||
result.gameObject.activeInHierarchy &&
|
||||
result.gameObject.GetComponent<RectTransform>() != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除无效结果
|
||||
allResults.RemoveAll(r =>
|
||||
r.gameObject == null ||
|
||||
!r.gameObject.activeInHierarchy ||
|
||||
!r.gameObject.GetComponent<RectTransform>());
|
||||
|
||||
if (allResults.Count > 0)
|
||||
{
|
||||
// 完整排序
|
||||
// allResults.Sort((a, b) =>
|
||||
// {
|
||||
// // 先按sorting layer
|
||||
// int layerCompare = SortingLayer.GetLayerValueFromID(b.sortingLayer)
|
||||
// .CompareTo(SortingLayer.GetLayerValueFromID(a.sortingLayer));
|
||||
// if (layerCompare != 0) return layerCompare;
|
||||
|
||||
// // 再按sorting order
|
||||
// int orderCompare = b.sortingOrder.CompareTo(a.sortingOrder);
|
||||
// if (orderCompare != 0) return orderCompare;
|
||||
|
||||
// // 最后按depth
|
||||
// return b.depth.CompareTo(a.depth);
|
||||
// });
|
||||
|
||||
// hoveredUI = allResults[0].gameObject;
|
||||
// string text = $"UI: {hoveredUI.name}, Layer: {SortingLayer.IDToName(allResults[0].sortingLayer)}, Order: {allResults[0].sortingOrder}";
|
||||
// if (UIText.text != text)
|
||||
// {
|
||||
// UIText.text = text;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//UIText.text = "No UI";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
162
Assets/Scripts/Manager/NoteManager.cs
Normal file
162
Assets/Scripts/Manager/NoteManager.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
public class NoteManager
|
||||
{
|
||||
public static NoteManager instance;
|
||||
public NoteManager()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private List<NoteBase> allNotes = new List<NoteBase>();
|
||||
public List<NoteBase> activeNotes = new List<NoteBase>();
|
||||
private List<NoteBase> notesToRemove = new List<NoteBase>();
|
||||
|
||||
public int currentActiveNoteCount => activeNotes.Count;
|
||||
private float lastKnownTime = -1f;
|
||||
|
||||
public void AddNote(NoteBase note)
|
||||
{
|
||||
allNotes.Add(note);
|
||||
// 只在添加时排序一次
|
||||
allNotes.Sort((a, b) => a.NoteAppearTime.CompareTo(b.NoteAppearTime));
|
||||
|
||||
note.UpdateNote(); // 初始化状态
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
note.noteVisual?.generateEffect?.PreExecute();
|
||||
note.noteVisual?.noteMain.SetActive(true);
|
||||
note.UpdateNote(); // 确保在下一帧也更新一次,防止遗漏
|
||||
});
|
||||
}
|
||||
|
||||
public void RemoveNote(NoteBase note)
|
||||
{
|
||||
activeNotes.Remove(note);
|
||||
allNotes.Remove(note);
|
||||
}
|
||||
|
||||
public void UpdateNote()
|
||||
{
|
||||
if (allNotes.Count == 0) return;
|
||||
|
||||
float currentTime = EditorManager.instance.songInformation.songTime;
|
||||
|
||||
// 检测时间方向
|
||||
bool isTimeMovingForward = currentTime >= lastKnownTime;
|
||||
lastKnownTime = currentTime;
|
||||
|
||||
// 清空待移除列表
|
||||
notesToRemove.Clear();
|
||||
// 处理时间前进的情况 - 添加新音符
|
||||
if (isTimeMovingForward)
|
||||
{
|
||||
// 查找所有应该激活但尚未激活的音符
|
||||
for (int i = 0; i < allNotes.Count; i++)
|
||||
{
|
||||
var note = allNotes[i];
|
||||
|
||||
// 如果音符应该出现但还没激活
|
||||
if (note.NoteAppearTime <= currentTime
|
||||
)
|
||||
{
|
||||
if (!activeNotes.Contains(note)) activeNotes.Add(note);
|
||||
}
|
||||
else if (note.exactJudgeTime < currentTime) break;
|
||||
}
|
||||
}
|
||||
// 处理时间倒退的情况 - 调整活跃列表
|
||||
else
|
||||
{
|
||||
// 移除在当前时间之后出现的音符
|
||||
for (int i = activeNotes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var note = activeNotes[i];
|
||||
if (note.NoteAppearTime > currentTime)
|
||||
{
|
||||
notesToRemove.Add(note);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < allNotes.Count; i++)
|
||||
{
|
||||
var note = allNotes[i];
|
||||
|
||||
// 如果音符应该出现但还没激活
|
||||
if (note.isFirstJudged && note.exactJudgeTime > currentTime
|
||||
)
|
||||
{
|
||||
if (!activeNotes.Contains(note)) activeNotes.Add(note);
|
||||
}
|
||||
// else if (note.NoteAppearTime < currentTime)
|
||||
// {
|
||||
// break; // 提前退出循环,优化性能
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 更新所有活跃音符
|
||||
for (int i = 0; i < activeNotes.Count; i++)
|
||||
{
|
||||
var note = activeNotes[i];
|
||||
note.UpdateNote();
|
||||
// Debug.Log($"Updating Note {note.elementName} at time {currentTime}");
|
||||
// 标记已判定的音符等待移除
|
||||
if (note.isFirstJudged)
|
||||
{
|
||||
notesToRemove.Add(note);
|
||||
}
|
||||
}
|
||||
|
||||
// 移除标记的音符
|
||||
for (int i = 0; i < notesToRemove.Count; i++)
|
||||
{
|
||||
activeNotes.Remove(notesToRemove[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 重置所有状态(用于歌曲重新开始等)
|
||||
public void ResetAll()
|
||||
{
|
||||
activeNotes.Clear();
|
||||
notesToRemove.Clear();
|
||||
lastKnownTime = -1f;
|
||||
|
||||
// 不重置音符状态,让音符自己的逻辑处理
|
||||
}
|
||||
|
||||
// 跳转到指定时间
|
||||
public void SeekToTime(float targetTime)
|
||||
{
|
||||
// 清空当前活跃列表
|
||||
activeNotes.Clear();
|
||||
notesToRemove.Clear();
|
||||
|
||||
// 添加在目标时间之前应该出现的音符
|
||||
for (int i = 0; i < allNotes.Count; i++)
|
||||
{
|
||||
var note = allNotes[i];
|
||||
|
||||
// 添加在目标时间之前应该出现的音符
|
||||
if (note.NoteAppearTime <= targetTime)
|
||||
{
|
||||
activeNotes.Add(note);
|
||||
}
|
||||
}
|
||||
|
||||
lastKnownTime = targetTime;
|
||||
}
|
||||
|
||||
// 获取所有音符(只读)
|
||||
public IReadOnlyList<NoteBase> GetAllNotes()
|
||||
{
|
||||
return allNotes.AsReadOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Manager/NoteManager.cs.meta
Normal file
11
Assets/Scripts/Manager/NoteManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fe401fc051728b49a4e682f518ffc54
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user