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

Unity中AudioSource播放时Slider进度显示实现问题求助

Unity音频进度Slider整合解决方案(解决应用冻结问题)

问题根源分析

  • 应用冻结是因为Update函数中循环赋值audio.time = time.value:每帧先把Slider值同步为音频当前时间,紧接着又把音频时间设回Slider值,形成无限循环阻塞主线程。
  • 重复设置time.maxValue = audio.clip.length完全冗余,会造成不必要的性能消耗。
  • 未区分“进度同步”和“用户拖动跳转”的逻辑,应该用Slider的事件回调处理用户交互,而非在Update里强制同步。

完整修正代码

整合原有功能与Slider的正确逻辑,修复所有问题:

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class AudioPlayer : MonoBehaviour
{
    [Header("List of Tracks")]
    [SerializeField] private Track[] audioTracks;
    
    private int trackIndex; 
    
    [Header("UI Components")]
    [SerializeField] private TextMeshProUGUI trackTextUI;
    [SerializeField] private Slider progressSlider; // 进度Slider
    
    private AudioSource audioSource;
    private bool isUserDraggingSlider; // 标记用户是否正在拖动Slider

    private void Start()
    {
        audioSource = GetComponent<AudioSource>();
        InitializeTrack(0); // 初始化默认曲目
        SetupSliderEvents(); // 绑定Slider交互事件
    }

    // 初始化曲目并更新Slider最大值
    private void InitializeTrack(int index)
    {
        trackIndex = index;
        audioSource.clip = audioTracks[trackIndex].trackAudioClip;
        trackTextUI.text = audioTracks[trackIndex].name;
        
        // 仅在切换曲目时设置Slider最大值
        progressSlider.maxValue = audioSource.clip.length;
        progressSlider.value = 0; // 重置进度到开头
    }

    // 设置Slider的交互事件
    private void SetupSliderEvents()
    {
        progressSlider.onDragStart.AddListener(_ => isUserDraggingSlider = true);
        progressSlider.onDragEnd.AddListener(_ => 
        {
            isUserDraggingSlider = false;
            // 拖动结束后同步音频到Slider位置
            audioSource.time = progressSlider.value;
        });
    }

    private void Update()
    {
        // 只有用户没拖动Slider且音频播放时,才同步进度到Slider
        if (!isUserDraggingSlider && audioSource.isPlaying)
        {
            progressSlider.value = audioSource.time;
        }
    }

    // 曲目切换按钮逻辑
    public void FiveMinuteMed()
    {
        InitializeTrack(0);
        audioSource.Play();
    }
    
    public void TenMinuteMed()
    {
        InitializeTrack(1);
        audioSource.Play();   
    }
    
    public void FifteenMinuteMed()
    {
        InitializeTrack(2);
        audioSource.Play();
    }

    // 播放/暂停/停止逻辑
    public void PlayAudio()
    {
        audioSource.Play();
    }
    
    public void PauseAudio()
    {
        audioSource.Pause();
    }
    
    public void StopAudio()
    {
        audioSource.Stop();
        progressSlider.value = 0; // 停止时重置Slider到开头
    }
}

// 确保Track类的定义正确
[System.Serializable]
public class Track
{
    public string name;
    public AudioClip trackAudioClip;
}

关键改动说明

  1. 移除循环赋值:删除audio.time = time.value,用isUserDraggingSlider标记区分自动同步和用户交互,彻底解决主线程阻塞问题。
  2. 优化Slider最大值设置:仅在切换曲目时设置progressSlider.maxValue,避免每帧重复操作浪费性能。
  3. 使用Slider事件处理交互:通过onDragStart和onDragEnd标记用户拖动状态,拖动结束后再同步音频进度,既支持跳转又避免循环冲突。
  4. 规范变量命名:把原变量名audio改为audioSource,避免和Unity内置关键字冲突,提升代码可读性。
  5. 同步UI与音频状态:调用StopAudio()时同步重置Slider值为0,保证UI状态和音频状态一致。

使用注意事项

  • 在Inspector面板中,将Slider组件拖到progressSlider字段上。
  • 确保Track数组中的每个元素都正确赋值name和trackAudioClip。
  • 按钮的OnClick事件分别绑定对应的方法(如FiveMinuteMed、PlayAudio等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:25:11