点击选中

This commit is contained in:
SoulliesOfficial
2025-04-16 08:33:34 -04:00
parent 11543b4997
commit 97427b0bf3
24 changed files with 634 additions and 139 deletions

View File

@@ -0,0 +1,38 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Ichni.RhythmGame
{
public class SelectSubmodule : SubmoduleBase
{
private GameElement elementToSelect;
public SelectSubmodule(GameElement attachedGameElement, GameElement elementToSelect = null) : base(attachedGameElement)
{
(attachedGameElement as IHaveSelectSubmodule).selectSubmodule = this;
(attachedGameElement).gameObject.layer = LayerMask.NameToLayer("Selectable");
this.elementToSelect = elementToSelect == null ? attachedGameElement : elementToSelect;
}
public void SelectGameElement()
{
Debug.Log(elementToSelect);
EditorManager.instance.operationManager.ClearSelectedElements();
EditorManager.instance.operationManager.AddSelectElement(elementToSelect);
EditorManager.instance.uiManager.inspector.SetInspector(elementToSelect);
EditorManager.instance.timeline.SetTimeLine(elementToSelect);
}
public override void SaveBM()
{
//这个模块不需要存档
}
}
public interface IHaveSelectSubmodule
{
public SelectSubmodule selectSubmodule { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e91fffff157a0d543850b1ce45419ff8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -53,7 +53,11 @@ namespace Ichni.RhythmGame
this.tags = tags;
EditorManager.instance.beatmapContainer.gameElementList.Add(this);
submoduleList = new List<SubmoduleBase>();
if (isFirstGenerated) SetDefaultSubmodules();
if (isFirstGenerated)
{
SetDefaultSubmodules();
}
SetParent(parentElement);
EditorManager.instance.uiManager.hierarchy.GenerateTab(this, parentElement);
@@ -70,12 +74,17 @@ namespace Ichni.RhythmGame
}
public virtual void SetEditorSubmodules()
{
}
/// <summary>
/// 在所有物体生成完毕后,执行的初始化方法
/// </summary>
public virtual void AfterInitialize()
{
SetEditorSubmodules();
}
/// <summary>

View File

@@ -4,7 +4,7 @@ using UnityEngine;
namespace Ichni.RhythmGame
{
public abstract class NoteVisualBase : SubstantialObject, IHaveEffectSubmodule
public abstract class NoteVisualBase : SubstantialObject, IHaveEffectSubmodule, IHaveSelectSubmodule
{
public NoteBase note;
@@ -15,11 +15,17 @@ namespace Ichni.RhythmGame
public List<GameObject> effectPartList;
public EffectSubmodule effectSubmodule { get; set; }
public SelectSubmodule selectSubmodule { get; set; }
public override void SetDefaultSubmodules()
{
base.SetDefaultSubmodules();
effectSubmodule = new EffectSubmodule(this, EffectSubmodule.EffectSubmodulePreset.Note);
}
public override void SetEditorSubmodules()
{
selectSubmodule = new SelectSubmodule(this, note);
}
}
}

View File

@@ -54,6 +54,7 @@ namespace Ichni.RhythmGame
public override void AfterInitialize()
{
base.AfterInitialize();
Refresh();
}
}

View File

@@ -47,6 +47,8 @@ namespace Ichni.RhythmGame
public override void AfterInitialize()
{
base.AfterInitialize();
if (trackPathSubmodule != null && trackPathSubmodule.pathNodeList.Count > 3)
{
trackPathSubmodule.ClosePath();
@@ -62,7 +64,6 @@ namespace Ichni.RhythmGame
trackPathSubmodule?.Refresh();
trackTimeSubmodule?.Refresh();
trackRendererSubmodule?.Refresh();
}
public override void OnDelete()

View File

@@ -1,4 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using Lean.Pool;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Serialization;
namespace Ichni.Editor
{
@@ -7,6 +13,8 @@ namespace Ichni.Editor
{
[Tooltip("指定用于计算缩放的摄像机(若为空则使用 Camera.main")]
public Camera sceneCamera;
public float cameraDistance;
[Tooltip("指定网格所在的平面0 = XZ (y=0), 1 = XY (z=0), 2 = YZ (x=0)")]
public int gridPlane = 0;
@@ -21,8 +29,19 @@ namespace Ichni.Editor
// 内部缓存材质
private Material gridMaterial;
public float logScale;
public float gridScale; // 1, 4, 16, 64...
[FormerlySerializedAs("showPositionText")] public bool canShowPositionText;
public bool isShowingPositionText;
public Transform textContainer;
public GameObject positionTextPrefab;
public Dictionary<GameObject, Vector3> positionTexts;
void Start()
{
positionTexts = new Dictionary<GameObject, Vector3>();
sceneCamera = EditorManager.instance.cameraManager.sceneCamera.sceneCamera;
// 实例化材质,避免修改共享材质
gridMaterial = GetComponent<MeshRenderer>().material;
@@ -35,27 +54,103 @@ namespace Ichni.Editor
sceneCamera = EditorManager.instance.cameraManager.currentCamera;
// 计算摄像机到网格平面的垂直距离
float camDistance = 0f;
cameraDistance = 0f;
Vector3 camPos = sceneCamera.transform.position;
Vector3 gridPos = transform.position;
switch (gridPlane)
{
case 0: // XZ 平面:垂直方向为 Y
camDistance = Mathf.Abs(camPos.y - gridPos.y);
cameraDistance = Mathf.Abs(camPos.y - gridPos.y);
break;
case 1: // XY 平面:垂直方向为 Z
camDistance = Mathf.Abs(camPos.z - gridPos.z);
cameraDistance = Mathf.Abs(camPos.z - gridPos.z);
break;
case 2: // YZ 平面:垂直方向为 X
camDistance = Mathf.Abs(camPos.x - gridPos.x);
cameraDistance = Mathf.Abs(camPos.x - gridPos.x);
break;
}
// 利用对数函数计算缩放等级:距离越远,网格越大
float logScale = Mathf.Floor(Mathf.Log(camDistance / distanceFactor + 1, 4));
float gridScale = baseScale * Mathf.Pow(4, logScale) * scaleMultiplier;
logScale = Mathf.Floor(Mathf.Log(cameraDistance / distanceFactor + 1, 4));
gridScale = baseScale * Mathf.Pow(4, logScale) * scaleMultiplier;
gridMaterial.SetFloat("_GridScale", 1 / gridScale);
gridMaterial.SetFloat("_DisappearEndDistance", 100 * gridScale);
if (canShowPositionText && isShowingPositionText)
{
GetPoints();
foreach (KeyValuePair<GameObject,Vector3> positionText in positionTexts)
{
positionText.Key.transform.position = positionText.Value + new Vector3(gridScale / 6, 0, gridScale / 12);
float scaleFactor = gridScale * 1.5f;
positionText.Key.transform.localScale = new Vector3(scaleFactor, scaleFactor, scaleFactor);
}
}
}
void GetPoints()
{
Ray sceneCameraRay = sceneCamera.ScreenPointToRay(new Vector2(Screen.width / 2f, Screen.height / 2f));
if (Physics.Raycast(sceneCameraRay, out RaycastHit sceneCameraHit, float.MaxValue, LayerMask.GetMask("Grid")))
{
if (sceneCameraHit.collider.gameObject == gameObject)
{
Vector3 point = sceneCameraHit.point;
float radius = gridScale * 16f;
float step = gridScale * 4f;
float minX = point.x - radius;
float maxX = point.x + radius;
float minZ = point.z - radius;
float maxZ = point.z + radius;
// 对于 X 与 Z 方向,根据网格间距取整,确保从整点开始
minX = Mathf.Floor(minX / step) * step;
maxX = Mathf.Ceil(maxX / step) * step;
minZ = Mathf.Floor(minZ / step) * step;
maxZ = Mathf.Ceil(maxZ / step) * step;
List<Vector3> newPositions = new List<Vector3>();
for (float x = minX; x <= maxX; x += step)
{
for (float z = minZ; z <= maxZ; z += step)
{
Vector3 position = new Vector3(x, 0, z);
if (!positionTexts.ContainsValue(position))
{
GameObject posText = LeanPool.Spawn(positionTextPrefab);
posText.transform.position = position + new Vector3(gridScale / 8, 0, gridScale / 16);
posText.transform.forward = -transform.up;
posText.GetComponent<TMP_Text>().text = $"({Mathf.RoundToInt(position.x)}, {Mathf.RoundToInt(position.z)})";
posText.transform.SetParent(textContainer);
positionTexts.Add(posText, position);
}
newPositions.Add(new Vector3(x, 0, z));
}
}
List<GameObject> toRemove = new List<GameObject>();
// 清除不在新范围内的Text
foreach (KeyValuePair<GameObject, Vector3> positionText in positionTexts)
{
if (!newPositions.Contains(positionText.Value))
{
LeanPool.Despawn(positionText.Key);
toRemove.Add(positionText.Key);
}
}
foreach (GameObject text in toRemove)
{
positionTexts.Remove(text);
}
}
}
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using Lean.Pool;
using UnityEngine;
namespace Ichni.Editor
@@ -19,11 +20,14 @@ namespace Ichni.Editor
public bool xPlaneEnabled;
public bool zPlaneEnabled;
public bool isYPlaneShowingPositionText;
private void Start()
{
yPlaneEnabled = true;
xPlaneEnabled = false;
zPlaneEnabled = false;
isYPlaneShowingPositionText = true;
RefreshPlanes();
}
@@ -38,11 +42,15 @@ namespace Ichni.Editor
var yPlaneToggle =
inspector.GenerateToggle(this, gridSettings, "Y Plane", nameof(yPlaneEnabled))
.AddListenerFunction(RefreshPlanes);
var xPlaneToggle =
inspector.GenerateToggle(this, gridSettings, "X Plane", nameof(xPlaneEnabled))
.AddListenerFunction(RefreshPlanes);
var zPlaneToggle =
inspector.GenerateToggle(this, gridSettings, "Z Plane", nameof(zPlaneEnabled))
.AddListenerFunction(RefreshPlanes);
var xPlaneToggle =
inspector.GenerateToggle(this, gridSettings, "X Plane", nameof(xPlaneEnabled))
var yPlaneShowPositionToggle =
inspector.GenerateToggle(this, gridSettings, "Show Y Plane Position", nameof(isYPlaneShowingPositionText))
.AddListenerFunction(RefreshPlanes);
}
@@ -51,6 +59,17 @@ namespace Ichni.Editor
yPlaneGrid.gameObject.SetActive(yPlaneEnabled);
xPlaneGrid.gameObject.SetActive(xPlaneEnabled);
zPlaneGrid.gameObject.SetActive(zPlaneEnabled);
yPlaneGrid.isShowingPositionText = isYPlaneShowingPositionText;
if (!yPlaneGrid.isShowingPositionText)
{
foreach (KeyValuePair<GameObject, Vector3> positionText in yPlaneGrid.positionTexts)
{
LeanPool.Despawn(positionText.Key);
}
yPlaneGrid.positionTexts.Clear();
}
}
}
}

View File

@@ -92,6 +92,7 @@ namespace Ichni
beatmapContainer.gameElementList.ForEach(gameElement =>
{
gameElement.AfterInitialize();
gameElement.Refresh();
});
}

View File

@@ -35,6 +35,7 @@ namespace Ichni.Editor
ResolutionHintsOperation();
UIOperation();
SwitchCameraOperation();
ClickSelectElement();
}
}
@@ -232,6 +233,20 @@ namespace Ichni.Editor
}
}
}
private void ClickSelectElement()
{
if (Mouse.current.leftButton.wasPressedThisFrame && !isPointerOverUI)
{
Vector2 mousePosition = Mouse.current.position.ReadValue();
Ray ray = EditorManager.instance.cameraManager.currentCamera.ScreenPointToRay(mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, LayerMask.GetMask("Selectable")))
{
GameElement clickedElement = hit.collider.GetComponent<GameElement>();//TODO: 对于Hold这种复杂的元素需要使用连接脚本进行获取
(clickedElement as IHaveSelectSubmodule)?.selectSubmodule.SelectGameElement();
}
}
}
}
public partial class InputListener

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Ichni.RhythmGame;
using Ichni.RhythmGame.Beatmap;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Ichni.Editor
{