@@ -5,6 +5,7 @@ using Ichni.RhythmGame;
|
||||
using Michsky.MUIP;
|
||||
using Sirenix.Utilities;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.Serialization;
|
||||
@@ -132,6 +133,24 @@ namespace Ichni.Editor
|
||||
EditorManager.instance.operationManager.ClearSelectedElements();
|
||||
EditorManager.instance.operationManager.AddSelectElement(connectedGameElement);
|
||||
}
|
||||
if (EditorManager.instance.useQuickMove)
|
||||
{
|
||||
if (connectedGameElement is IHaveTransformSubmodule haveTransformSubmodule)
|
||||
{
|
||||
QuickMover quickMover = Instantiate(EditorManager.instance.basePrefabs.QuickMoveObj).GetComponent<QuickMover>();
|
||||
quickMover.Initialize(haveTransformSubmodule);
|
||||
}
|
||||
else if (connectedGameElement is NoteBase noteBase && noteBase.noteVisual != null)
|
||||
{
|
||||
QuickMover quickMover = Instantiate(EditorManager.instance.basePrefabs.QuickMoveObj).GetComponent<QuickMover>();
|
||||
quickMover.Initialize(noteBase.noteVisual);
|
||||
}
|
||||
else if (QuickMover.instance != null)
|
||||
{
|
||||
Destroy(QuickMover.instance.gameObject);
|
||||
QuickMover.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
EditorManager.instance.uiManager.inspector.SetInspector(connectedGameElement);
|
||||
|
||||
@@ -198,7 +217,7 @@ namespace Ichni.Editor
|
||||
for (var index = 0; index < FixedList.Count; index++)
|
||||
{
|
||||
int hasYield = 0;
|
||||
while (Time.realtimeSinceStartup - startTime > 1f / StrandTimeWhileStartUp * 3f && hasYield <= 2)
|
||||
while (Time.realtimeSinceStartup - startTime > 1f / StrandTimeWhileStartUp * 3f && hasYield <= 1)
|
||||
{
|
||||
yield return null;
|
||||
hasYield += 1;
|
||||
|
||||
@@ -103,11 +103,11 @@ namespace Ichni.RhythmGame
|
||||
var container = inspector.GenerateContainer("Transform");
|
||||
var subcontainer = container.GenerateSubcontainer(1);
|
||||
var originalPosInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Position", nameof(originalPosition));
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Position", nameof(originalPosition), true);
|
||||
var originalRotInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Rotation", nameof(originalEulerAngles));
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Rotation", nameof(originalEulerAngles), true);
|
||||
var originalScaleInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Scale", nameof(originalScale));
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Scale", nameof(originalScale), true);
|
||||
var currentPosText =
|
||||
inspector.GenerateParameterText(this, subcontainer, "Current Position", nameof(currentPosition), true);
|
||||
var currentRotText =
|
||||
|
||||
8
Assets/Scripts/Graphical Tools/QuickMover.meta
Normal file
8
Assets/Scripts/Graphical Tools/QuickMover.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd71e53392300e547bd7aae27850df3a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
191
Assets/Scripts/Graphical Tools/QuickMover/QuickMover.cs
Normal file
191
Assets/Scripts/Graphical Tools/QuickMover/QuickMover.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine.InputSystem;
|
||||
using DG.Tweening;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public class QuickMover : MonoBehaviour
|
||||
{
|
||||
public static QuickMover instance;
|
||||
|
||||
[Header("Settings")]
|
||||
public float moveSensitivity = 0.5f; // 移动灵敏度
|
||||
|
||||
[Header("References")]
|
||||
public GameObject prefab;
|
||||
public BoxCollider colliderX;
|
||||
public BoxCollider colliderY;
|
||||
public BoxCollider colliderZ;
|
||||
|
||||
// 运行时状态
|
||||
private IHaveTransformSubmodule targetElement;
|
||||
private Camera editorCamera => EditorManager.instance.cameraManager.currentCamera;
|
||||
private bool isMoving;
|
||||
private int activeMoveCode = -1;
|
||||
private Vector3 initialTargetPosition;
|
||||
private Vector3 initialMouseScreenPos;
|
||||
|
||||
public GameElement targetGameElement =>
|
||||
targetElement?.transformSubmodule?.attachedGameElement;
|
||||
|
||||
public void Initialize(IHaveTransformSubmodule targetElement)
|
||||
{
|
||||
this.targetElement = targetElement;
|
||||
|
||||
if (instance != null)
|
||||
{
|
||||
|
||||
Destroy(instance.gameObject);
|
||||
}
|
||||
instance = this;
|
||||
|
||||
if (targetGameElement != null)
|
||||
transform.position = targetGameElement.transform.position;
|
||||
transform.localScale = Vector3.zero;
|
||||
StartCoroutine(WindowAnim.ShowPanelOnScale(gameObject));
|
||||
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (isMoving) return;
|
||||
|
||||
transform.position = targetGameElement.transform.position;
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
Vector2 mousePosition = Mouse.current.position.ReadValue();
|
||||
Ray ray = editorCamera.ScreenPointToRay(mousePosition);
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, LayerMask.GetMask("Default")))
|
||||
{
|
||||
if (hit.collider == colliderX)
|
||||
{
|
||||
colliderX.gameObject.transform.DOScale(colliderX.gameObject.transform.localScale * 1.2f, 0.2f);
|
||||
StartMovement(0);
|
||||
}
|
||||
else if (hit.collider == colliderY)
|
||||
{
|
||||
colliderY.gameObject.transform.DOScale(colliderY.gameObject.transform.localScale * 1.2f, 0.2f);
|
||||
StartMovement(1);
|
||||
}
|
||||
else if (hit.collider == colliderZ)
|
||||
{
|
||||
colliderZ.gameObject.transform.DOScale(colliderZ.gameObject.transform.localScale * 1.2f, 0.2f);
|
||||
StartMovement(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private Vector3 objPosOffset;
|
||||
private void StartMovement(int moveCode)
|
||||
{
|
||||
Debug.Log($"StartMovement: {moveCode}");
|
||||
if (targetGameElement == null) return;
|
||||
|
||||
activeMoveCode = moveCode;
|
||||
initialTargetPosition = targetGameElement.transform.position;
|
||||
initialMouseScreenPos = Mouse.current.position.ReadValue();
|
||||
objPosOffset = targetElement.transformSubmodule.currentPosition - targetElement.transformSubmodule.originalPosition;
|
||||
StartCoroutine(MovementRoutine());
|
||||
}
|
||||
|
||||
private IEnumerator MovementRoutine()
|
||||
{
|
||||
isMoving = true;
|
||||
|
||||
while (Mouse.current.leftButton.isPressed)
|
||||
{
|
||||
UpdateTargetPosition();
|
||||
targetElement.transformSubmodule.originalPosition = targetElement.transformSubmodule.currentPosition - objPosOffset;
|
||||
yield return null;
|
||||
}
|
||||
// 当鼠标释放时,结束移动
|
||||
EndMovement();
|
||||
isMoving = false;
|
||||
activeMoveCode = -1;
|
||||
}
|
||||
private void EndMovement()
|
||||
{
|
||||
targetGameElement.transform.position = transform.position;
|
||||
targetElement.transformSubmodule.currentPosition = targetGameElement.transform.localPosition;
|
||||
targetElement.transformSubmodule.originalPosition = targetElement.transformSubmodule.currentPosition - objPosOffset;
|
||||
targetGameElement.Refresh();
|
||||
if (activeMoveCode == 0)
|
||||
{
|
||||
colliderX.gameObject.transform.DOScale(colliderX.gameObject.transform.localScale / 1.2f, 0.2f);
|
||||
// Do something specific for X axis
|
||||
}
|
||||
else if (activeMoveCode == 1)
|
||||
{
|
||||
colliderY.gameObject.transform.DOScale(colliderY.gameObject.transform.localScale / 1.2f, 0.2f);
|
||||
// Do something specific for Y axis
|
||||
}
|
||||
else if (activeMoveCode == 2)
|
||||
{
|
||||
colliderZ.gameObject.transform.DOScale(colliderZ.gameObject.transform.localScale / 1.2f, 0.2f);
|
||||
// Do something specific for Z axis
|
||||
}
|
||||
}
|
||||
private void UpdateTargetPosition()
|
||||
{
|
||||
if (targetGameElement == null) return;
|
||||
|
||||
// 获取当前鼠标位置
|
||||
Vector3 currentMousePos = Mouse.current.position.ReadValue();
|
||||
Vector3 mouseDelta = currentMousePos - initialMouseScreenPos;
|
||||
|
||||
// 计算移动轴的世界方向
|
||||
Vector3 worldAxis = GetWorldAxis(activeMoveCode);
|
||||
|
||||
// 计算屏幕移动向量对应的世界移动量
|
||||
float worldDelta = CalculateWorldDelta(worldAxis, mouseDelta);
|
||||
|
||||
// 应用新位置
|
||||
Vector3 newPosition = initialTargetPosition + worldAxis * worldDelta;
|
||||
Vector3 newPositionFormatted = new Vector3(
|
||||
Mathf.Round(newPosition.x * 100f) / 100f,
|
||||
Mathf.Round(newPosition.y * 100f) / 100f,
|
||||
Mathf.Round(newPosition.z * 100f) / 100f
|
||||
);
|
||||
targetGameElement.transform.position = newPositionFormatted;
|
||||
transform.position = newPositionFormatted;
|
||||
}
|
||||
|
||||
private Vector3 GetWorldAxis(int moveCode)
|
||||
{
|
||||
return moveCode switch
|
||||
{
|
||||
0 => transform.right, // X轴
|
||||
1 => transform.up, // Y轴
|
||||
2 => transform.forward, // Z轴
|
||||
_ => Vector3.zero
|
||||
};
|
||||
}
|
||||
|
||||
private float CalculateWorldDelta(Vector3 worldAxis, Vector3 mouseDelta)
|
||||
{
|
||||
// 将世界轴转换为屏幕方向
|
||||
Vector3 screenRefPoint = editorCamera.WorldToScreenPoint(initialTargetPosition);
|
||||
Vector3 screenAxisEnd = editorCamera.WorldToScreenPoint(initialTargetPosition + worldAxis);
|
||||
|
||||
// 计算屏幕方向向量
|
||||
Vector3 screenAxis = (screenAxisEnd - screenRefPoint).normalized;
|
||||
|
||||
// 防止摄像机与轴平行时出现零向量
|
||||
if (screenAxis.sqrMagnitude < 0.01f) return 0;
|
||||
|
||||
// 计算鼠标移动在轴方向上的投影
|
||||
Vector2 screenAxis2D = new Vector2(screenAxis.x, screenAxis.y);
|
||||
Vector2 mouseDelta2D = new Vector2(mouseDelta.x, mouseDelta.y);
|
||||
|
||||
float projection = Vector2.Dot(mouseDelta2D, screenAxis2D.normalized);
|
||||
|
||||
// 应用灵敏度并返回
|
||||
return projection * moveSensitivity * 0.01f;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Graphical Tools/QuickMover/QuickMover.cs.meta
Normal file
11
Assets/Scripts/Graphical Tools/QuickMover/QuickMover.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cde63278924ce8944b8accfbf000a7e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -232,7 +232,7 @@ public class SampleWindow : MovableWindow//该window高度为300,横的要XWid
|
||||
far += 1f / Xdevide;
|
||||
}
|
||||
far -= 1f / Xdevide;
|
||||
float time = far * timePerBeat;
|
||||
float time = Mathf.Round(far * timePerBeat * 1000f) / 1000f;
|
||||
|
||||
|
||||
switch (NoteCode)
|
||||
|
||||
@@ -73,9 +73,11 @@ namespace Ichni.RhythmGame
|
||||
public GameObject stringIntPairUnit;
|
||||
|
||||
[Title("字体")] public Dictionary<string, TMP_FontAsset> fonts;
|
||||
|
||||
[Title("图形化动画编辑器")] public GameObject graphicalFlexibleFloatWindow;
|
||||
|
||||
|
||||
[Title("图形化动画编辑器")]
|
||||
public GameObject graphicalFlexibleFloatWindow;
|
||||
public GameObject QuickMoveObj;
|
||||
|
||||
//采音器
|
||||
|
||||
[Title("Background相关")] public Sprite defaultBackground;
|
||||
|
||||
@@ -39,9 +39,10 @@ namespace Ichni
|
||||
public CommandScripts commandScripts;
|
||||
|
||||
public NoteBase.NoteJudgeType currentJudgeType;
|
||||
public bool useNotePrefab = true;
|
||||
public bool ExpandWhileClick = true;
|
||||
|
||||
public bool useClickSelect;
|
||||
public bool useNotePrefab;
|
||||
public bool ExpandWhileClick;
|
||||
public bool useQuickMove;
|
||||
public BasePrefabsCollection basePrefabs;
|
||||
public Dictionary<string, CustomPrefabsCollection> customPrefabs;
|
||||
|
||||
@@ -55,6 +56,10 @@ namespace Ichni
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
useNotePrefab = true;
|
||||
ExpandWhileClick = true;
|
||||
useQuickMove = true;
|
||||
useClickSelect = true;
|
||||
isLoaded = false;
|
||||
projectManager = new ProjectManager();
|
||||
operationManager = new OperationManager();
|
||||
@@ -121,7 +126,15 @@ namespace Ichni
|
||||
|
||||
public void LoadProject(string projectName)
|
||||
{
|
||||
projectManager.loadManager.Load(projectName);
|
||||
if (!InformationTransistor.instance.isRecovery)
|
||||
|
||||
{
|
||||
projectManager.loadManager.Load(projectName);
|
||||
}
|
||||
else
|
||||
{
|
||||
projectManager.loadManager.LoadExport(projectName);
|
||||
}
|
||||
musicPlayer.audioSource.clip = songInformation.song;
|
||||
beatmapContainer.gameElementList.ForEach(gameElement =>
|
||||
{
|
||||
@@ -150,10 +163,14 @@ namespace Ichni
|
||||
});
|
||||
var useNotePrefabToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Note Prefab", nameof(useNotePrefab));
|
||||
|
||||
var useClickSelectToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Click Select", nameof(useClickSelect));
|
||||
var ExpandWhileClickToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Expand Tab While Click", nameof(ExpandWhileClick));
|
||||
|
||||
var useQuickMoveToggle =
|
||||
inspector.GenerateToggle(this, inGameSettings, "Use Quick Move", nameof(useQuickMove));
|
||||
|
||||
var generation = container.GenerateSubcontainer(3);
|
||||
var generateFolderButton =
|
||||
inspector.GenerateButton(this, generation, "Generate Folder",
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Ichni.Editor
|
||||
ResolutionHintsOperation();
|
||||
UIOperation();
|
||||
SwitchCameraOperation();
|
||||
ClickSelectElement();
|
||||
if (EditorManager.instance.useClickSelect) ClickSelectElement();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -183,6 +183,41 @@ namespace Ichni
|
||||
ES3.Load<CommandScripts_BM>("CommandScripts", EditorManager.instance.projectInformation.CommandScriptsPath,
|
||||
ProjectManager.SaveSettings).ExecuteBM();
|
||||
}
|
||||
|
||||
public void LoadExport(string projectName)
|
||||
{
|
||||
|
||||
LoadProjectInfoExport(projectName);
|
||||
LoadSongInfoExport(projectName);
|
||||
LoadCommandScriptsExport(projectName);
|
||||
LoadBeatMapExport(projectName);
|
||||
LogWindow.Log("Load Export Complete,", new Color(0.5f, 0f, 1f));
|
||||
LogWindow.Log("Please Save Your Project As You Can", new Color(0.5f, 0f, 1f));
|
||||
|
||||
}
|
||||
private void LoadProjectInfoExport(string projectName)
|
||||
{
|
||||
string projectInfoPath = Application.streamingAssetsPath + "/Export/" + projectName + "/ProjectInfo.bytes";
|
||||
ES3.Load<ProjectInformation_BM>("ProjectInformation", projectInfoPath, ProjectManager.ExportSettings).ExecuteBM();
|
||||
}
|
||||
|
||||
private void LoadSongInfoExport(string projectName)
|
||||
{
|
||||
string songInfoPath = Application.streamingAssetsPath + "/Export/" + projectName + "/SongInfo.bytes";
|
||||
ES3.Load<SongInformation_BM>("SongInformation", songInfoPath, ProjectManager.ExportSettings).ExecuteBM();
|
||||
}
|
||||
|
||||
private void LoadBeatMapExport(string projectName)
|
||||
{
|
||||
string beatMapPath = Application.streamingAssetsPath + "/Export/" + projectName + "/Beatmap.bytes";
|
||||
ES3.Load<BeatmapContainer_BM>("Beatmap", beatMapPath, ProjectManager.ExportSettings).ExecuteBM();
|
||||
}
|
||||
|
||||
private void LoadCommandScriptsExport(string projectName)
|
||||
{
|
||||
string commandScriptsPath = Application.streamingAssetsPath + "/Export/" + projectName + "/CommandScripts.bytes";
|
||||
ES3.Load<CommandScripts_BM>("CommandScripts", commandScriptsPath, ProjectManager.ExportSettings).ExecuteBM();
|
||||
}
|
||||
}
|
||||
|
||||
public class BeatmapClipManager
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace Ichni
|
||||
|
||||
public bool isLoadedProject;
|
||||
public string loadedProjectName;
|
||||
|
||||
public bool isRecovery = false;
|
||||
public ProjectInformation_BM projectInfo_BM;
|
||||
public SongInformation_BM songInfo_BM;
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Ichni.StartMenu
|
||||
public TMP_Text projectNameText, lastSavedTimeText, songNameText;
|
||||
public Button loadButton;
|
||||
public Image MemuMask;
|
||||
public bool isRecovery = false;
|
||||
public void SetUpTab(string projectName, string lastSavedTime, string songName)
|
||||
{
|
||||
this.projectName = projectName;
|
||||
@@ -31,6 +32,7 @@ namespace Ichni.StartMenu
|
||||
MemuMask.gameObject.SetActive(true);
|
||||
InformationTransistor.instance.isLoadedProject = true;
|
||||
InformationTransistor.instance.loadedProjectName = projectName;
|
||||
InformationTransistor.instance.isRecovery = isRecovery;
|
||||
|
||||
string projectPath = Application.streamingAssetsPath + "/Projects/" + projectName;
|
||||
InformationTransistor.instance.projectInfo_BM = ES3.Load<ProjectInformation_BM>("ProjectInformation", projectPath + "/ProjectInfo.json");
|
||||
|
||||
Reference in New Issue
Block a user