1

我想要做的是在文件夹中包含一个音频文件(在资源下),我可以将任何合格的音频文件放在指定的文件夹中,并从该单点读取程序中的众多触发器(这就是为什么我的 AudioClip下面是公共静态的,所以我可以参考它)。目前,相同的音频文件在整个程序中工作,但要更改文件需要在 Inspector 中手动重新定义,我的最终客户将无法访问,而且由于存在大量参考点,这很乏味。

这是我到目前为止所拥有的:

public static AudioClip BGM;
public AudioSource BGMSource;
private string formatted1;

void Start()
{
   foreach(string file in System.IO.Directory.GetFiles(Application.dataPath+"/Resources/Audio/BGM"))
   {
      if(file.EndsWith(System.IO.Patch.GetExtension(".mp3")))
      {
        formatted1 = file.Replace(".mp3",string.Empty);
        BGM = Resources.Load<AudioClip>(formatted1); 
         //BGM = (AudioClip)Resources.Load(formatted1,typeof(AudioClip));  <--same result with this
        Debug.Log("found: "+formatted1);
      }

   }
   if(BGM == null)
   {
     Debug.Log("Yeah, its null");
   }

   BGMSource.PlayOneShot(BGM, .9f);

   if(BGMSource.isPlaying != true)
   {
     Debug.Log("I'm not playing");
   }
}

因此,这只是不播放,没有错误消息。原来BGM是空的。Debug 是这样说的,但是如果我要为 BGMSource.clip.name 添加一个 Debug 调用,它将完全出错,并在该 Debug 上出现 NullReferenceException。

formatted1 字符串的调试(文件路径和名称),它确实提供了正确的文件,称为 Test.mp3 ("C:/...Resources/Audio/BGM\Test"),按照推荐的格式没有 ".mp3"从另一个站点。我确实尝试过使用 .mp3 扩展名,似乎没关系,仍然没有播放。我还尝试使用 .wav 文件和 .ogg 文件,结果相同(注意:如果我手动附加为公共 AudioClip,所有文件都很好,因为在这种情况下,上面写的 AudioSource 也会播放,但正如我所带领的,我们在这种情况下不希望那样)。是的,所有测试音频文件都在目录 /Resources/Audio/BGM 中。

另一个网站说了一些关于添加到文件顶部的内容 [RequireComponent(typeof(AudioClip))] 或 [RequireComponent(typeof(AudioSource))] 但什么也没做。

最后,这个程序最终将被分配给一个没有源访问权限的组,因此他们必须能够通过将任何 .mp3 放在 Resources/Audio/BGM 中以进行自动播放来交换音频文件。

欢迎任何帮助,谢谢!

4

1 回答 1

2

首先是一般注意事项:切勿用于+ "/"系统文件路径!而是Path.Combine根据运行的平台自动插入正确的路径分隔符

string file in System.IO.Directory.GetFiles(Path.Combine(Application.dataPath, "Resources", "Audio", "BGM"))

然后请阅读文档Resources.Load

  1. 它需要将您的文件放在一个名为的文件夹中,该文件夹Resources被编译到应用程序构建中,因此之后无法更改。这似乎是你的情况。

  2. 它不需要您传入的完整系统路径Directory.GetFiles,因为返回

    指定目录中文件的全名(包括路径)数组

    而是希望所有Resources文件夹中都有一个路径-是的,您可以有多个文件夹。

    假设您将文件放在类似的结构中

    Assets
    |--Resources
    |  |--someFile.mp3
    |
    |--SomeOtherFolder
    |  |--Resources
    |  |  |--someOtherFile.mp3
    |  |  |--ASubFolder
    |  |  |  |--yetAnotherFile.mp3
    

    然后你会通过使用来解决这些问题

    Resources.Load<AudioClip>("someFile");
    Resources.Load<AudioClip>("someOtherFile");
    Resources.Load<AudioClip>("ASubfolder/yetAnotherFile");
    

    因为什么时候构建所有Resources的都打包在一起。

    所以在你的情况下应该是

    Resources.Load<AudioClip>("Audio/BGM/" + formatted1);
    

    您必须确保这formatted1不是完整路径,而只是文件名!您可以简单地使用Path.GetFileNameWithoutExtension,因此您甚至不需要更换

    var formatted1 = Path.GetFileNameWithoutExtension(file);
    
  3. 很糟糕^^

    在Unity 自己推荐的文件夹的最佳实践中Resources

    不要使用它!


然而

由于根本不建议使用Resources 我宁愿推荐:

如果您以后不想更改它们

您不能更改Resources之后的内容,例如替换文件。因此,如果您以后无论如何都无法更改文件,那么为什么不在以后需要它们的地方直接引用它们呢?

只需将您的音频文件放在一个不 存在的文件夹中,Resources然后直接在脚本中需要它们的地方引用它们:

// Simply drag&drop the clip into this field via the Inspector in Unity
[SerializeField] private AudioClip someClip;

如果您想稍后更改它们

如果您实际上希望能够在构建之后替换它们,您可以改为使用UnityWebRequestMultimedia.GetAudioClip它也可以用于在运行时从系统文件加载文件。为此,您不会将文件放入Resources或任何其他文件夹,而是放入StreamingAssetsApplication.persistentDataPath.

我通常去:

  • 在编辑器使用StreamingAssets文件夹中,因此所有内容都位于项目中并通过以下方式访问它Application.streamingAssetsPath
  • 在构建中首先检查文件是否存在于Application.persistentDataPath
  • 如果不复制并将其Application.streamingAssetsPath存储到Application.persistentDataPath
  • 否则只需从Application.persistentDataPath

修改后的 API 示例

[RequireComponent(typeof(AudioSource))]
public class AudioExample : MonoBehaviour
{
    [SerializeField] private AudioSource _audioSource;

    public List<AudioClip> LoadedAudioClips = new List<AudioClip>;

    private List<UnityWebRequest> _runningWebRequests = new List<UnityWebRequest>();

    private void Awake()
    {
        if(!_audioSource) _audioSource = GetComponent<AudioSource>();
    }

    private void Start()
    {
        StartCoroutine(GetAudioClip());
    }

    private IEnumerator GetAudioClip()
    {
        foreach(string file in System.IO.Directory.GetFiles(Path.Combine(Application.persistentDataPath, "Audio", "BGM"))
        {
            if(!file.EndsWith(System.IO.Patch.GetExtension(".mp3"))) continue;

            UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file:///" + file, AudioType.MPEG);
            {
               _runningWebRequests.Add(www);
               www.Send();
            }
        }

        while(_runningWebRequests.Count > 0)
        {
            foreach(var www in _runningWebRequests.Where(www => www.isDone))
            {
                _runningWebRequests.Remove(www);

                if (www.isError)
                {
                    Debug.LogWarning(www.error);
                }
                else
                {
                    var clip = DownloadHandlerAudioClip.GetContent(www);
                    if(clip == null)
                    {
                        Debug.LogError("Huh?!");
                    }
                    else
                    {
                        LoadedAudioClips.Add(clip);
                    }
                }
            }

            yield return null;
        }
    }
}

还看到你的评论是这样的:

StreamingAssets也是一个特殊文件夹,您可以在其中存储要在运行时读取的文件。它是本地的。此外,此文件夹从外部不“可见”,以后无法更改。

如果您以后需要能够更改内容(例如还保存文件),您将始终需要使用 the Application.persistentDataPath

于 2020-01-31T06:19:27.657 回答