@@ -12,6 +12,10 @@ using Ichni.Editor;
|
||||
using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using TMPro;
|
||||
using UniRx;
|
||||
using Unity.VisualScripting;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +78,6 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
line.startColor = line.endColor = color;
|
||||
}
|
||||
|
||||
// 工具方法:刷新两个线条之间的 MeshCollider
|
||||
private void RefreshMeshCollider(LineRenderer lineA, LineRenderer lineB)
|
||||
{
|
||||
MeshCollider col = lineA.GetComponent<MeshCollider>();
|
||||
@@ -150,7 +153,7 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
GameObject obj = Instantiate(EditorManager.instance.basePrefabs.emptyObject, this.transform);
|
||||
LineRenderer lr = obj.AddComponent<LineRenderer>();
|
||||
|
||||
Color color = (b % 1f <= 0.01f) ? Color.green : Color.cyan;
|
||||
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;
|
||||
@@ -201,54 +204,29 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
BeatLines.Add(lr);
|
||||
}
|
||||
|
||||
Color color = (b % 1f <= 0.01f) ? Color.green : Color.cyan;
|
||||
Color color = (Mathf.Abs(b - Mathf.Round(b)) <= 0.01f) ? Color.green : Color.cyan;
|
||||
SetupLineRenderer(lr, p0, p1, color, false);
|
||||
|
||||
// 同步 Beats 数组,这对 AddNote 很重要
|
||||
float bi = (trackPercent >= 1f) ? EditorManager.instance.songInformation.beatManager.GetBeatFromTime(trackTime.trackEndTime) : b;
|
||||
Beats.Add(bi < 0 ? 0f : bi);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// 隐藏多余
|
||||
for (int i = index; i < BeatLines.Count; i++) BeatLines[i].gameObject.SetActive(false);
|
||||
|
||||
// 刷新 Collider
|
||||
for (int i = 0; i < index - 1; i++) RefreshMeshCollider(BeatLines[i], BeatLines[i + 1]);
|
||||
}
|
||||
// void OnDrawGizmos()
|
||||
// {
|
||||
// // 调试用,保持原样
|
||||
// if (BeatLines.Count > 0)
|
||||
// {
|
||||
// foreach (var line in BeatLines)
|
||||
// {
|
||||
// if (line != null)
|
||||
// {
|
||||
// MeshCollider collider = line.GetComponent<MeshCollider>();
|
||||
// if (collider != null && collider.sharedMesh != null)
|
||||
// {
|
||||
// Gizmos.color = new Color(0, 1, 0, 0.3f);
|
||||
// // DrawMesh 需要传入位置和旋转,因为 Mesh 数据是局部的
|
||||
// Gizmos.DrawWireMesh(collider.sharedMesh, line.transform.position, line.transform.rotation);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public bool ForceRefresh = false;
|
||||
void Update()
|
||||
{
|
||||
if (ForceRefresh)
|
||||
{
|
||||
AdjustBeatLine();
|
||||
}
|
||||
|
||||
if (InputListener.instance.isPointerOverUI) return;
|
||||
CastRay();
|
||||
if (IsEnabled && selectedLine != null)
|
||||
{
|
||||
DetectNote();
|
||||
}
|
||||
if (ForceRefresh)
|
||||
{
|
||||
AdjustBeatLine();
|
||||
}
|
||||
|
||||
}
|
||||
public void CastRay()
|
||||
@@ -262,44 +240,30 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
if (Physics.RaycastAll(ray).FirstOrDefault(h => h.collider.CompareTag("LineRenderer")).collider != null)
|
||||
{
|
||||
hit = Physics.RaycastAll(ray).First(h => h.collider.CompareTag("LineRenderer"));
|
||||
if (hit.collider.CompareTag("LineRenderer"))
|
||||
|
||||
LineRenderer hoveredLine = hit.collider.GetComponent<LineRenderer>();
|
||||
if (BeatLines.Contains(hoveredLine))
|
||||
{
|
||||
LineRenderer hoveredLine = hit.collider.GetComponent<LineRenderer>();
|
||||
|
||||
// [修复] DOTween 逻辑
|
||||
if (BeatLines.Contains(hoveredLine))
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
Debug.Log($"Clicked on line area: {hoveredLine.gameObject.name} at {hit.point}");
|
||||
}
|
||||
if (selectedLine != hoveredLine)
|
||||
{
|
||||
if (selectedLine != null)
|
||||
{
|
||||
Debug.Log($"Clicked on line area: {hoveredLine.gameObject.name} at {hit.point}");
|
||||
}
|
||||
|
||||
// 如果悬停到了新的线
|
||||
if (selectedLine != hoveredLine)
|
||||
{
|
||||
// 1. 还原上一条选中的线
|
||||
if (selectedLine != null)
|
||||
{
|
||||
// 杀掉旧的动画
|
||||
|
||||
selectedLine.startWidth = 0.05f;
|
||||
selectedLine.endWidth = 0.05f;
|
||||
}
|
||||
|
||||
// 2. 更新当前选中的线
|
||||
selectedLine = hoveredLine;
|
||||
|
||||
// 3. 对新线开启宽度的 PingPong 动画
|
||||
|
||||
selectedLine.startWidth = 0.15f;
|
||||
selectedLine.endWidth = 0.15f;
|
||||
selectedLine.startWidth = 0.05f;
|
||||
selectedLine.endWidth = 0.05f;
|
||||
}
|
||||
selectedLine = hoveredLine;
|
||||
selectedLine.startWidth = 0.15f;
|
||||
selectedLine.endWidth = 0.15f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// [优化] 如果鼠标移到了空白处,应该停止所有高亮
|
||||
if (selectedLine != null)
|
||||
{
|
||||
selectedLine.startWidth = 0.05f;
|
||||
@@ -335,53 +299,86 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
float time = EditorManager.instance.songInformation.beatManager.GetTimeFromBeat(
|
||||
Beats[BeatLines.IndexOf(selectedLine)]
|
||||
);
|
||||
Vector3 pos = new Vector3();
|
||||
NoteBase a = null;
|
||||
switch (NoteCode)
|
||||
{
|
||||
case 0:
|
||||
Tap a = Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time);
|
||||
|
||||
//a.noteVisual.transformSubmodule.originalPosition = new Vector3(isExpand ? (localMousePosition.x / XWidth) : 0f, 0f, 0f);
|
||||
case 0:
|
||||
a = Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time);
|
||||
a.noteVisual.transformSubmodule.Refresh();
|
||||
pos = a.noteVisual.transform.position;
|
||||
break;
|
||||
case 3:
|
||||
Hold b = Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time, time + 0.5f);
|
||||
a = Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time, time + 0.5f);
|
||||
a.noteVisual.transformSubmodule.Refresh();
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
StartCoroutine(DraggingHold((Hold)a));
|
||||
});
|
||||
|
||||
//b.noteVisual.transformSubmodule.originalPosition = new Vector3(isExpand ? (localMousePosition.x / XWidth) : 0f, 0f, 0f);
|
||||
b.noteVisual.transformSubmodule.Refresh();
|
||||
pos = b.noteVisual.transform.position;
|
||||
break;
|
||||
case 1:
|
||||
Stay c = Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time);
|
||||
|
||||
//c.noteVisual.transformSubmodule.originalPosition = new Vector3(isExpand ? (localMousePosition.x / XWidth) : 0f, 0f, 0f);
|
||||
c.noteVisual.transformSubmodule.Refresh();
|
||||
pos = c.noteVisual.transform.position;
|
||||
a = Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time);
|
||||
a.noteVisual.transformSubmodule.Refresh();
|
||||
break;
|
||||
case 2:
|
||||
Flick d = Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time, new List<Vector2>());
|
||||
|
||||
//d.noteVisual.transformSubmodule.originalPosition = new Vector3(isExpand ? (localMousePosition.x / XWidth) : 0f, 0f, 0f);
|
||||
d.noteVisual.transformSubmodule.Refresh();
|
||||
pos = d.noteVisual.transform.position;
|
||||
a = Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, TrackedTrack, time, new List<Vector2>());
|
||||
a.noteVisual.transformSubmodule.Refresh();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CreateTextHint(pos, $"A Note Added");
|
||||
Observable.NextFrame().Subscribe(_ =>
|
||||
{
|
||||
CreateTextHint(a);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
private void CreateTextHint(Vector3 worldPos, string content)
|
||||
private IEnumerator DraggingHold(Hold hold)
|
||||
{
|
||||
GameObject obj = Instantiate(EditorManager.instance.basePrefabs.emptyObject, this.transform);
|
||||
LineRenderer lr = obj.AddComponent<LineRenderer>();
|
||||
lr.startWidth = lr.endWidth = 0.05f;
|
||||
lr.positionCount = 2;
|
||||
lr.material = EditorManager.instance.basePrefabs.defaultTrailMaterial;
|
||||
lr.startColor = lr.endColor = Color.yellow;
|
||||
lr.SetPosition(0, hold.noteVisual.transform.position);
|
||||
lr.SetPosition(1, hold.noteVisual.transform.position);
|
||||
while (Keyboard.current.digit4Key.isPressed && selectedLine != null)
|
||||
|
||||
{
|
||||
yield return null;
|
||||
try
|
||||
{
|
||||
|
||||
float time = EditorManager.instance.songInformation.beatManager.GetTimeFromBeat(
|
||||
Beats[BeatLines.IndexOf(selectedLine)]
|
||||
);
|
||||
hold.holdEndTime = time < hold.exactJudgeTime ? hold.exactJudgeTime + 0.1f : time;
|
||||
hold.noteVisual.transformSubmodule.Refresh();
|
||||
lr.SetPosition(1, (selectedLine.GetPosition(0) + selectedLine.GetPosition(1)) / 2);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogWarning(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
Destroy(lr.gameObject);
|
||||
CreateTextHint(hold);
|
||||
}
|
||||
private void CreateTextHint(NoteBase noteBase)
|
||||
{
|
||||
// 1. 创建一个新的 GameObject
|
||||
string content = noteBase.elementName;
|
||||
Vector3 worldPos = noteBase.noteVisual.transform.position;
|
||||
GameObject hintObj = new GameObject("NoteHint_" + content);
|
||||
hintObj.transform.position = worldPos;
|
||||
|
||||
// 2. 添加 TextMeshPro 组件 (注意是 TextMeshPro,不是 TextMeshProUGUI)
|
||||
// 因为我们在 3D 空间生成,所以使用非 UI 版本
|
||||
TextMeshPro text = hintObj.AddComponent<TextMeshPro>();
|
||||
|
||||
// 3. 配置文字属性
|
||||
text.text = content;
|
||||
text.fontSize = 6; // 根据你的缩放调整大小
|
||||
@@ -393,6 +390,7 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
|
||||
// 5. 动画效果:向上移动 1 个单位,并同时淡出
|
||||
// 1 秒后执行
|
||||
hintObj.transform.DOScale(Vector3.one * 1.2f, 1f).SetEase(Ease.OutBack).From(Vector3.zero);
|
||||
hintObj.transform.DOMoveY(worldPos.y + 1f, 1f);
|
||||
text.DOFade(0, 1f).OnComplete(() => Destroy(hintObj));
|
||||
// 7. 让文字始终面向相机 (Billboard 效果)
|
||||
|
||||
Reference in New Issue
Block a user