You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Roblox触摸触发音效重复播放致Studio崩溃问题求助

Roblox Lua语音触发脚本异常排查与修复

预期功能

  • 为Positions文件夹内每个Position对象克隆父级Sound并播放
  • 同步在游戏内屏幕显示字幕序列

完整脚本(原始版本)

local Players = game:GetService("Players");
local RunService = game:GetService("RunService");

local col = script.Parent:WaitForChild("Collision", 30);
local audioPositions = script.Parent:WaitForChild("Positions"):GetChildren();
local voiceline = script.Parent;
local subtitleSequence = script.Parent:WaitForChild("SubtitleSequence"):GetChildren();

--[[Contains a function that creates an audio clone by passing the audio to clone
and a target parent which is used on this script (and as far as I know, it works)]]
local audioFunc = require(game:GetService("ReplicatedStorage").__AUDIO);
--[[Used to return the GameGui Subtitles text used to play out the subtitle sequence
(again, as far as I know, it works)]]
local gameUIFunc = require(game:GetService("ReplicatedStorage").__GAME_UI);

local touched = false;

local function RunSubtitleSequence()
    for i, subtitle in pairs(subtitleSequence) do
        local duration = subtitle:WaitForChild("Duration");
        
        local subtitleText = gameUIFunc.returnSubtitlesTextObject(Players.LocalPlayer);
        if subtitleText == nil then return; end;
        subtitleText.Text = subtitle.Value;
        wait(duration.Value);
    end;
    gameUIFunc.returnSubtitlesTextObject(Players.LocalPlayer).Text = "";
end;

col.Touched:Connect(function()
    RunService.Heartbeat:Wait();
    if touched then
        return;
    end;
    touched = true;
    RunService.Heartbeat:Wait();
    for i, audioPosition in pairs(audioPositions) do
        audioFunc.createSound(voiceline, audioPosition);
    end;
    RunService.Heartbeat:Wait();
    task.spawn(function()
        RunSubtitleSequence();
    end);
end);

对象结构

|----Sound [SOUND]
|----|----Positions [FOLDER]
|----|----|----Position [PART]
|----|----|----Position [PART]
|----|----|----Position [PART]
|----|----SubtitleSequence [FOLDER]
|----|----|----0 [STRINGVALUE]
|----|----|----|----Duration [INTVALUE]
|----|----|----1 [STRINGVALUE]
|----|----|----|----Duration [INTVALUE]
|----|----VoicelineTrigger [LOCALSCRIPT]
|----|----Collision [PART]

已尝试手段

  • 添加touched防抖标记
  • 插入RunService.Heartbeat:Wait()做帧同步
  • 使用task.spawn()异步执行字幕序列
  • 改用:Once()绑定事件并销毁Collision部件

报错信息

19:52:46.208  Infinite yield possible on 'ReplicatedStorage.__SCRIPTS.__VOICE_LINES:WaitForChild("Positions")'  -  Studio
19:52:46.208  Stack Begin  -  Studio
19:52:46.209  Script 'ReplicatedStorage.__SCRIPTS.__VOICE_LINES.VoicelineTrigger', Line 5  -  Studio - VoicelineTrigger:5
19:52:46.209  Stack End  -  Studio

同时伴随Roblox核心模块无限等待警告,偶现脚本重复执行导致Studio崩溃。


修复方案

1. 解决资源加载超时问题

脚本启动时Positions等对象可能未完成加载,需添加加载等待与超时判断:

-- 等待游戏核心资源加载完成
repeat task.wait() until game:IsLoaded()

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

-- 逐个加载关键对象,添加超时处理
local col = script.Parent:WaitForChild("Collision", 30)
if not col then warn("Collision部件加载超时") return end

local positionsFolder = script.Parent:WaitForChild("Positions", 30)
if not positionsFolder then warn("Positions文件夹加载超时") return end
local audioPositions = positionsFolder:GetChildren()

local subtitleSeqFolder = script.Parent:WaitForChild("SubtitleSequence", 30)
if not subtitleSeqFolder then warn("SubtitleSequence文件夹加载超时") return end
local subtitleSequence = subtitleSeqFolder:GetChildren()

-- 模块加载也添加超时
local audioModule = ReplicatedStorage:WaitForChild("__AUDIO", 10)
if not audioModule then warn("__AUDIO模块加载失败") return end
local audioFunc = require(audioModule)

local gameUIModule = ReplicatedStorage:WaitForChild("__GAME_UI", 10)
if not gameUIModule then warn("__GAME_UI模块加载失败") return end
local gameUIFunc = require(gameUIModule)

2. 彻底杜绝重复触发

使用:Once()绑定事件,触发后立即断开连接并销毁碰撞体,避免任何重复执行可能:

local function onTouched()
    -- 立即断开事件并销毁碰撞体
    touchedConnection:Disconnect()
    col:Destroy()

    -- 批量克隆并播放音频
    for _, audioPosition in ipairs(audioPositions) do
        audioFunc.createSound(voiceline, audioPosition)
    end

    -- 异步启动字幕序列
    task.spawn(RunSubtitleSequence)
end

-- 绑定一次性触发事件
local touchedConnection = col.Touched:Once(onTouched)

3. 优化字幕序列函数

缓存字幕文本对象,减少重复调用,添加属性超时判断,用task.wait()替代wait()提升性能:

local function RunSubtitleSequence()
    -- 缓存字幕对象,避免重复查找
    local subtitleText = gameUIFunc.returnSubtitlesTextObject(Players.LocalPlayer)
    if not subtitleText then 
        warn("无法获取字幕文本对象")
        return 
    end

    for _, subtitle in ipairs(subtitleSequence) do
        -- 给Duration添加超时等待
        local duration = subtitle:WaitForChild("Duration", 5)
        if not duration then 
            warn("字幕[" .. subtitle.Name .. "]缺少Duration属性")
            continue 
        end

        subtitleText.Text = subtitle.Value
        task.wait(duration.Value)
    end
    -- 清空字幕
    subtitleText.Text = ""
end

4. 脚本结构优化建议

将脚本放在StarterPlayerScripts或StarterCharacterScripts而非ReplicatedStorage,避免因复制导致多实例执行;若必须放在ReplicatedStorage,需添加单例判断确保只运行一次:

-- 单例判断,防止脚本多实例执行
if script:GetAttribute("HasRun") then return end
script:SetAttribute("HasRun", true)

内容的提问来源于stack exchange,提问作者R0CK3T_DEV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:06:11