聊天里的「[裁决之杖]」不是纯文本:点击弹出道具详情、鼠标悬停显示属性——图文混排让聊天里的道具名变成可交互的链接。图文混排的实现要点是标记的解析、图标与文字的混合渲染与点击的命中判定。
---图文混排:标记解析为富文本段
function RichText.parse(text)
local segments = {}
local pos = 1
while pos <= #text do
local s, e = text:find('%[item:(%d+)%]', pos)
if s then
if s > pos then
segments[#segments + 1] =
{ type = 'text', content = text:sub(pos, s - 1) }
end
local itemId = tonumber(text:match('%[item:(%d+)%]', pos))
segments[#segments + 1] =
{ type = 'item', id = itemId }
pos = e + 1
else
segments[#segments + 1] =
{ type = 'text', content = text:sub(pos) }
break
end
end
return segments
end
混排的解析把文本拆成段落:纯文本段与道具段交替排列——道具段的标记格式 [item:ID],ID 对应道具的模板表。解析的结果驱动渲染:文本段用纯文本渲染、道具段用图标加名字的可点击链接渲染,混排的视觉让道具在聊天里一眼可辨。
---混排的渲染:文本与图标的混合
function RichText.render(win, segments)
local x = 0
for _, seg in ipairs(segments) do
if seg.type == 'text' then
local t = GUI:Text_Create(win, nil, x, 0,
12, "#FFFFFF", seg.content)
x = x + GUI:Text_GetWidth(t)
elseif seg.type == 'item' then
local icon = GUI:Image_Create(win, nil,
x, -2, IconAtlas.get(Item.iconOf(seg.id)))
GUI:addOnClickEvent(icon, function()
ItemPopup.show(seg.id)
end)
x = x + 34
end
end
end
渲染的混合将文本与图标在行内交替排布:文本段按宽度排布、图标段固定 34 像素的宽度——图标与文字的基线对齐让混排的视觉不突兀。道具链接的点击弹出详情浮窗:名字、品质、属性、获取途径——点击的交互让聊天里的道具名变成商店橱窗。表情的嵌入走同一段的解析逻辑:表情以 {f:ID} 的占位符嵌入,渲染时替换为表情图,表情与道具的混排在同一行共存。
混排的渲染一致性测试:解析的段落数与渲染的控件数一致,文本与图标的交替不错位;混排行的高度自适应测试:图标的高度不撑破行高。
解析的正则曾经贪婪匹配,两个道具链接之间的文本被吞掉,非贪婪的匹配修复。图标的点击热区曾经偏移,点击区域与图标的视觉边界错位,热区的校准用标记框辅助调试。混排的行高曾经不统一,图标行比纯文本行高出几像素,行高按最大子元素的高度统一。
道具链接的格式进协议文档:发送端怎么标记、接收端怎么解析。表情的图集与道具的图集分离加载,聊天的打开不依赖全量图标的就绪。混排的渲染支持多行折叠:超长的消息折叠为「展开查看」,交互的体验不因长文本破坏。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
实战应用:用在哪里 战士的烈火剑法一击熄火后要等八秒冷却,连招断档感强烈。疾风烈火斩在烈火剑法命中后给一次连击窗口:三秒内再…
实战应用:用在哪里 阵营对抗打到中期容易疲软:打赢没有额外好处,输掉也没有代价。阵营声望体系给阵营战装上荣誉刻度:个人与阵营…
实战应用:用在哪里 拿下沙巴克之后呢?城主除了名字挂在城墙上,对城市毫无影响。城主施政玩法让占领变成治理:城主每周获得市政令…
实战应用:用在哪里 主线路光缆被挖断的深夜,全服掉线 20 分钟,玩家以为游戏倒闭。备用线路方案给接入层配第二条出口:主线路…
实战应用:用在哪里 行会官员由帮主任命的老模式弊端明显:任人唯亲、能上不能下。行会选举接口把官员换届做成投票制:每两个月一次…
实战应用:用在哪里 烈火剑法的伤害加成、冷却时间、下一级提升,全靠玩家记忆或去官网查。技能说明悬浮卡片在鼠标悬停技能图标零点…