一个 防抖 模式是防止函数过多运行或输入触发多次的编码技术。以下脚本场景展示了防抖作为最佳实践。
检测碰撞
假设您想创建一个危险的陷阱部件,当被触碰时造成10点伤害。初始实现可能会使用基本的 BasePart.Touched 连接和如下的 damagePlayer 函数:
脚本 - 伤害玩家
local part = script.Parent
local function damagePlayer(otherPart)
print(part.Name .. " 与 " .. otherPart.Name .. " 碰撞")
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
humanoid.Health -= 10 -- 减少玩家健康
end
end
part.Touched:Connect(damagePlayer)
虽然乍一看是合逻辑的,但测试会显示 Touched 事件在细微物理碰撞的基础上快速多次触发。

为了避免初次接触造成过多伤害,您可以添加一个防抖系统,通过 实例属性 强制实施伤害的冷却时间。
脚本 - 使用防抖给予伤害
local part = script.Parent
local RESET_TIME = 1
local function damagePlayer(otherPart)
print(part.Name .. " 与 " .. otherPart.Name .. " 碰撞")
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
if not part:GetAttribute("Touched") then
part:SetAttribute("Touched", true) -- 设置属性为真
humanoid.Health -= 10 -- 减少玩家健康
task.wait(RESET_TIME) -- 等待重置持续时间
part:SetAttribute("Touched", false) -- 重置属性
end
end
end
part.Touched:Connect(damagePlayer)
触发声音
在处理音效时,防抖也是很有用的,例如在两个部件碰撞时播放声音 (Touched),或者在用户与屏幕按钮交互时在 Activated 事件上播放声音。在这两种情况下,调用 Sound:Play() 会从其轨道的开始位置播放,如果没有防抖系统,声音可能会快速多次播放。
为了防止声音重叠,您可以使用 IsPlaying 属性进行防抖:
脚本 - 使用防抖播放碰撞声音
local projectile = script.Parent
local function playSound()
-- 查找部件上的子声音
local sound = projectile:FindFirstChild("Impact")
-- 仅在声音尚未播放时播放
if sound and not sound.IsPlaying then
sound:Play()
end
end
projectile.Touched:Connect(playSound)
脚本 - 使用防抖播放按钮点击声
local button = script.Parent
local function onButtonActivated()
-- 查找按钮上的子声音
local sound = button:FindFirstChild("Click")
-- 仅在声音尚未播放时播放
if sound and not sound.IsPlaying then
sound:Play()
end
end
button.Activated:Connect(onButtonActivated)
拾取效果
游戏中通常包含可在3D世界中收集的道具,例如医药包、弹药包等。如果您设计这些可收集物品使其在世界中保持供玩家一次又一次地抓取,则在拾取刷新和重新激活之前,应添加一个“冷却”时间。
与 检测碰撞 类似,您可以通过 实例属性 管理防抖状态,并通过更改部件的 Transparency 可视化冷却时间。
脚本 - 使用防抖的健康道具
local part = script.Parent
part.Anchored = true
part.CanCollide = false
local COOLDOWN_TIME = 5
local function healPlayer(otherPart)
local humanoid = otherPart.Parent:FindFirstChildWhichIsA("Humanoid")
if humanoid then
if not part:GetAttribute("CoolingDown") then
part:SetAttribute("CoolingDown", true) -- 设置属性为真
humanoid.Health += 25 -- 增加玩家健康
part.Transparency = 0.75 -- 使部件半透明以指示冷却状态
task.wait(COOLDOWN_TIME) -- 等待冷却持续时间
part.Transparency = 0 -- 重置部件为完全不透明
part:SetAttribute("CoolingDown", false) -- 重置属性
end
end
end
part.Touched:Connect(healPlayer)