Unity3D: Resource.Load определил, что AudioClip заканчивает тем, что Null входит в AudioSource - PullRequest
0 голосов
/ 31 января 2020

Я пытаюсь сделать аудиофайл в папке (в разделе «Ресурсы»), куда я могу поместить любой подходящий аудиофайл в указанную папку и получить в моей программе многочисленные триггеры, считываемые из этой единственной точки (которая является почему мой AudioClip ниже опубликован c stati c, поэтому я могу сослаться на него). В настоящее время один и тот же аудиофайл работает во всей программе, но для его изменения требуется ручное переопределение в Инспекторе, к которому у моего конечного клиента не будет доступа, и, кроме того, он утомителен из-за множества существующих опорных точек.

Вот то, что у меня есть:

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, он полностью выдаст ошибку с NullReferenceException для этой отладки.

Отладка для строки formatted1 (Путь к файлу и имя), он представляет правильный файл с именем Test.mp3 («C: / ... Resources / Audio / BGM \ Test»), отформатированный без «.mp3», как было рекомендовано с другого сайта. Я попробовал с включенным расширением .mp3, казалось, не имеет значения, все еще не играл. Я также попытался с файлами .wav и .ogg, тот же результат (примечание: все файлы были в порядке, если я подключил их как publi c AudioClip вручную, так как в этом случае будет воспроизводиться также AudioSource, как написано выше, но, как я говорю, с, мы не хотим этого в этом случае). Да, все тестовые аудиофайлы были в каталоге / Resources / Audio / BGM.

Другой сайт что-то сказал о добавлении в начало файла [RequireComponent (typeof (AudioClip))] или [RequireComponent (typeof (AudioSource))]], но это ничего не сделало.

Наконец, эта программа в конечном итоге будет передана группе, которая не будет иметь доступа к источнику, поэтому они ДОЛЖНЫ иметь возможность поменять аудио-файл, сбросив любой .mp3 в разделе Ресурсы / Аудио / BGM для автоматического воспроизведения.

Любая помощь Добро пожаловать, спасибо!

1 Ответ

1 голос
/ 31 января 2020

Сначала общее примечание: Никогда используйте + "/" для путей к системным файлам! Скорее всего, иск 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. Это плохо ^^

    В их Рекомендации по работе с Resources папкой Unity сами рекомендуют

    Не используйте!


Однако

Поскольку вообще не рекомендуется использовать Resources Я бы лучше порекомендовал:

Если вы не хотите измените их позже

Вы не можете изменить Resources впоследствии, например, для замены файла. Так что если вы все равно не можете изменить файлы позже, то почему бы не обратиться непосредственно к ним в тех местах, где они нужны позже?

Просто поместите ваши аудиофайлы в папку, которая не Resources и ссылки на них в ваших сценариях непосредственно там, где они вам нужны:

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

Если вы хотите изменить их позже

В случае, если вы действительно хотите иметь возможность заменить их позже также после сборки вы можете вместо этого использовать UnityWebRequestMultimedia.GetAudioClip, который также может использоваться для загрузки файлов из системного файла во время выполнения. Для этого вы бы не поместили свои файлы в Resources или любую другую папку, а вместо этого StreamingAssets или Application.persistentDataPath.

Я обычно go:

  • В редакторе используйте папку 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 также является специальной папкой, в которой вы можете хранить файлы, которые хотите прочитать во время выполнения. Это местный . Также эта папка не «видна» извне и не может быть изменена позже.

Если вам нужно будет позже что-то изменить (например, сохранить файлы), вам всегда нужно будет использовать Application.persistentDataPath.

...