using System; using UnityEngine; namespace CharacterPreview { public class ModelMove : MonoBehaviour { // 摄像机属性 private Camera _camera; public Camera CurrentCamera { get { if (!_camera) { _camera = Camera.main; if (!_camera) { _camera = FindObjectOfType(); } } return _camera; } } public Vector2 horizontalMoveRange = new Vector2(-1f, 2f); // X轴范围 public Vector2 verticalMoveRange = new Vector2(-2f, 2f); // Y轴范围 public Vector2 depthMoveRange = new Vector2(-1, 10f); // Z轴范围 (深度) public Vector2 scaleRange = new Vector2(0.5f, 3f); // 缩放范围 (x=min, y=max) // 初始状态变量 private Vector3 _initialScale = Vector3.one; private Quaternion _initialRotation = Quaternion.identity; // 模型相对于摄像机的初始局部位置偏移量 private Vector3 _initialCameraLocalOffset; // 用于Input输入的控制器对象 private GameObject _controlModelMoveGameObject; public bool CanFix => ModBehaviour.config.data.canEdit; // 模型在摄像机局部空间中的默认位置偏移量 (用于Reset) public static readonly Vector3 DefaultCameraLocalOffset = new Vector3(0.38f, -0.92f, 2.00f); private void Awake() { EnsureControlModelMoveGameObject(); } private void Start() { if (ModBehaviour.config.data.use) { ApplyConfig(); } else { RefreshPosition(); } } private void Update() { // // 调试功能,按下 "-" 打印模型相对于摄像机的局部位置 // if (Input.GetKeyDown(KeyCode.Minus)) // { // if (CurrentCamera) // { // var localPositionRelativeToCamera = // CurrentCamera.transform.InverseTransformPoint(transform.position); // Debug.Log($"模型相对于摄像机的局部位置: {localPositionRelativeToCamera}"); // } // else // { // Debug.LogWarning("找不到摄像机,无法计算局部位置。模型的全局位置为: " + transform.position); // } // } } private void OnDestroy() { // 销毁时清理生成的控制器GameObject if (_controlModelMoveGameObject) { Destroy(_controlModelMoveGameObject); _controlModelMoveGameObject = null; } } /// /// 确保ControlModelMove GameObject存在并绑定脚本。 /// private void EnsureControlModelMoveGameObject() { if (_controlModelMoveGameObject == null) { // 尝试查找场景中已有的ControlModelMove _controlModelMoveGameObject = GameObject.Find("ControlModelMove"); if (_controlModelMoveGameObject == null) { // 如果没有,则创建新的 _controlModelMoveGameObject = new GameObject("ControlModelMove"); } // 确保ControlModelMove组件已添加 if (_controlModelMoveGameObject.GetComponent() == null) { _controlModelMoveGameObject.AddComponent(); } } } /// /// 将模型朝向当前摄像机。 /// public void LookAtCamera() { if(!CanFix) return; if (CurrentCamera) { transform.LookAt(CurrentCamera.transform); } else { Debug.LogWarning("ModelMove.LookAtCamera: 找不到摄像机,无法使模型朝向摄像机。"); } SaveDataToConfig(); } /// /// 重置模型的位置、旋转和缩放 /// public void RefreshPosition() { if(!CanFix) return; // 重置缩放和旋转到初始状态 transform.localScale = _initialScale; transform.rotation = _initialRotation; if (CurrentCamera) { // 计算模型在世界空间中相对于摄像机的默认位置 var worldPos = CameraLocalToWorld(CurrentCamera, DefaultCameraLocalOffset); transform.position = worldPos; // 使模型朝向摄像机 LookAtCamera(); // 记录模型重置后的相对于摄像机的局部偏移量,作为后续移动的基准 _initialCameraLocalOffset = CurrentCamera.transform.InverseTransformPoint(transform.position); } else { Debug.LogWarning("ModelMove.RefreshPosition: 找不到摄像机。模型将保持其当前世界位置,且相机相对移动功能将无法正常工作。"); _initialCameraLocalOffset = transform.position; transform.position = new Vector3(8, 8, -16); } SaveDataToConfig(); } /// /// 移动模型 /// /// 相对于当前总偏移量的位移增量(在摄像机局部坐标系下) public void Move(Vector3 shift) { if(!CanFix) return; if (!CurrentCamera) { Debug.LogWarning("ModelMove.Move: 找不到摄像机,无法执行相机相对移动。"); return; } var currentLocalPos = CurrentCamera.transform.InverseTransformPoint(transform.position); var currentOffsetFromInitial = currentLocalPos - _initialCameraLocalOffset; var targetOffsetFromInitial = currentOffsetFromInitial + shift; targetOffsetFromInitial.x = Mathf.Clamp(targetOffsetFromInitial.x, horizontalMoveRange.x, horizontalMoveRange.y); targetOffsetFromInitial.y = Mathf.Clamp(targetOffsetFromInitial.y, verticalMoveRange.x, verticalMoveRange.y); targetOffsetFromInitial.z = Mathf.Clamp(targetOffsetFromInitial.z, depthMoveRange.x, depthMoveRange.y); var newLocalPos = _initialCameraLocalOffset + targetOffsetFromInitial; transform.position = CurrentCamera.transform.TransformPoint(newLocalPos); SaveDataToConfig(); } /// /// 等比例缩放模型 /// /// 缩放增量,通常来自鼠标滚轮或UI滑块 public void Scale(float increment) { if(!CanFix) return; // 假设是等比例缩放,所以只取x轴的值来计算 var currentScale = transform.localScale.x; var newScale = currentScale + increment; // 将新的缩放值限制在预设范围内 newScale = Mathf.Clamp(newScale, scaleRange.x, scaleRange.y); // 应用新的等比例缩放值 SaveDataToConfig(); transform.localScale = new Vector3(newScale, newScale, newScale); } /// /// 旋转模型 /// /// 旋转量,通常来自鼠标拖拽的偏移量(delta) public void Rotate(Vector2 rotationAmount) { if(!CanFix) return; // 左右拖拽(rotationAmount.x)时,围绕世界坐标的Y轴旋转,使模型保持直立 transform.Rotate(Vector3.up, -rotationAmount.x * Time.deltaTime, Space.World); if (CurrentCamera) { // 上下拖拽(rotationAmount.y)时,围绕摄像机的右方向轴旋转,感觉更自然 transform.Rotate(CurrentCamera.transform.right, rotationAmount.y * Time.deltaTime, Space.World); } else { // 如果找不到相机,则退而求其次,围绕世界坐标的X轴旋转 Debug.LogWarning("ModelMove.Rotate: 找不到摄像机,上下旋转将使用世界X轴。"); transform.Rotate(Vector3.right, rotationAmount.y * Time.deltaTime, Space.World); } SaveDataToConfig(); } /// /// 沿摄像机的Z轴(朝向)旋转模型,实现“滚动”或“倾斜”效果。 /// /// 要旋转的角度。正值通常为顺时针,负值为逆时针。 public void RotateAroundCameraZ(float angle) { if(!CanFix) return; if (CurrentCamera == null) { Debug.LogWarning("ModelMove.RotateAroundCameraZ: 无法执行围绕相机Z轴的旋转,因为找不到相机。"); return; } var rotationAxis = CurrentCamera.transform.forward; transform.Rotate(rotationAxis, angle, Space.World); SaveDataToConfig(); } public void SaveDataToConfig() { var configData = ModBehaviour.config.data; configData.modelPosition = CurrentCamera.transform.InverseTransformPoint(transform.position); configData.modelRotation = transform.eulerAngles; configData.modelScale = CurrentCamera.transform.localScale.x; } public void ApplyConfig() { var configData = ModBehaviour.config.data; transform.position = CameraLocalToWorld(CurrentCamera, configData.modelPosition); transform.eulerAngles = configData.modelRotation; transform.localScale = new Vector3(configData.modelScale, configData.modelScale, configData.modelScale); } /// /// 将摄像机局部空间中的点转换为世界空间中的点。 /// /// 参考摄像机。 /// 摄像机局部空间中的点。 /// 世界空间中的点。 public static Vector3 CameraLocalToWorld(Camera camera, Vector3 localPoint) { if (camera == null) throw new ArgumentNullException(nameof(camera), "Camera cannot be null for CameraLocalToWorld conversion."); var camTransform = camera.transform; return camTransform.position + camTransform.rotation * localPoint; } } }