Roblox:Humanoid.Died事件触发函数重复执行20+次问题求助
Roblox开发问题排查:事件重复触发与数值多次累加
问题描述
在Roblox开发中,Humanoid.Died()或BindableEvent触发时,绑定的函数会执行20多次,对应的IntegerValue也会被累加相应次数。已尝试防抖(debounce)、BindableEvent、connection:Disconnect()等方法,但问题仍未解决。
相关代码
模块中的damageHumanoid函数
function module.damageHumanoid(attacker, player, humanoid, damage) local connection local debounce = false connection = humanoid.Died:Connect(function() if not debounce then debounce = true connection:Disconnect() module.onDeath(player) end end) if player:FindFirstChild("damage") == nil then newFolder = Instance.new("Folder") newFolder.Name = "damage" newFolder.Parent = player end if newFolder:FindFirstChild(tostring(attacker)) == nil then record = Instance.new("IntValue") record.Name = tostring(attacker) record.Parent = newFolder end if record.Value >= 100 then -- sanity check else record.Value = record.Value + damage end return humanoid:TakeDamage(damage) end
触发的onDeath函数
function module.onDeath(player) if player:FindFirstChild("damage") ~= nil then local folder = player:WaitForChild("damage") local contents = folder:GetChildren() for i,v in pairs(contents) do local item = folder[tostring(v)] damages[item.Name] = item.Value end end local debounce = false if not debounce then debounce = true module.handleKill(damages) end end
剑脚本的Blow函数
function Blow(Hit) if not Hit or not Hit.Parent or not CheckIfAlive() or not ToolEquipped then return end local RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand") if not RightArm then return end local RightGrip = RightArm:FindFirstChild("RightGrip") if not RightGrip or (RightGrip.Part0 ~= Handle and RightGrip.Part1 ~= Handle) then return end local character = Hit.Parent if character == Character then return end local humanoid = character:FindFirstChildOfClass("Humanoid") if not humanoid or humanoid.Health == 0 then return end local player = Players:GetPlayerFromCharacter(character) if player and player == Player then return end UntagHumanoid(humanoid) TagHumanoid(humanoid, Player) module.damageHumanoid(plur, player, humanoid, Damage) end
问题根源分析
- 重复绑定Died事件:每次调用
damageHumanoid都会给同一个Humanoid绑定一次Died事件,多次攻击后会形成多个事件连接,Humanoid死亡时所有连接的回调都会执行,导致函数重复触发。 - 防抖变量作用域错误:
damageHumanoid中的debounce是局部变量,每个事件连接的回调都拥有独立的debounce,无法起到全局防抖的作用;onDeath中的debounce同样是函数内局部变量,每次调用都会重置为false,完全无效。 - 未声明局部变量:
newFolder、record未用local声明,成为全局变量,可能导致变量被意外覆盖,引发逻辑错误。 - 全局
damages变量污染:onDeath中直接使用全局damages表,多次调用会导致数据叠加,且未清理旧数据。
解决方案与修正代码
核心修复点
- 确保
Humanoid.Died事件只绑定一次,使用Once连接(自动执行一次后断开)或维护已绑定标记表。 - 将防抖变量提升到模块级,确保同一玩家/对象的事件回调共享防抖状态。
- 所有局部变量添加
local声明,避免全局污染。 - 每次处理死亡时创建独立的
damages表,避免数据残留。
修正后的代码
模块中的damageHumanoid函数
-- 模块内维护已绑定Died事件的Humanoid,避免重复绑定 local boundHumanoids = {} function module.damageHumanoid(attacker, player, humanoid, damage) -- 仅为未绑定过的Humanoid添加Died事件 if not boundHumanoids[humanoid] then boundHumanoids[humanoid] = true -- 使用Once连接,自动执行一次后断开 humanoid.Died:Once(function() boundHumanoids[humanoid] = nil -- 清理标记,允许玩家复活后重新绑定 module.onDeath(player) end) end -- 局部变量声明,避免全局污染 local damageFolder = player:FindFirstChild("damage") if not damageFolder then damageFolder = Instance.new("Folder") damageFolder.Name = "damage" damageFolder.Parent = player end local attackerId = tostring(attacker) local damageRecord = damageFolder:FindFirstChild(attackerId) if not damageRecord then damageRecord = Instance.new("IntValue") damageRecord.Name = attackerId damageRecord.Parent = damageFolder end -- 简化逻辑 if damageRecord.Value < 100 then damageRecord.Value += damage end return humanoid:TakeDamage(damage) end
触发的onDeath函数
-- 模块级防抖表,防止同一玩家死亡事件被重复处理 local deathHandled = {} function module.onDeath(player) -- 已处理过死亡则直接返回 if deathHandled[player] then return end deathHandled[player] = true local damageFolder = player:FindFirstChild("damage") if not damageFolder then return end -- 创建独立的damages表,避免全局数据污染 local damages = {} for _, record in ipairs(damageFolder:GetChildren()) do if record:IsA("IntValue") then damages[record.Name] = record.Value end end module.handleKill(damages) -- 清理玩家的damage文件夹,避免下次死亡重复读取 damageFolder:Destroy() -- 5秒后清理防抖标记,允许玩家复活后重新处理死亡事件 task.delay(5, function() deathHandled[player] = nil end) end
剑脚本的Blow函数
function Blow(Hit) if not Hit or not Hit.Parent or not CheckIfAlive() or not ToolEquipped then return end local RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand") if not RightArm then return end local RightGrip = RightArm:FindFirstChild("RightGrip") if not RightGrip or (RightGrip.Part0 ~= Handle and RightGrip.Part1 ~= Handle) then return end local character = Hit.Parent if character == Character then return end local humanoid = character:FindFirstChildOfClass("Humanoid") -- 修正判断条件,Health<=0时直接返回 if not humanoid or humanoid.Health <= 0 then return end local player = Players:GetPlayerFromCharacter(character) if player and player == Player then return end UntagHumanoid(humanoid) TagHumanoid(humanoid, Player) -- 修正笔误:plur改为Player module.damageHumanoid(Player, player, humanoid, Damage) end
内容的提问来源于stack exchange,提问作者DrGigaByte
相关产品推荐
相关产品推荐

