341 lines
15 KiB
C#
341 lines
15 KiB
C#
|
|
using System;
|
|||
|
|
using TMPro;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.EventSystems;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
|
|||
|
|
namespace SceneView
|
|||
|
|
{
|
|||
|
|
public class ParametersPanel : MonoBehaviour, IDragHandler, IBeginDragHandler
|
|||
|
|
{
|
|||
|
|
public RectTransform rectTransform;
|
|||
|
|
public const float wide = 400;
|
|||
|
|
|
|||
|
|
public (TMP_InputField x, TMP_InputField y, TMP_InputField z)
|
|||
|
|
position, localPosition, localScale; // 删除了 'scale',因为它在 Awake 中被注释掉了
|
|||
|
|
|
|||
|
|
public (TMP_InputField x, TMP_InputField y, TMP_InputField z, TMP_InputField w)
|
|||
|
|
rotation, localRotation;
|
|||
|
|
|
|||
|
|
private Vector2 shift;
|
|||
|
|
private int timer = 0;
|
|||
|
|
private int refreshTime = 10; // 每10帧刷新一次
|
|||
|
|
|
|||
|
|
// 新增:标志位,表示是否有输入框正在被编辑
|
|||
|
|
private bool isEditingInputField = false;
|
|||
|
|
|
|||
|
|
private void Awake()
|
|||
|
|
{
|
|||
|
|
if (!rectTransform) rectTransform = GetComponent<RectTransform>();
|
|||
|
|
if (!rectTransform) rectTransform = gameObject.AddComponent<RectTransform>();
|
|||
|
|
rectTransform.sizeDelta = new Vector2(wide, 500);
|
|||
|
|
rectTransform.anchoredPosition = new Vector2(wide / 2 + 10, 0);
|
|||
|
|
CanvasControl.OnChangeFocusObject += OnChangeFocusObject;
|
|||
|
|
|
|||
|
|
var title = RectTransformConfig.Default;
|
|||
|
|
title.AnchorMin = Vector2.up;
|
|||
|
|
title.AnchorMax = Vector2.one;
|
|||
|
|
title.Pivot = new Vector2(0.5f, 0);
|
|||
|
|
title.SizeDelta = new Vector2(0, 50);
|
|||
|
|
title.AnchoredPosition = new Vector2(0, 0);
|
|||
|
|
var titleObj = ControlUtilities.CreateRect(transform, "标题", title);
|
|||
|
|
titleObj.gameObject.AddComponent<Image>().color = new Color(0.3f, 0.3f, 0.3f, 0.8f);
|
|||
|
|
var titleText = TextConfig.Default;
|
|||
|
|
titleText.RectConfig = RectTransformConfig.FillParent;
|
|||
|
|
titleText.Text = "焦点参数";
|
|||
|
|
ControlUtilities.CreateText(titleObj, titleText);
|
|||
|
|
|
|||
|
|
var contentConfig = RectTransformConfig.FillParent;
|
|||
|
|
var content = ControlUtilities.CreateRect(transform, "内容", contentConfig);
|
|||
|
|
|
|||
|
|
var vLayout = content.gameObject.AddComponent<VerticalLayoutGroup>();
|
|||
|
|
vLayout.padding = new RectOffset(2, 2, 2, 2);
|
|||
|
|
vLayout.childAlignment = TextAnchor.UpperCenter;
|
|||
|
|
vLayout.childControlWidth = true;
|
|||
|
|
vLayout.childControlHeight = true;
|
|||
|
|
vLayout.spacing = 2;
|
|||
|
|
|
|||
|
|
var labelConfig = TextConfig.Default;
|
|||
|
|
|
|||
|
|
// 全局位置
|
|||
|
|
labelConfig.Text = "全局位置";
|
|||
|
|
ControlUtilities.CreateText(content, labelConfig);
|
|||
|
|
position = CreateVector3InputField(content, ApplyWorldPositionChange);
|
|||
|
|
|
|||
|
|
// 全局旋转 (使用Quaternion)
|
|||
|
|
labelConfig.Text = "全局旋转";
|
|||
|
|
ControlUtilities.CreateText(content, labelConfig);
|
|||
|
|
rotation = CreateVector4InputField(content, ApplyWorldRotationChange);
|
|||
|
|
|
|||
|
|
// 局部位置
|
|||
|
|
labelConfig.Text = "局部位置";
|
|||
|
|
ControlUtilities.CreateText(content, labelConfig);
|
|||
|
|
localPosition = CreateVector3InputField(content, ApplyLocalPositionChange);
|
|||
|
|
|
|||
|
|
// 局部缩放
|
|||
|
|
labelConfig.Text = "局部缩放";
|
|||
|
|
ControlUtilities.CreateText(content, labelConfig);
|
|||
|
|
localScale = CreateVector3InputField(content, ApplyLocalScaleChange);
|
|||
|
|
|
|||
|
|
// 局部旋转 (使用Quaternion)
|
|||
|
|
labelConfig.Text = "局部旋转";
|
|||
|
|
ControlUtilities.CreateText(content, labelConfig);
|
|||
|
|
localRotation = CreateVector4InputField(content, ApplyLocalRotationChange);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnDestroy()
|
|||
|
|
{
|
|||
|
|
CanvasControl.OnChangeFocusObject -= OnChangeFocusObject;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Update()
|
|||
|
|
{
|
|||
|
|
timer++;
|
|||
|
|
// 只有当没有输入框被编辑时才刷新
|
|||
|
|
if (timer >= refreshTime && !isEditingInputField)
|
|||
|
|
{
|
|||
|
|
timer = 0;
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnChangeFocusObject(GameObject obj)
|
|||
|
|
{
|
|||
|
|
// 焦点对象改变时,立即刷新
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Refresh()
|
|||
|
|
{
|
|||
|
|
if (!CanvasControl.FocusGameObject)
|
|||
|
|
{
|
|||
|
|
ClearAllInputFields();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
|
|||
|
|
// --- 全局位置 (World Position) ---
|
|||
|
|
var currentPosition = targetTransform.position;
|
|||
|
|
position.x.text = currentPosition.x.ToString("F3"); // "F3" 表示保留3位小数
|
|||
|
|
position.y.text = currentPosition.y.ToString("F3");
|
|||
|
|
position.z.text = currentPosition.z.ToString("F3");
|
|||
|
|
|
|||
|
|
// --- 局部位置 (Local Position) ---
|
|||
|
|
var currentLocalPosition = targetTransform.localPosition;
|
|||
|
|
localPosition.x.text = currentLocalPosition.x.ToString("F3");
|
|||
|
|
localPosition.y.text = currentLocalPosition.y.ToString("F3");
|
|||
|
|
localPosition.z.text = currentLocalPosition.z.ToString("F3");
|
|||
|
|
|
|||
|
|
// --- 局部缩放 (Local Scale) ---
|
|||
|
|
var currentLocalScale = targetTransform.localScale;
|
|||
|
|
localScale.x.text = currentLocalScale.x.ToString("F3");
|
|||
|
|
localScale.y.text = currentLocalScale.y.ToString("F3");
|
|||
|
|
localScale.z.text = currentLocalScale.z.ToString("F3");
|
|||
|
|
|
|||
|
|
// --- 全局旋转 (World Rotation) - Quaternion ---
|
|||
|
|
var currentRotation = targetTransform.rotation;
|
|||
|
|
rotation.x.text = currentRotation.x.ToString("F3");
|
|||
|
|
rotation.y.text = currentRotation.y.ToString("F3");
|
|||
|
|
rotation.z.text = currentRotation.z.ToString("F3");
|
|||
|
|
rotation.w.text = currentRotation.w.ToString("F3");
|
|||
|
|
|
|||
|
|
// --- 局部旋转 (Local Rotation) - Quaternion ---
|
|||
|
|
var currentLocalRotation = targetTransform.localRotation;
|
|||
|
|
localRotation.x.text = currentLocalRotation.x.ToString("F3");
|
|||
|
|
localRotation.y.text = currentLocalRotation.y.ToString("F3");
|
|||
|
|
localRotation.z.text = currentLocalRotation.z.ToString("F3");
|
|||
|
|
localRotation.w.text = currentLocalRotation.w.ToString("F3");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ClearAllInputFields()
|
|||
|
|
{
|
|||
|
|
position.x.text = ""; position.y.text = ""; position.z.text = "";
|
|||
|
|
localPosition.x.text = ""; localPosition.y.text = ""; localPosition.z.text = "";
|
|||
|
|
localScale.x.text = ""; localScale.y.text = ""; localScale.z.text = "";
|
|||
|
|
rotation.x.text = ""; rotation.y.text = ""; rotation.z.text = ""; rotation.w.text = "";
|
|||
|
|
localRotation.x.text = ""; localRotation.y.text = ""; localRotation.z.text = ""; localRotation.w.text = "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Helper method to add common input field event listeners
|
|||
|
|
private void AddInputFieldListeners(TMP_InputField inputField)
|
|||
|
|
{
|
|||
|
|
inputField.onSelect.AddListener((_) => isEditingInputField = true);
|
|||
|
|
inputField.onDeselect.AddListener((_) =>
|
|||
|
|
{
|
|||
|
|
isEditingInputField = false;
|
|||
|
|
// 在失去焦点后立即刷新,以更新可能的非用户输入引起的改变或重新格式化用户输入
|
|||
|
|
Refresh();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// 修改 CreateVector3InputField,接受一个Action用于处理onEndEdit
|
|||
|
|
public (TMP_InputField x, TMP_InputField y, TMP_InputField z) CreateVector3InputField(Transform parent, Action<string, int> onEndEditCallback)
|
|||
|
|
{
|
|||
|
|
var rectConfig = RectTransformConfig.Default;
|
|||
|
|
var pack = ControlUtilities.CreateRect(parent, "向量组", rectConfig);
|
|||
|
|
var hLayout = pack.gameObject.AddComponent<HorizontalLayoutGroup>();
|
|||
|
|
hLayout.childForceExpandHeight = true;
|
|||
|
|
hLayout.childForceExpandWidth = true;
|
|||
|
|
hLayout.childControlWidth = true;
|
|||
|
|
hLayout.childControlHeight = true;
|
|||
|
|
hLayout.spacing = 2;
|
|||
|
|
hLayout.padding = new RectOffset(2, 2, 2, 2);
|
|||
|
|
|
|||
|
|
var inputConfig = LabeledInputFieldConfig.Default;
|
|||
|
|
inputConfig.InputFieldConfig.BackgroundColor = new Color(0.7f, 0.7f, 0.7f, 0.7f);
|
|||
|
|
inputConfig.LabelWidth = 15;
|
|||
|
|
inputConfig.LabelFontSize = 14;
|
|||
|
|
inputConfig.Spacing = 0;
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "X";
|
|||
|
|
var inputX = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputX.inputField);
|
|||
|
|
inputX.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 0));
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "Y";
|
|||
|
|
var inputY = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputY.inputField);
|
|||
|
|
inputY.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 1));
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "Z";
|
|||
|
|
var inputZ = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputZ.inputField);
|
|||
|
|
inputZ.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 2));
|
|||
|
|
|
|||
|
|
return (inputX.inputField, inputY.inputField, inputZ.inputField);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改 CreateVector4InputField,接受一个Action用于处理onEndEdit
|
|||
|
|
public (TMP_InputField x, TMP_InputField y, TMP_InputField z, TMP_InputField w) CreateVector4InputField(
|
|||
|
|
Transform parent, Action<string, int> onEndEditCallback)
|
|||
|
|
{
|
|||
|
|
var rectConfig = RectTransformConfig.Default;
|
|||
|
|
var pack = ControlUtilities.CreateRect(parent, "向量组", rectConfig);
|
|||
|
|
var hLayout = pack.gameObject.AddComponent<HorizontalLayoutGroup>();
|
|||
|
|
hLayout.childForceExpandHeight = true;
|
|||
|
|
hLayout.childForceExpandWidth = true;
|
|||
|
|
hLayout.childControlWidth = true;
|
|||
|
|
hLayout.childControlHeight = true;
|
|||
|
|
hLayout.spacing = 2;
|
|||
|
|
hLayout.padding = new RectOffset(2, 2, 2, 2);
|
|||
|
|
|
|||
|
|
var inputConfig = LabeledInputFieldConfig.Default;
|
|||
|
|
inputConfig.InputFieldConfig.BackgroundColor = new Color(0.7f, 0.7f, 0.7f, 0.7f);
|
|||
|
|
inputConfig.LabelWidth = 15;
|
|||
|
|
inputConfig.LabelFontSize = 14;
|
|||
|
|
inputConfig.Spacing = 0;
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "X";
|
|||
|
|
var inputX = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputX.inputField);
|
|||
|
|
inputX.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 0));
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "Y";
|
|||
|
|
var inputY = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputY.inputField);
|
|||
|
|
inputY.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 1));
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "Z";
|
|||
|
|
var inputZ = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputZ.inputField);
|
|||
|
|
inputZ.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 2));
|
|||
|
|
|
|||
|
|
inputConfig.LabelText = "W";
|
|||
|
|
var inputW = ControlUtilities.CreateLabeledInputField(pack, inputConfig);
|
|||
|
|
AddInputFieldListeners(inputW.inputField);
|
|||
|
|
inputW.inputField.onEndEdit.AddListener(text => onEndEditCallback?.Invoke(text, 3));
|
|||
|
|
|
|||
|
|
return (inputX.inputField, inputY.inputField, inputZ.inputField, inputW.inputField);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyWorldPositionChange(string text, int axisIndex)
|
|||
|
|
{
|
|||
|
|
if (CanvasControl.FocusGameObject == null) return;
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
if (float.TryParse(text, out var newValue))
|
|||
|
|
{
|
|||
|
|
var pos = targetTransform.position;
|
|||
|
|
if (axisIndex == 0) pos.x = newValue;
|
|||
|
|
else if (axisIndex == 1) pos.y = newValue;
|
|||
|
|
else if (axisIndex == 2) pos.z = newValue;
|
|||
|
|
targetTransform.position = pos;
|
|||
|
|
}
|
|||
|
|
Refresh(); // 刷新以确保所有相关字段(如localPosition)都已更新
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyLocalPositionChange(string text, int axisIndex)
|
|||
|
|
{
|
|||
|
|
if (CanvasControl.FocusGameObject == null) return;
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
if (float.TryParse(text, out var newValue))
|
|||
|
|
{
|
|||
|
|
var localPos = targetTransform.localPosition;
|
|||
|
|
if (axisIndex == 0) localPos.x = newValue;
|
|||
|
|
else if (axisIndex == 1) localPos.y = newValue;
|
|||
|
|
else if (axisIndex == 2) localPos.z = newValue;
|
|||
|
|
targetTransform.localPosition = localPos;
|
|||
|
|
}
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyLocalScaleChange(string text, int axisIndex)
|
|||
|
|
{
|
|||
|
|
if (CanvasControl.FocusGameObject == null) return;
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
if (float.TryParse(text, out var newValue))
|
|||
|
|
{
|
|||
|
|
var localScale = targetTransform.localScale;
|
|||
|
|
if (axisIndex == 0) localScale.x = newValue;
|
|||
|
|
else if (axisIndex == 1) localScale.y = newValue;
|
|||
|
|
else if (axisIndex == 2) localScale.z = newValue;
|
|||
|
|
targetTransform.localScale = localScale;
|
|||
|
|
}
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyWorldRotationChange(string text, int axisIndex)
|
|||
|
|
{
|
|||
|
|
if (CanvasControl.FocusGameObject == null) return;
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
if (float.TryParse(text, out var newValue))
|
|||
|
|
{
|
|||
|
|
var rot = targetTransform.rotation;
|
|||
|
|
if (axisIndex == 0) rot.x = newValue;
|
|||
|
|
else if (axisIndex == 1) rot.y = newValue;
|
|||
|
|
else if (axisIndex == 2) rot.z = newValue;
|
|||
|
|
else if (axisIndex == 3) rot.w = newValue;
|
|||
|
|
targetTransform.rotation = rot; // Quaternion需要整体重新赋值
|
|||
|
|
}
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyLocalRotationChange(string text, int axisIndex)
|
|||
|
|
{
|
|||
|
|
if (CanvasControl.FocusGameObject == null) return;
|
|||
|
|
var targetTransform = CanvasControl.FocusGameObject.transform;
|
|||
|
|
if (float.TryParse(text, out var newValue))
|
|||
|
|
{
|
|||
|
|
var localRot = targetTransform.localRotation;
|
|||
|
|
if (axisIndex == 0) localRot.x = newValue;
|
|||
|
|
else if (axisIndex == 1) localRot.y = newValue;
|
|||
|
|
else if (axisIndex == 2) localRot.z = newValue;
|
|||
|
|
else if (axisIndex == 3) localRot.w = newValue;
|
|||
|
|
targetTransform.localRotation = localRot; // Quaternion需要整体重新赋值
|
|||
|
|
}
|
|||
|
|
Refresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
shift = transform.position - new Vector3(eventData.position.x, eventData.position.y);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void OnDrag(PointerEventData eventData)
|
|||
|
|
{
|
|||
|
|
transform.position = eventData.position + shift;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|