当前位置: 首页 > news >正文

Unity TextMeshPro 超链接实现 - 冷夜

TMP 的超链接功能本质上是‌在富文本中嵌入可点击的标记区域‌,然后通过代码检测玩家的点击位置,精准识别被点击的链接并执行对应逻辑。下面从零开始,一步步拆解。


一、超链接语法

在 TMP 文本中,超链接使用类似 HTML 的标签语法:

text
 
<link="自定义ID">显示文本</link>

比如在 RPG 聊天频道里标记一件装备:

text
 
获得稀有装备:<link="item_1234">龙息之剑</link>!

为了增强视觉提示,通常会配合下划线或颜色标签一起使用:

text
 
<u><link="item_1234">龙息之剑</link></u> <color=#FFA500><link="weapon_123">传说之剑</link></color>

‌注意事项:‌

  • 链接 ID 可以是任意字符串,建议用有意义的命名规则(如 item_编号player_名字
  • 标签必须正确闭合,否则会破坏整个文本块的渲染
  • 文本组件的 Rich Text 选项必须勾选

二、点击检测的两种实现方式

方式一:Update 轮询检测(适合简单场景)

在 Update 中检测鼠标点击,然后调用 TMP_TextUtilities.FindIntersectingLink 判断是否点中了链接:

csharp
 
using TMPro; using UnityEngine; public class LinkHandler : MonoBehaviour { public TMP_Text textComponent; private Camera mainCamera; void Start() { mainCamera = Camera.main; textComponent.raycastTarget = true; // 必须启用射线检测 } void Update() { if (Input.GetMouseButtonDown(0)) { // 关键:查找与鼠标位置相交的链接 int linkIndex = TMP_TextUtilities.FindIntersectingLink( textComponent, Input.mousePosition, mainCamera // 注意相机参数,见下文详解 ); if (linkIndex != -1) { TMP_LinkInfo linkInfo = textComponent.textInfo.linkInfo[linkIndex]; string linkId = linkInfo.GetLinkID(); // 拿到 "item_1234" string linkText = linkInfo.GetLinkText(); // 拿到 "龙息之剑" Debug.Log($"点击了链接:ID={linkId},文本={linkText}"); OnLinkClicked(linkId, linkText); } } } void OnLinkClicked(string id, string text) { // 根据 ID 执行不同逻辑:打开物品面板、跳转网页等 } }

方式二:IPointerClickHandler 接口(推荐,性能更好)

让脚本继承 IPointerClickHandler 接口,利用 Unity 原生 UI 事件系统,比每帧轮询更高效:

csharp
 
using TMPro; using UnityEngine; using UnityEngine.EventSystems; [RequireComponent(typeof(TMP_Text))] public class LinkOpener : MonoBehaviour, IPointerClickHandler { public void OnPointerClick(PointerEventData eventData) { TMP_Text textMeshPro = GetComponent<TMP_Text>(); int linkIndex = TMP_TextUtilities.FindIntersectingLink( textMeshPro, eventData.position, eventData.enterEventCamera // 从事件数据中获取相机 ); if (linkIndex != -1) { TMP_LinkInfo linkInfo = textMeshPro.textInfo.linkInfo[linkIndex]; string linkId = linkInfo.GetLinkID(); string linkText = linkInfo.GetLinkText(); // 处理点击逻辑 HandleLinkClick(linkId, linkText); } } void HandleLinkClick(string id, string text) { // 例如:打开物品详情面板 Debug.Log($"点击了:{text}(ID:{id})"); } }

‌注意:‌ 脚本必须挂载在 TMP 的 UI 对象上,且该对象需要启用 Raycast Target


三、Canvas 渲染模式与相机参数(最容易踩的坑)

FindIntersectingLink 的第三个参数(相机)传什么,完全取决于 Canvas 的 Render Mode

表格
Canvas 渲染模式传入的相机参数说明
‌Screen Space - Overlay‌ null UI 渲染在最上层,不需要相机
‌Screen Space - Camera‌ Canvas 绑定的 World Camera 必须传入对应相机
‌World Space‌ 场景中的主相机或指定相机 UI 存在于 3D 世界中

‌传错相机是最常见的 Bug 来源‌——如果参数不对,FindIntersectingLink 永远返回 -1,点击怎么都没反应。建议测试阶段先用 Overlay 模式,相机参数直接传 null


四、动态生成超链接文本

实际项目中,文本往往是动态拼接的。推荐用 StringBuilder 批量构建,避免频繁字符串拼接带来的 GC 开销:

csharp
 
using System.Text; using TMPro; using UnityEngine; public class ChatMessageBuilder : MonoBehaviour { public TMP_Text chatText; private StringBuilder linkBuilder = new StringBuilder(); public void AddItemLink(string itemName, string itemId) { linkBuilder.AppendLine($"<u><link=\"{itemId}\">{itemName}</link></u>"); } public void ApplyText() { chatText.text = linkBuilder.ToString(); linkBuilder.Clear(); } }

五、实战:物品点击查看详情完整示例

csharp
 
using TMPro; using UnityEngine; using UnityEngine.EventSystems; [RequireComponent(typeof(TMP_Text))] public class ItemLinkHandler : MonoBehaviour, IPointerClickHandler { private TMP_Text tmpText; void Awake() { tmpText = GetComponent<TMP_Text>(); } public void OnPointerClick(PointerEventData eventData) { int linkIndex = TMP_TextUtilities.FindIntersectingLink( tmpText, eventData.position, eventData.enterEventCamera ); if (linkIndex == -1) return; TMP_LinkInfo linkInfo = tmpText.textInfo.linkInfo[linkIndex]; string linkId = linkInfo.GetLinkID(); // 根据 ID 前缀分发不同逻辑 if (linkId.StartsWith("item_")) { OpenItemDetailPanel(linkId); } else if (linkId.StartsWith("player_")) { OpenPlayerProfile(linkId); } } void OpenItemDetailPanel(string itemId) { Debug.Log($"打开物品详情:{itemId}"); // 实际项目中:UIManager.Instance.ShowItemDetail(itemId); } void OpenPlayerProfile(string playerId) { Debug.Log($"打开玩家资料:{playerId}"); } }

文本内容示例:

text
 
玩家[<link="player_007">张三</link>]分享了装备 <color=#FF6600><link="item_2048">暗影之刃</link></color>, 点击名称即可查看详情。

六、进阶:超链接 + 图文混排

TMP 的超链接可以和 Sprite 标签结合,实现图标 + 可点击文字的混排效果:

text
 
点击查看 <sprite name="sword_icon"> <link="item_2048">暗影之刃</link>

调试技巧:

  • 用 <size=150%> 临时放大图标检查对齐
  • 用 <voffset=0.5em> 微调图文垂直对齐
  • 在编辑器中通过 TMP Sprite Asset Creator 批量处理图标

七、常见问题排查

表格
问题可能原因解决方法
点击没反应 相机参数传错了 检查 Canvas 渲染模式,调整第三个参数
点击没反应 Raycast Target 未启用 勾选 TMP 组件上的 Raycast Target
点击没反应 Rich Text 未启用 勾选 TMP 组件上的 Rich Text
链接不显示下划线 没有包裹 <u> 标签 在 <link> 外层加 <u>...</u>
多个链接点击混乱 文本未正确闭合标签 检查每个 <link> 是否有对应的 </link>

掌握了这些,你就能在聊天系统、任务描述、物品说明等任何需要文本交互的场景里,轻松实现类似网页超链接.

http://www.jsqmd.com/news/821530/

相关文章:

  • 挡烟垂壁采购核心疑问解答 合规厂家筛选指南 - 奔跑123
  • Notepad--国产编辑器5大核心技术深度解析:从替代到超越的国产软件实践
  • 如何快速掌握AMD处理器调试工具:从新手到专家的完整指南
  • ParaView动画时间戳全攻略:从科研图表到汇报视频的格式美化技巧
  • 多行业苛刻工况下,机封定制的选型与交付全场景实录 - 奔跑123
  • ncmppGui:基于C++的极速NCM文件解密技术方案为音乐爱好者解决格式限制问题
  • 如何在3分钟内配置你的英雄联盟本地自动化助手:终极指南
  • Dify应用开发入门:通过示例项目快速掌握低代码AI工作流构建
  • 高校新规:毕业论文质量抽检加严!导师太忙不管我?实测8款AI毕业论文工具就是免费私教 - 逢君学术-AI论文写作
  • 免支撑3D打印MacroPad支架:活铰链设计与人体工学应用
  • 海外适配优选!2026声测管厂家推荐排行 品质合规/出口达标 - 极欧测评
  • Meta Ray - Ban 智能眼镜再升级:手势编写消息全开放,多项新功能来袭!
  • 有源滤波器设计全解析:从原理图到实战调试
  • 初次使用 Taotoken 平台从注册到完成第一次 API 调用的全过程记录
  • 不止于诊断:挖掘CANas的UDS刷写与安全算法集成功能(附C# Demo源码解析)
  • 如何在魔兽世界中快速掌握GSE高级宏编辑器:新手完整入门指南
  • Rust操作redis
  • 九大网盘直链下载神器:LinkSwift 终极使用指南与深度解析
  • 矿区重卡充电桩怎么选?2026年品牌深度测评 - 科技焦点
  • 嵌入式系统引导加载程序(Bootloader)设计:从基础原理到工业级实现
  • DevChat:基于工作区模型的AI编程助手,实现上下文感知的持续协作
  • 构建系统核心原理:从DAG调度到缓存机制的设计与实践
  • 上下文引擎:用管道模式解耦业务与横切关注点
  • 魔兽世界宏编辑器终极指南:5分钟掌握GSE高级技能自动化
  • 免费B站视频下载器终极指南:轻松获取大会员4K高清内容
  • AI开发环境隔离利器:基于Bubblewrap的轻量级沙盒实践
  • 机械密封公司排行参考:从工况适配到品控全维度解析 - 奔跑123
  • 如何3分钟搞定九大网盘文件下载:LinkSwift网盘直链助手终极指南
  • 开源协作社区工具OpenClaw Guild:构建高效开发者公会的完整指南
  • 你的差速小车为什么画圈不准?可能是数学模型离散化没搞对(避坑指南)