聊天里的「[裁决之杖]」不是纯文本:点击弹出道具详情、鼠标悬停显示属性——图文混排让聊天里的道具名变成可交互的链接。图文混排的实现要点是标记的解析、图标与文字的混合渲染与点击的命中判定。
---图文混排:标记解析为富文本段
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 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
设计初衷 结婚是传奇里少数的"全服见证型"消费场景:玩家愿意为仪式感花钱,但仪式感的档位要拉开且各档都有体面——简约档不寒酸…
设计初衷 沙巴克攻城的荣誉需要一条可以触摸的兑现路径:战功商店用功勋货币把"为行会流血"折算成专属奖励。设计目标三条:功勋只…
底层原理 限频器(throttle)一刀切:窗口内只放一次,突发全拒。令牌桶是它的互补形态:桶以恒定速率生成令牌(每秒 2 …
设计初衷 货币系统的失控从不是一夜之间:金币产出每周悄悄多 5%,三个月后物价翻倍才被发现,追溯源头时账目早已混成一团。经济…
业务场景 沙巴克攻城前,行会会长发放集结令:会员凭令在开战前 30 分钟传送集结点,一令一人。令旗系统的三个环节:发放(按会…
底层原理 元表 __call 让一张表可以像函数一样被调用:call(table, args) 触发时,Lua 先查表的 _…