galgame中很常见的文字弹出加渐隐出现的动效,这个动效没办法交给美术做。
Text作为一个整体,没有办法获取到其中的任意一个字符,成了最难突破的地方,只能把Text组件作为整体来控制,当然N个Text组件,每个控制一个字符倒是也能实现,稍加一些优化简直是活字印刷术。但这种方法效率实在太差了,没办法采用。
放一张图,看一眼大概就知道核心思路是什么了。
原理是开一个协程,在每一帧将原来的字符串转化为带有富文本标记的字符串,然后在富文本标记中设定每一个文字在每一帧的透明度。
核心代码如下,本次采用lua写的,过程可以参考一下
--用于拼接透16进制的透明度值
local Hex = { "0", "1", "2", "3",
"4", "5", "6", "7",
"8", "9", "A", "B",
"C", "D", "E", "F" }
local Format = "{1} "
--渐变的光标以每秒36个字符的速度向后移动
local kTravelSpeed = 36
--渐变动画时长0.1秒
local kFadeDuration = 0.1
--参与渐变动画的字符数量
local kFadeCharCount = kTravelSpeed * kFadeDuration
--- @brief 播放文本过程
--- @public
function AVGTextPanel:PlayTextProcessing()
self.isPlaying = true
--源字符串长度
local strLength = utf8.len(self.str)
--富文本化字符串table
local richStrTable = {}
local charTable = {}
for i = 1, strLength do
--字符串中的每一个字符
local char = utf8.sub(self.str, i, i + 1)
table.insert(charTable, char)
--为每个字符添加富文本标记 所有文字透明度为0
local utf8RichChar = formatex(Format, formatex("#{0}{1}{2}", self.color, Hex[1], Hex[1]), char)
table.insert(richStrTable, utf8RichChar)
end
--加入富文本格式后的字符串
local richStr = table.concat(richStrTable, nil, 1, #richStrTable)
--强制重绘当前ui自适应后的尺寸
self.compText.text = richStr
LayoutRebuilder.ForceRebuildLayoutImmediate(self.transform)
local hasPlayedCharCount = 0 --已经完成渐变动画的字符数量
local currentTime = 0 --当前经过的时间
--存在字符未完成渐变动画
while (hasPlayedCharCount < strLength) do
self:WaitForSeconds(Time.deltaTime)
currentTime = currentTime + Time.deltaTime
--最后一个正在渐变的字符的位置
local lastFadingCharPos = currentTime * kTravelSpeed
--最后一个正在渐变的字符的索引
local lastFadingCharIndex = math.floor(lastFadingCharPos)
--对越界进行修正 索引最小为1
local fixLastFadingCharIndex = Mathf.Min(strLength, lastFadingCharIndex)
fixLastFadingCharIndex = Mathf.Max(1, fixLastFadingCharIndex)
--循环中需要改变值 缓存一份数据
local cacheHasPlayedCharCount = hasPlayedCharCount
--遍历参与渐变的字符
for i = fixLastFadingCharIndex, cacheHasPlayedCharCount, -1 do
--透明度值
local fadeValue = 255 * Mathf.Clamp01((lastFadingCharPos - i) / kFadeCharCount)
local hex1 = math.floor(fadeValue / 16)
local hex2 = math.floor(fadeValue % 16)
richStrTable[i] = formatex(Format, formatex("#{0}{1}{2}", self.color, Hex[hex1 + 1], Hex[hex2 + 1]), charTable[i])
--更新已经完成渐变动画的字符数量
if fadeValue == 255 then
hasPlayedCharCount = Mathf.Max(hasPlayedCharCount, i)
end
end
richStr = table.concat(richStrTable, nil, 1, #richStrTable)
self.compText.text = richStr
end
self:StopPlay()
end