using System.Collections; using UnityEngine; using Ichni.RhythmGame; using UnityEngine.InputSystem; using DG.Tweening; using UniRx; using UniRx.Triggers; 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)); targetGameElement.OnDestroyAsObservable() .Subscribe(_ => { if (gameObject != null) Destroy(gameObject); instance = null; }).AddTo(this); } void Update() { if (isMoving) return; transform.eulerAngles = targetGameElement.parentElement?.transform.eulerAngles ?? Vector3.zero; 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; targetGameElement.transform.position = newPosition; targetGameElement.transform.localPosition = new Vector3( Mathf.Round(targetGameElement.transform.localPosition.x * 100f) / 100f, Mathf.Round(targetGameElement.transform.localPosition.y * 100f) / 100f, Mathf.Round(targetGameElement.transform.localPosition.z * 100f) / 100f ); transform.position = newPosition; } 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; } } }