Files
test/Assets/PerfectWorld/Prefab/Task/TaskTrace/StyledTaskTraceText.cs

150 lines
5.3 KiB
C#

using UnityEngine;
using TMPro;
using UnityEngine.EventSystems;
using BrewMonster.Scripts.Task.UI;
using System.Collections.Generic;
using BrewMonster.UI;
using System.Text;
using System.Text.RegularExpressions;
namespace BrewMonster
{
public class StyledTaskTraceText : MonoBehaviour, IPointerClickHandler
{
public TMP_Text tmp;
private List<LinkCommand> linkCommands =new List<LinkCommand>();
private void Start()
{
tmp.raycastTarget = true;
tmp.ForceMeshUpdate();
}
// Helper method to find intersecting link with proper camera handling // 辅助方法,用于查找相交的链接并正确处理相机
private int FindIntersectingLink(PointerEventData eventData)
{
if (tmp == null) return -1;
tmp.ForceMeshUpdate();
// Get camera for link detection // 获取用于链接检测的相机
Camera camera = null;
Canvas canvas = tmp.GetComponentInParent<Canvas>();
if (canvas != null)
{
// IMPORTANT: TMP_TextUtilities.FindIntersectingLink expects camera=null for ScreenSpaceOverlay.
// 重要:ScreenSpaceOverlay 必须传 camera=null,否则会算错导致 linkIndex = -1。
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
camera = null;
}
else
{
// ScreenSpaceCamera / WorldSpace
camera = eventData.pressEventCamera != null ? eventData.pressEventCamera : canvas.worldCamera;
}
}
else
{
// No canvas found; fall back to pressEventCamera (may be null) then main
camera = eventData.pressEventCamera != null ? eventData.pressEventCamera : Camera.main;
}
// Try with camera first, then fallback to null // 先尝试使用相机,然后回退到null
int linkIndexCam = TMP_TextUtilities.FindIntersectingLink(tmp, eventData.position, camera);
int linkIndexNull = TMP_TextUtilities.FindIntersectingLink(tmp, eventData.position, null);
return linkIndexCam != -1 ? linkIndexCam : linkIndexNull;
}
public void Set(string text)
{
tmp.text = FormatForTextMeshPro(text);
}
public static string FormatForTextMeshPro(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder result = new StringBuilder(text);
result.Replace("\\r", "\n");
return ProcessColorCodes(result);
}
public static string ProcessColorCodes(StringBuilder text)
{
string pattern = @"\^([0-9A-Fa-f]{6})";
return Regex.Replace(text.ToString(), pattern, match =>
{
string hexColor = match.Groups[1].Value;
return $"<color=#{hexColor}>";
}, RegexOptions.None);
}
public void AddToFirstPosition(LinkCommand linkCommand)
{
linkCommands.Insert(0, linkCommand);
}
public void AddToLastPosition(LinkCommand linkCommand)
{
linkCommands.Add(linkCommand);
}
public void AddLinkCommand(LinkCommand linkCommand)
{
linkCommands.Add(linkCommand);
}
public void RemoveLinkCommand(int linkIndex)
{
linkCommands.RemoveAt(linkIndex);
}
public void RefreshLinkCommands()
{
tmp.text = "";
linkCommands.Clear();
}
public void OnPointerClick(PointerEventData eventData)
{
if (tmp == null) return;
// Detect link directly in click handler // 在点击处理程序中直接检测链接
int linkIndex = FindIntersectingLink(eventData);
// Validate link index // 验证链接索引
if (linkIndex == -1 || linkIndex >= tmp.textInfo.linkCount || linkIndex >= linkCommands.Count)
{
return;
}
tmp.ForceMeshUpdate();
TMP_LinkInfo linkInfo = tmp.textInfo.linkInfo[linkIndex];
string linkText = linkInfo.GetLinkText();
string entityID = linkInfo.GetLinkID();
switch (entityID)
{
case "coord":
if (linkIndex < linkCommands.Count && linkCommands[linkIndex] != null)
{
linkCommands[linkIndex].Execute(tmp);
}
//Debug.Log($"[StyledTaskTraceText] OnPointerClick: linkCommands[{linkIndex}].Execute(tmp) => {linkCommands[linkIndex].Execute(tmp)}");
break;
case "npc":
if (linkIndex < linkCommands.Count && linkCommands[linkIndex] != null)
{
linkCommands[linkIndex].Execute(tmp);
}
break;
case "monster":
break;
default:
Debug.Log($"Clicked unknown link: ID={entityID} Text={linkText}");
break;
}
}
}
}