local leishen = {}
local function showEffect(msgID, p1, p2, p3, msgData)
local data = SL:JsonDecode(msgData, false) or {}
SL:Print("特效数据", data)
local num = data.num or 0
local eff1, eff2 = data.preEff, data.startEff
-- 创建父节
根据你提供的代码,我看到了前端使用了多个定时器来控制特效倒计时。从浮生梦老师前端课程内容来看,定时器应该在后端统一管理,前端只负责接收后端发送的时间数据并更新显示。
以下是修改方案:
## 后端修改(leishen.link函数中arg2 == 4的部分):
```lua
elseif arg2 == 4 then
-- Button_5: 触发特效
local config = {
preEff = 83433, -- 预警特效ID
startEff = 83383, -- 技能特效ID
cd = 40, -- 特效cd时间
num = math.random(3, 5) -- 3-5个特效
}
local now = os.time()
local time = getobjintvar(actor, 40) or 0
if now - time > config.cd then
lib:msg(actor, "触发华丽特效!", 1)
local data = {}
data.num = config.num
data.preEff = config.preEff
data.startEff = config.startEff
-- 获取玩家位置
local mapid = getbaseinfo(actor, 3)
local x, y = getbaseinfo(actor, 4), getbaseinfo(actor, 5)
data.mapdata = {}
for i = 1, data.num do
data.mapdata[i] = {
x = x + math.random(-6, 6),
y = y + math.random(-6, 6)
}
end
-- 设置冷却时间
setobjintvar(actor, 40, now)
-- 启动后端定时器
local timerID = "leishen_timer_" .. getobjid(actor)
local count = 40 -- 总倒计时秒数
-- 后端定时器每秒发送时间给前端
addtimer(timerID, 1, function()
count = count - 1
if count >= 0 then
-- 发送当前剩余时间给前端
local timeData = {
totalCount = count,
percent = (count / 40) * 100
}
sendluamsg(actor, 2028, tbl2json(timeData)) -- 使用新消息ID 2028
return true -- 继续定时器
else
-- 定时器结束
return false
end
end)
-- 发送初始特效数据给前端
sendluamsg(actor, 2027, tbl2json(data))
else
local remaining = config.cd - (now - time)
lib:msg(actor, "特效还在冷却中,请等待" .. remaining .. "秒!", 1)
end
end
```
## 前端修改(showEffect函数):
```lua
local function showEffect(msgID, p1, p2, p3, msgData)
local data = SL:JsonDecode(msgData, false) or {}
SL:Print("特效数据", data)
local num = data.num or 0
local eff1, eff2 = data.preEff, data.startEff
-- 检查窗口是否已存在
local existingWin = GUI:getChildByName(GUI:getRootNode(), "EffectLayer")
if existingWin and not GUI:Win_IsNull(existingWin) then
GUI:removeFromParent(existingWin)
end
-- 创建父节点作为容器
local sceneLayer = GUI:Win_Create("EffectLayer", 0, 0, 0, 0, false, false, true, false, false, false, 1)
-- 主倒计时进度条
local mainImage = GUI:Image_Create(sceneLayer, "Main_Image", 700, 500, "res/erdalu/leishen/jdt/leishen.png")
if GUI:Win_IsNotNull(mainImage) then
GUI:setVisible(mainImage, true)
end
local mainLoadingBar = GUI:LoadingBar_Create(mainImage, "Main_LoadingBar", 0, 0, "res/erdalu/leishen/jdt/1.png", 0)
GUI:LoadingBar_setPercent(mainLoadingBar, 100) -- 初始100%
-- 存储所有需要管理的对象
local effectObjects = {}
for i = 1, num do
-- 获取屏幕尺寸
local screenWidth = SL:GetMetaValue("SCREEN_WIDTH") or 1280
local screenHeight = SL:GetMetaValue("SCREEN_HEIGHT") or 720
-- 在屏幕范围内随机位置显示特效
local posX, posY
if data.mapdata and data.mapdata[i] then
posX = data.mapdata[i].x or math.random(100, screenWidth - 100)
posY = data.mapdata[i].y or math.random(100, screenHeight - 100)
else
posX = math.random(100, screenWidth - 100)
posY = math.random(100, screenHeight - 100)
end
-- 创建预警特效
local circleEffect = GUI:Effect_Create(sceneLayer, "circle_effect_" .. i,
posX, posY, 0, eff1, 0, 0, 0, 1)
-- 每个特效的倒计时文本
local countdownText = GUI:Text_Create(circleEffect, "countdown_" .. i,
0, 30, 20, "#FF0000", "40")
-- 存储对象
effectObjects[i] = {
circleEffect = circleEffect,
countdownText = countdownText,
posX = posX,
posY = posY,
eff2 = eff2,
count = 40
}
end
-- 注册接收后端定时器时间的消息
SL:RegisterLuaNetMsg(2028, function(msgID, p1, p2, p3, timeDataStr)
local timeData = SL:JsonDecode(timeDataStr, false) or {}
local totalCount = timeData.totalCount or 0
local percent = timeData.percent or 0
SL:Print("收到后端时间数据:", "剩余时间:", totalCount, "百分比:", percent)
-- 更新主进度条
if not GUI:Win_IsNull(mainLoadingBar) then
GUI:LoadingBar_setPercent(mainLoadingBar, percent)
end
-- 更新所有特效的倒计时文本
for i = 1, num do
if effectObjects[i] and effectObjects[i].countdownText then
if not GUI:Win_IsNull(effectObjects[i].countdownText) then
GUI:Text_setString(effectObjects[i].countdownText, tostring(totalCount))
end
-- 当倒计时为0时触发技能特效
if totalCount == 0 then
if not GUI:Win_IsNull(effectObjects[i].circleEffect) then
-- 创建技能特效
local skillEffect = GUI:Effect_Create(sceneLayer, "skill_effect_" .. i .. math.random(999999),
effectObjects[i].posX, effectObjects[i].posY, 0, eff2, 0, 0, 0, 1)
-- 技能特效动画
if not GUI:Win_IsNull(skillEffect) then
GUI:setOpacity(skillEffect, 255)
local skillAction = GUI:ActionSequence(
GUI:ActionScaleTo(0.2, 2.0),
GUI:DelayTime(0.3),
GUI:ActionFadeTo(0.5, 0),
GUI:CallFunc(function()
GUI:removeFromParent(skillEffect)
end)
)
GUI:runAction(skillEffect, skillAction)
end
-- 清理单个特效
if not GUI:Win_IsNull(effectObjects[i].countdownText) then
GUI:removeFromParent(effectObjects[i].countdownText)
end
if not GUI:Win_IsNull(effectObjects[i].circleEffect) then
GUI:removeFromParent(effectObjects[i].circleEffect)
end
end
end
end
end
-- 所有倒计时结束,清理场景
if totalCount == 0 then
SL:Sleep(1) -- 等待1秒让技能特效播放完
if not GUI:Win_IsNull(sceneLayer) then
GUI:removeFromParent(sceneLayer)
end
-- 取消注册消息
SL:UnRegisterLuaNetMsg(2028)
end
end)
end
```
## 修改要点:
1. **后端统一管理定时器**:使用`addtimer`函数在后端创建定时器,每秒向前端发送当前剩余时间
2. **前端只负责显示**:前端不再使用`SL:Schedule`,而是通过消息2028接收后端的时间数据
3. **消息分离**:
- 2027消息:发送特效初始数据
- 2028消息:发送定时器时间数据
4. **资源清理**:在倒计时结束后正确取消消息注册
这样修改后,定时器的控制权完全在后端,前端只需要根据后端发送的数据更新显示,符合游戏开发的最佳实践。