Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/UI/Button3D.cs
2025-08-27 20:44:29 +08:00

142 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq; // 用于可能的LINQ操作但在此版本中可能不直接使用
using TMPro; // 用于 TextMeshPro 组件
using UnityEngine;
using UnityEngine.Events; // 用于 UnityEvent
namespace UI
{
public class Button3D : MonoBehaviour
{
[Tooltip("当按钮被点击时触发的UnityEvent。可以在Inspector中配置.")]
public UnityEvent OnClick;
public MeshRenderer renderer; // 请确保在Inspector中拖拽赋值
public Material outlineMaterial; // 请确保在Inspector中拖拽赋值
public TMP_Text text; // 文本组件
private Material[] _originalMaterials; // 用于存储按钮的原始材质,以便正确添加和移除描边
private void Awake()
{
if (renderer == null)
{
Debug.LogError("Button3D: MeshRenderer is not assigned. Please assign it in the Inspector.", this);
return;
}
if (outlineMaterial == null)
{
Debug.LogWarning(
"Button3D: Outline Material is not assigned. Outline effect will not work. Please assign it in the Inspector.",
this);
}
if (text == null)
{
Debug.LogWarning("Button3D: TMP_Text is not assigned. Text features will not work. Please assign it in the Inspector.", this);
// 这里不return允许按钮无文本运行
}
// 存储原始材质数组,以便在添加和移除描边时正确操作
// .ToArray() 是为了确保我们拿到的是拷贝,而不是引用,防止外部意外修改
_originalMaterials = renderer.materials.ToArray();
// 确保初始化时没有边框材质
// Important: 调用RemoveOutlineMaterialInternal()可能会清除_originalMaterials所以要确保先保存
RemoveOutlineMaterialInternal(); // 这一步会根据_originalMaterials重新设置renderer.materials
// 初始时隐藏文本
if (text != null)
{
text.gameObject.SetActive(false);
}
}
private void Update()
{
// 文本始终朝向摄像机
if (text != null && text.IsActive() && Camera.main != null)
{
text.transform.LookAt(text.transform.position + Camera.main.transform.rotation * Vector3.forward,
Camera.main.transform.rotation * Vector3.up);
}
}
private void OnMouseEnter()
{
if (renderer == null) return;
// 鼠标进入时显示文本
if (text != null)
{
text.gameObject.SetActive(true);
}
// 如果没有描边材质,或者渲染器已经有描边材质,就没必要再添加了
// 检查当前材质数组长度是否已经大于等于_originalMaterials的长度+1
// 这样可以避免重复添加
if (outlineMaterial == null || renderer.materials.Length > _originalMaterials.Length)
{
return;
}
// 如果当前材质数组和_originalMaterials不一致说明可能被其他逻辑修改了
// 稳妥起见最好先恢复到_originalMaterials
if (!renderer.materials.SequenceEqual(_originalMaterials))
{
//Debug.LogWarning("Button3D: Renderer materials were unexpectedly modified before OnMouseEnter. Restoring original materials.");
// 通常不应该发生,除非有其他脚本在修改
renderer.materials = _originalMaterials;
}
// 创建一个新数组,包含原始材质和描边材质
Material[] newMaterials = new Material[_originalMaterials.Length + 1];
System.Array.Copy(_originalMaterials, newMaterials, _originalMaterials.Length);
newMaterials[_originalMaterials.Length] = outlineMaterial;
renderer.materials = newMaterials;
}
private void OnMouseExit()
{
if (renderer == null) return;
// 鼠标离开时隐藏文本
if (text != null)
{
text.gameObject.SetActive(false);
}
// 调用内部方法移除边框材质
RemoveOutlineMaterialInternal();
}
private void OnMouseDown()
{
// 触发UnityEvent
OnClick.Invoke();
}
/// <summary>
/// 移除渲染器上的边框材质(如果存在),恢复到按钮的原始材质。
/// </summary>
private void RemoveOutlineMaterialInternal()
{
if (renderer == null) return;
// 即使_originalMaterials == null因为Awake中的LogError也可以安全赋值空数组
// 但如果_originalMaterials确实是null说明Awake有问题后续操作也可能继续出错
if (_originalMaterials == null)
{
Debug.LogError("Button3D: _originalMaterials is null. Cannot remove outline. Check Awake method.", this);
return;
}
// 直接将渲染器材质恢复为_originalMaterials的副本
renderer.materials = _originalMaterials.ToArray(); // 使用ToArray()确保赋值一个副本避免_originalMaterials被意外修改
}
}
}