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中的属性ID,随机从Effect_21到Effect_28中选择一个特效,让它飞到对应的cur_attr位置。
以下是完整的代码实现:
```lua
-- 在fentian表中添加特效管理相关变量
fentian._effectPool = {} -- 特效对象池
fentian._usedEffects = {} -- 已使用的特效ID记录
fentian._attrPositions = {} -- 属性位置缓存
-- 初始化特效池和位置
function fentian:initEffectSystem()
-- 清空记录
fentian._usedEffects = {}
fentian._attrPositions = {}
-- 预计算所有cur_attr的位置
for i = 1, 8 do
local attrName = "cur_attr_" .. i
if not GUI:Win_IsNull(fentian.parent._ui[attrName]) then
local pos = GUI:getWorldPosition(fentian.parent._ui[attrName])
fentian._attrPositions[i] = pos
end
end
end
-- 创建随机特效动画
function fentian:playRandomEffectToAttr(attrId)
-- 检查参数有效性
if not attrId or attrId < 1 or attrId > 8 then
SL:Print("无效的属性ID:", attrId)
return
end
-- 检查目标位置是否存在
local targetPos = fentian._attrPositions[attrId]
if not targetPos then
SL:Print("属性" .. attrId .. "的位置未找到")
return
end
-- 随机选择一个特效ID (21-28)
local effectId = math.random(21, 28)
-- 检查该特效是否已在使用中
if fentian._usedEffects[effectId] then
-- 如果已使用,重新随机(最多尝试8次)
for i = 1, 8 do
effectId = math.random(21, 28)
if not fentian._usedEffects[effectId] then
break
end
end
end
-- 如果所有特效都在使用中,使用第一个可用的
if fentian._usedEffects[effectId] then
for i = 21, 28 do
if not fentian._usedEffects[i] then
effectId = i
break
end
end
end
-- 标记特效为已使用
fentian._usedEffects[effectId] = true
-- 获取UI根节点
local ui = fentian.parent._ui
if not ui or GUI:Win_IsNull(ui.Layout_eff) then
SL:Print("特效容器不存在")
return
end
-- 创建特效
local effectName = "fly_effect_" .. effectId
local flyEffect = GUI:Effect_Create(ui.Layout_eff, effectName, 0, 0, 3, effectId, 0, 0, 0, 1)
if GUI:Win_IsNull(flyEffect) then
SL:Print("创建特效失败,ID:", effectId)
return
end
-- 设置特效初始位置(屏幕中央)
local screenW = SL:GetMetaValue("SCREEN_WIDTH") or 0
local screenH = SL:GetMetaValue("SCREEN_HEIGHT") or 0
local startX = screenW / 2
local startY = screenH / 2
GUI:setPosition(flyEffect, startX, startY)
GUI:setScale(flyEffect, 0.5) -- 初始缩放
-- 计算飞行距离和角度
local dx = targetPos.x - startX
local dy = targetPos.y - startY
local distance = math.sqrt(dx * dx + dy * dy)
-- 计算角度(弧度)
local angle = math.atan2(dy, dx)
-- 计算控制点(贝塞尔曲线中间点)
local controlX = startX + dx * 0.5
local controlY = startY + dy * 0.5 + 100 -- 向上弯曲
-- 创建贝塞尔曲线动作
local bezierConfig = {
controlPoint_1 = cc.p(startX + dx * 0.3, startY + dy * 0.3 + 80),
controlPoint_2 = cc.p(startX + dx * 0.7, startY + dy * 0.7 + 80),
endPosition = cc.p(targetPos.x, targetPos.y)
}
-- 计算飞行时间(根据距离调整)
local flyTime = distance / 500 -- 每500像素1秒
if flyTime < 0.5 then flyTime = 0.5 end
if flyTime > 2.0 then flyTime = 2.0 end
-- 创建动作序列
local actionSequence = GUI:ActionSequence(
-- 同时执行移动和旋转
GUI:ActionSpawn(
GUI:ActionBezierTo(flyTime, bezierConfig),
GUI:ActionRotateBy(flyTime, angle * 57.2958) -- 弧度转角度
),
-- 到达后缩放消失
GUI:ActionScaleTo(0.2, 0.1),
GUI:ActionFadeTo(0.2, 0),
-- 回调:移除特效并清理标记
GUI:CallFunc(function()
-- 移除特效
if not GUI:Win_IsNull(flyEffect) then
GUI:removeFromParent(flyEffect)
end
-- 清除标记
fentian._usedEffects[effectId] = nil
SL:Print("特效动画完成,属性ID:", attrId)
end)
)
-- 执行动作
GUI:runAction(flyEffect, actionSequence)
SL:Print("开始播放特效动画,特效ID:", effectId, "目标属性:", attrId)
end
-- 更新特效动画(在upmain函数中调用)
function fentian:updateEffectAnimations()
-- 初始化特效系统
fentian:initEffectSystem()
-- 获取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
-- 为每个属性播放动画
for _, attrId in ipairs(used_attr_list) do
-- 使用延迟执行,让动画有先后顺序
SL:ScheduleOnce(function()
fentian:playRandomEffectToAttr(attrId)
end, 0.3 * (_ - 1)) -- 每个动画间隔0.3秒
end
end
-- 在fentian.upmain函数中添加特效动画调用
-- 找到原来的upmain函数,在适当位置添加:
function fentian.upmain()
-- ... 原有的代码 ...
-- 在显示属性特效之后,添加动画调用
-- 原来的代码:
-- 根据T13显示对应特效
for _, attr_id in ipairs(used_attr_list) do
local effect_name = "cur_attr_" .. attr_id
if not GUI:Win_IsNull(ui[effect_name]) then
GUI:setVisible(ui[effect_name], true)
end
end
-- 在这里添加特效动画
fentian:updateEffectAnimations()
-- ... 剩余的原有代码 ...
end
-- 修改事件监听,当T13变化时重新播放动画
SL:RegisterLUAEvent(LUA_EVENT_SERVER_VALUE_CHANGE, "fentian", function(data)
if next(data) and data.key == "T13" then
-- 先更新界面
fentian.upmain()
-- 然后播放新的动画
SL:ScheduleOnce(function()
fentian:updateEffectAnimations()
end, 0.1) -- 延迟0.1秒确保界面更新完成
end
end)
```
**代码说明:**
1. **特效管理系统**:
- `_effectPool`: 管理特效对象
- `_usedEffects`: 记录正在使用的特效ID,避免重复
- `_attrPositions`: 缓存所有cur_attr的世界坐标
2. **动画流程**:
- 从Effect_21到Effect_28随机选择特效
- 特效从屏幕中央飞向对应的cur_attr位置
- 使用贝塞尔曲线实现弧形飞行效果
- 动画完成后自动移除特效
3. **防止重复**:
- 每个特效ID在同一时间只能使用一次
- 已播放过的动画不会重复播放
4. **性能优化**:
- 使用对象池思想管理特效
- 动画完成后立即清理资源
- 使用延迟执行避免动画重叠
**使用注意事项**:
1. 确保Effect_21到Effect_28这些特效资源存在
2. cur_attr_1到cur_attr_8的UI节点需要正确设置
3. 动画时间根据屏幕距离自动调整
4. 多个属性动画会顺序播放,间隔0.3秒
这个实现完全符合你的需求:T13中每新增一个属性,就会随机选择一个未使用的特效播放动画,且不会重复播放之前的动画。