Unity3D: Resource.Load, определенный AudioClip, заканчивает нулевым переходом в AudioSource

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

Вот что у меня есть на данный момент:

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 пуста. Об этом говорится в отладке, но если я добавлю вызов отладки для BGMSource.clip.name, он полностью выдаст ошибку с исключением 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 для автоматического воспроизведения.

Любая помощь приветствуется, спасибо!


person user2402654    schedule 30.01.2020    source источник
comment
Прежде всего, ресурсы нельзя заменить, если у вас нет доступа к источнику. Для этого я думаю, что вы ограничены StreamingAssets или просто любой относительной папкой, используя метод доступа streamingassets. Что, я думаю, происходит с веб-запросом. Вы также ограничены тем, какие типы аудио единство может загружать в сборку среды выполнения. Не все типы можно импортировать во время выполнения, как в редакторе. Поскольку весь код изменится для работы с потоковыми активами, сейчас бесполезно пытаться отлаживать это.   -  person Smileynator    schedule 31.01.2020
comment
Я быстро взглянул на потоковые ресурсы, я раньше не использовал их. Мне нужно больше времени, чтобы проверить это, но пока результат тот же. Не уверен, имеет ли это значение для потокового использования ресурсов, но эта программа, скорее всего, всегда будет отключена. Я бы подумал, что потоковая передача означает только онлайн, но сайт документации строго не говорит онлайн, так что посмотрим, смогу ли я что-нибудь сделать. Спасибо за совет!   -  person user2402654    schedule 31.01.2020
comment
Предлагаю вам прочитать документацию по потоковым ресурсам. Но в двух словах: активы обычно присутствуют в игре и на них жестко ссылается Unity, поэтому Unity знает, что делать. Ресурсы по-прежнему упакованы в игре, но в специальной zip-папке с собственной файловой структурой для доступа. И затем есть потоковые ресурсы, которые в основном просто переносят файл как есть в папку сборки. Вы используете UnityWebRequest для их получения, даже если это локальные файлы (но они не обязательно должны быть)   -  person Smileynator    schedule 31.01.2020


Ответы (1)


Сначала общее замечание: Никогда не используйте + "/" в качестве пути к системным файлам! Скорее подайте в суд на Path.Combine, который автоматически вставляет правильные разделители пути в соответствии с платформа, на которой он работает

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

Затем прочтите документацию по Resources.Load!

  1. Это требует, чтобы ваш файл (ы) был помещен в папку с именем Resources, которая скомпилирована в сборку приложения и, следовательно, не может быть изменена впоследствии. Кажется, это так для вас.

  2. Он не принимает полный системный путь, как вы передаете, поскольку _ 6_ возвращает

    Массив полных имен (включая пути) файлов в указанном каталоге.

    но скорее ожидает путь во всех 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. # P12 # # P13 #
    # P14 #

тем не мение

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

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

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

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

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

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

Если вы действительно хотите иметь возможность заменить их позже, также после сборки, вы можете вместо этого использовать _ 20_, который также можно использовать для загрузки файлов из системного файла во время выполнения. Для этого вы не будете помещать свои файлы в Resources или любую другую папку, а лучше либо в StreamingAssets, либо в _ 23_.

Я обычно иду:

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

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

person derHugo    schedule 31.01.2020
comment
Что ж, это было основательно, лол! Итак, хотя, как вы упомянули, Resoures.Load не собирается делать то, что мне нужно для этой цели, упомянутые вами корректировки стандартов абсолютно приветствуются, поскольку я использую те же варианты гетто для replace и + / в других в моей проге есть места, которые можно обновлять. Веб-бит, который я комично уже имел в своем коде раньше, но был разочарован строкой ошибок и выбросил его. Как и протокол, то, что я упустил, было простым, и ваш пример показывает, что я упустил. Большое спасибо! - person user2402654; 31.01.2020