feat: 角色展示v1.2
This commit is contained in:
@@ -3,10 +3,12 @@ using UnityEngine;
|
||||
|
||||
namespace CharacterPreview
|
||||
{
|
||||
public class ModelMove:MonoBehaviour
|
||||
public class ModelMove : MonoBehaviour
|
||||
{
|
||||
// 摄像机属性
|
||||
private Camera _camera;
|
||||
public Camera currentCamera
|
||||
|
||||
public Camera CurrentCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -18,36 +20,280 @@ namespace CharacterPreview
|
||||
_camera = FindObjectOfType<Camera>();
|
||||
}
|
||||
}
|
||||
|
||||
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 (currentCamera)
|
||||
if (ModBehaviour.config.data.use)
|
||||
{
|
||||
var worldPos = CameraLocalToWorld(currentCamera, new Vector3(1, -1, 1));
|
||||
transform.position = worldPos;
|
||||
ApplyConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = new Vector3(8, 8, -16);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将摄像机局部坐标系中的点转换为世界坐标系中的点。
|
||||
/// 假设摄像机局部坐标系:前向为 +Z,右为 +X,上为 +Y。
|
||||
/// 确保ControlModelMove GameObject存在并绑定脚本。
|
||||
/// </summary>
|
||||
/// <param name="camera">目标摄像机</param>
|
||||
/// <param name="localPoint">在摄像机局部坐标系中的点</param>
|
||||
/// <returns>对应的世界坐标</returns>
|
||||
private void EnsureControlModelMoveGameObject()
|
||||
{
|
||||
if (_controlModelMoveGameObject == null)
|
||||
{
|
||||
// 尝试查找场景中已有的ControlModelMove
|
||||
_controlModelMoveGameObject = GameObject.Find("ControlModelMove");
|
||||
if (_controlModelMoveGameObject == null)
|
||||
{
|
||||
// 如果没有,则创建新的
|
||||
_controlModelMoveGameObject = new GameObject("ControlModelMove");
|
||||
}
|
||||
|
||||
// 确保ControlModelMove组件已添加
|
||||
if (_controlModelMoveGameObject.GetComponent<ControlModelMove>() == null)
|
||||
{
|
||||
_controlModelMoveGameObject.AddComponent<ControlModelMove>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将模型朝向当前摄像机。
|
||||
/// </summary>
|
||||
public void LookAtCamera()
|
||||
{
|
||||
if(!CanFix)
|
||||
return;
|
||||
if (CurrentCamera)
|
||||
{
|
||||
transform.LookAt(CurrentCamera.transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("ModelMove.LookAtCamera: 找不到摄像机,无法使模型朝向摄像机。");
|
||||
}
|
||||
SaveDataToConfig();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置模型的位置、旋转和缩放
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移动模型
|
||||
/// </summary>
|
||||
/// <param name="shift">相对于当前总偏移量的位移增量(在摄像机局部坐标系下)</param>
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 等比例缩放模型
|
||||
/// </summary>
|
||||
/// <param name="increment">缩放增量,通常来自鼠标滚轮或UI滑块</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 旋转模型
|
||||
/// </summary>
|
||||
/// <param name="rotationAmount">旋转量,通常来自鼠标拖拽的偏移量(delta)</param>
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 沿摄像机的Z轴(朝向)旋转模型,实现“滚动”或“倾斜”效果。
|
||||
/// </summary>
|
||||
/// <param name="angle">要旋转的角度。正值通常为顺时针,负值为逆时针。</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将摄像机局部空间中的点转换为世界空间中的点。
|
||||
/// </summary>
|
||||
/// <param name="camera">参考摄像机。</param>
|
||||
/// <param name="localPoint">摄像机局部空间中的点。</param>
|
||||
/// <returns>世界空间中的点。</returns>
|
||||
public static Vector3 CameraLocalToWorld(Camera camera, Vector3 localPoint)
|
||||
{
|
||||
if (camera == null)
|
||||
throw new System.ArgumentNullException(nameof(camera));
|
||||
throw new ArgumentNullException(nameof(camera),
|
||||
"Camera cannot be null for CameraLocalToWorld conversion.");
|
||||
|
||||
Transform camTransform = camera.transform;
|
||||
// 旋转局部点到世界方向,然后加上摄像机位置
|
||||
var camTransform = camera.transform;
|
||||
return camTransform.position + camTransform.rotation * localPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user