Lua Roblox API: 如何防抖一个撞到盒子里的玩家/角色

背景: 只有一个玩家和一个浮在空中并被固定的部件(矩形棱柱)。

实际上我不太明白底层发生了什么,所以很难理解。没有防抖,当事件触发时,回调函数被connect()或事件处理程序(不确定)调用,而没有防抖,函数会多次调用,打印语句会在输出框中重复。因此,在一个存储防抖标志的变量(布尔类型)的情况下,这个问题得到了解决。然后,当玩家的模型在盒子的模型外时,我尝试“取消防抖”。但是,我不知道如何正确地做这件事。

下面是我的代码尝试:

local box = game.Workspace.BoxModel;
local debounce = false;

local function onTouchedDebounced()
    if (debounce == false)
    then
        debounce = true;
        print(“Hello! onTouchedDebounced() has run.”);
        box.Touched:Connect(onTouchedDebounced));
    end
end

local function onTouchedUndebounced()
    if (debounce == true)
    then
        print(“Hello! onTouchedUndebounced() has run.”);
        debounce = false;
    end
end

box.Touched:Connect(onTouchedDebounced);
box.TouchEnded:Connect(onTouchedUndebounced);
点赞
用户2860267
用户2860267

你所做的核心是正确的:在第一个事件之后开始阻止,并在一段时间后解除阻止。如果这是按钮按下或鼠标点击,你的解决方案将工作良好。但是 Touched 事件增加了复杂性,因为每个接触盒子的物体都会触发它,一个玩家的角色可能有多个接触点。

TouchedTouchEndeded 事件提供了一个引用,指向触摸零件的实例。

如果目标是每个玩家仅触发一次事件,或者只要有人触摸它就触发一次,则可以保持一个当前正在接触盒子的零件字典。当一个对象接触时,你会增加一个计数器。当一个部分停止时,你会减少它。只有在所有触摸点都被移除后,你才会移除抖动标志。

local box = game.Workspace.BoxModel
local playersTouching = {} --<string playerName, int totalParts>

local function onTouchedDebounced(otherPart)
    -- 检查触碰的是玩家
    local playerModel = otherPart.Parent
    if not playerModel:IsA("Model") then
        warn(otherPart.Name .. " 不是角色的子级。退出。")
        return
    end

    -- 检查是否已经有玩家触碰了盒子
    local playerName = playerModel.Name
    local total = playersTouching[playerName]
    if total and total > 0 then
        warn(playerName .. " 已经接触了盒子")
        playersTouching[playerName] = total + 1
        return
    end

    -- 处理一个接触盒子的新玩家
    playersTouching[playerName] = 1

    -- 在这里做你只想每次事件发生一次的事情...
    print(string.format("%s 和 %s 触发了 onTouchedDebounced()。", playerName, otherPart.Name))
end

local function onTouchedUndebounced(otherPart)
    -- 减少此玩家的计数器
    local playerName = otherPart.Parent.Name
    if playersTouching[playerName] == nil then
        return
    end

    local newTotal = playersTouching[playerName] - 1
    playersTouching[playerName] = newTotal

    -- 如果总数回到了零,清除抖动标志
    if newTotal == 0 then
        playersTouching[playerName] = nil
        print(string.format("%s 已经没有更多的接触零件,在 onTouchedUndebounced() 中触发。", playerName))
    end
end

box.Touched:Connect(onTouchedDebounced)
box.TouchEnded:Connect(onTouchedUndebounced)
2020-08-05 03:24:38