local fentian = {}
function fentian.main(param1, param2, param3, param4)
lib:Require(param1, function(state)
if state then
if param1 then
fentian.parent = lib:openwin(param1, nil, true, param4) or {}
根据你的需求,我来帮你实现一个随机特效飞向对应符文的动画效果。这个功能会在T13值变化时触发,每次只对新增加的属性播放动画。
```lua
-- 在fentian模块中添加特效管理相关代码
fentian._effectPool = {} -- 特效池,用于管理已播放的特效
fentian._lastUsedAttrStr = "" -- 记录上一次的T13值
-- 在upmain函数中添加特效播放逻辑(在获取T13值之后)
function fentian.upmain()
-- ... 前面的代码保持不变 ...
-- 获取T13的值(随机到的属性编号)
local used_attr_str = SL:GetMetaValue("SERVER_VALUE", "T13") or ""
local used_attr_list = {}
if used_attr_str ~= "" then
for v in string.gmatch(used_attr_str, "[^,]+") do
table.insert(used_attr_list, tonumber(v))
end
end
-- 播放特效动画(只对新增加的属性)
fentian:playRandomEffectToAttr(used_attr_str, used_attr_list, ui)
-- ... 后面的代码保持不变 ...
end
-- 新增函数:播放随机特效到属性位置
function fentian:playRandomEffectToAttr(currentAttrStr, attrList, ui)
-- 如果没有属性或UI为空,直接返回
if not currentAttrStr or not ui or not attrList then
return
end
-- 比较当前和上一次的T13值,找出新增的属性
local newAttrs = {}
local lastAttrs = {}
-- 解析上一次的属性
if self._lastUsedAttrStr ~= "" then
for v in string.gmatch(self._lastUsedAttrStr, "[^,]+") do
table.insert(lastAttrs, tonumber(v))
end
end
-- 找出新增的属性(在当前但不在上一次的)
for _, attrId in ipairs(attrList) do
local isNew = true
for _, lastAttrId in ipairs(lastAttrs) do
if attrId == lastAttrId then
isNew = false
break
end
end
if isNew then
table.insert(newAttrs, attrId)
end
end
-- 更新记录
self._lastUsedAttrStr = currentAttrStr
-- 为每个新增属性播放特效
for _, newAttrId in ipairs(newAttrs) do
self:playSingleEffectToAttr(newAttrId, ui)
end
end
-- 新增函数:播放单个特效到属性位置
function fentian:playSingleEffectToAttr(attrId, ui)
-- 获取目标属性节点的位置
local targetNode = ui["cur_attr_" .. attrId]
if GUI:Win_IsNull(targetNode) then
return
end
-- 获取目标位置(世界坐标)
local targetPos = GUI:getWorldPosition(targetNode)
if not targetPos then
return
end
-- 从Effect_21到Effect_28中随机选择一个特效ID
local randomEffectId = math.random(21, 28)
-- 创建父节点(如果不存在)
local parent = GUI:Attach_Parent()
if GUI:Win_IsNull(parent) then
return
end
-- 创建随机起始位置(在屏幕中心附近随机偏移)
local screenW = SL:GetMetaValue("SCREEN_WIDTH") or 800
local screenH = SL:GetMetaValue("SCREEN_HEIGHT") or 600
local startX = screenW / 2 + math.random(-100, 100)
local startY = screenH / 2 + math.random(-100, 100)
-- 创建特效
local effectName = "Effect_Fly_" .. attrId .. "_" .. os.time()
local effect = GUI:Effect_Create(parent, effectName, startX, startY, 3, randomEffectId, 0, 0, 0, 1)
if GUI:Win_IsNull(effect) then
return
end
-- 设置特效初始属性
GUI:setScale(effect, 0.5)
GUI:setLocalZOrder(effect, 9999) -- 确保在最上层
-- 计算移动距离和角度(使用三角函数)
local deltaX = targetPos.x - startX
local deltaY = targetPos.y - startY
local distance = math.sqrt(deltaX * deltaX + deltaY * deltaY)
-- 计算移动时间(根据距离动态调整)
local moveTime = distance / 500 -- 每500像素用1秒
if moveTime < 0.5 then
moveTime = 0.5
elseif moveTime > 2 then
moveTime = 2
end
-- 创建动画序列
local function onAnimationComplete()
-- 动画完成后隐藏并移除特效
GUI:setVisible(effect, false)
SL:ScheduleOnce(function()
if not GUI:Win_IsNull(effect) then
GUI:removeFromParent(effect)
end
end, 0.1)
end
-- 创建移动动画
local moveAction = GUI:ActionMoveBy(moveTime, deltaX, deltaY)
-- 创建缩放动画(先变大后变小)
local scaleUp = GUI:ActionScaleTo(moveTime/2, 0.8)
local scaleDown = GUI:ActionScaleTo(moveTime/2, 0.3)
local scaleSequence = GUI:ActionSequence(scaleUp, scaleDown)
-- 创建旋转动画(如果特效需要旋转)
local rotateAction = GUI:ActionRotateBy(moveTime, 360)
-- 组合动画:同时移动、缩放和旋转
local spawnActions = {}
table.insert(spawnActions, moveAction)
table.insert(spawnActions, scaleSequence)
table.insert(spawnActions, rotateAction)
local spawnAction = GUI:ActionSpawn(unpack(spawnActions))
-- 创建完整动画序列:执行动画 -> 回调
local sequence = GUI:ActionSequence(
spawnAction,
GUI:CallFunc(onAnimationComplete)
)
-- 执行动画
GUI:runAction(effect, sequence)
-- 将特效添加到管理池
self._effectPool[effectName] = {
effect = effect,
attrId = attrId,
startTime = os.time()
}
end
-- 清理特效池的函数(可选)
function fentian:cleanEffectPool()
local currentTime = os.time()
for name, data in pairs(self._effectPool) do
-- 清理超过10秒的特效
if currentTime - data.startTime > 10 then
if not GUI:Win_IsNull(data.effect) then
GUI:removeFromParent(data.effect)
end
self._effectPool[name] = nil
end
end
end
-- 在关闭窗口时清理资源
SL:RegisterLUAEvent(LUA_EVENT_CLOSEWIN, "fentian", function(CLOSEWINdata)
if CLOSEWINdata and CLOSEWINdata == "fentian" then
-- 清理所有特效
for name, data in pairs(fentian._effectPool) do
if not GUI:Win_IsNull(data.effect) then
GUI:removeFromParent(data.effect)
end
end
fentian._effectPool = {}
fentian._lastUsedAttrStr = ""
SL:UnRegisterLUAEvent(LUA_EVENT_PLAYER_EQUIP_CHANGE, "fentian")
SL:UnRegisterLUAEvent(LUA_EVENT_CLOSEWIN, "fentian")
end
end)
```
**实现原理说明:**
1. **新增属性检测**:通过比较当前T13值和上一次记录的T13值,找出新增加的属性ID
2. **随机特效选择**:从Effect_21到Effect_28中随机选择一个特效
3. **三角函数计算**:
- 计算起始位置到目标位置的距离(使用勾股定理)
- 根据距离动态调整动画时间
- 使用`ActionMoveBy`实现直线飞行动画
4. **复合动画效果**:同时包含移动、缩放和旋转动画
5. **特效管理**:使用特效池管理所有播放中的特效,避免内存泄漏
6. **防止重复播放**:只对新增加的属性播放特效,已存在的属性不会重复播放
**使用到的关键函数:**
- `GUI:Effect_Create()` - 创建特效
- `GUI:getWorldPosition()` - 获取世界坐标
- `GUI:ActionMoveBy()` - 移动动作
- `GUI:ActionScaleTo()` - 缩放动作
- `GUI:ActionRotateBy()` - 旋转动作
- `GUI:ActionSequence()` - 动作序列
- `GUI:ActionSpawn()` - 同时执行多个动作
- `GUI:runAction()` - 运行动作
- `GUI:CallFunc()` - 动作回调函数
这样实现后,每次T13值变化时,只会对新增加的属性播放一次飞行动画,不会重复播放已有的属性动画。