202 lines
7.8 KiB
C#
202 lines
7.8 KiB
C#
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;
|
|
transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack);
|
|
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;
|
|
transform.localScale = //相机距离的函数,保持在一定大小范围内
|
|
Vector3.one * Mathf.Clamp(Vector3.Distance(editorCamera.transform.position, transform.position) * 0.05f, 0.1f, 1000f);
|
|
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("Selectable")))
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
}
|
|
} |