Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

List, sorting audio sources

Discussion in 'Scripting' started by Griffo, Apr 1, 2021.

  1. Griffo

    Griffo

    Joined:
    Jul 5, 2011
    Posts:
    700
    Hi, below is script I've written to populate a list of enemy audio sources that are on automatic weapons, then if they are playing put them into another list and sort them by distance to the player so only have the closest xx play so not to sound horrible, what I'd like to know is this code ok or its it a expensive overhead ? Thanks.

    Code (CSharp):
    1. [Header("found when the scene is loaded")]
    2. [SerializeField] public Transform m_Cam;
    3.  
    4. [Header("maximum sound sources to play at once")]
    5. public int _maxWeaponSoundsources;
    6. public int _maxFootstepsSoundsources;
    7.  
    8. [Header("colours")]
    9. public Color _redColor;
    10. public Color _greenColor;
    11. public Color _whiteColor;
    12.  
    13. [Header("List of AudioSource's")]
    14. [SerializeField] public List<AudioSource> _audioSources = new List<AudioSource>();
    15.  
    16. [Header("List of automaitic weapon sound effects playing at the same time")]
    17. [SerializeField] public List<AudioSource> _automaticWeaponAudioSources = new List<AudioSource>();
    18.  
    19. [Header("List of footstep sound effects playing at the same time")]
    20. [SerializeField] public List<AudioSource> _footStepAudioSources = new List<AudioSource>();
    21.  
    22. private int MaxWeaponSoundsources;
    23.  
    24. // -----------------------------------------------------------------
    25. // Name :   OnEnable
    26. // Desc :  
    27. // -----------------------------------------------------------------
    28. private void OnEnable()
    29. {
    30.     MaxWeaponSoundsources       = _maxWeaponSoundsources - 1;
    31.  
    32.     if (GameObject.Find("AR Camera") != null)
    33.     {
    34.         m_Cam = GameObject.Find("AR Camera").GetComponent<Transform>();
    35.         return;
    36.     }
    37.  
    38.     if (GameObject.Find("Temp Camera") != null)
    39.         m_Cam = GameObject.Find("Temp Camera").GetComponent<Transform>();
    40.     else if (GameObject.Find("UI Camera") != null)
    41.         m_Cam = GameObject.Find("UI Camera").GetComponent<Transform>();
    42. }
    43.  
    44. // -----------------------------------------------------------------
    45. // Name :   Update
    46. // Desc :  
    47. // -----------------------------------------------------------------
    48. private void Update()
    49. {
    50.  
    51.     if (AudioManager.instance == null)
    52.         return;
    53.  
    54.     if (_audioSources.Count < MaxWeaponSoundsources)
    55.         return;
    56.  
    57.     if (_automaticWeaponAudioSources.Count > MaxWeaponSoundsources)
    58.         _automaticWeaponAudioSources.Sort(ByDistance);
    59.  
    60.     if (_audioSources.Count > MaxWeaponSoundsources)
    61.     {
    62.         for (int i = 0; i < _audioSources.Count; i++)
    63.         {
    64.             if (!_audioSources[i].isPlaying)
    65.                 _audioSources[i].gameObject.GetComponent<Renderer>().material.color = _whiteColor;
    66.  
    67.             if (_audioSources[i].isPlaying)
    68.             {
    69.                 if (!_automaticWeaponAudioSources.Contains(_audioSources[i]))
    70.                     _automaticWeaponAudioSources.Add(_audioSources[i]);
    71.  
    72.                 for (int l = 0; l < _automaticWeaponAudioSources.Count; l++)
    73.                 {
    74.                     _automaticWeaponAudioSources[l].gameObject.GetComponent<Renderer>().material.color = _greenColor;
    75.  
    76.                     if (l > MaxWeaponSoundsources)
    77.                     {
    78.                         // MUTE the sound source so the weapon can NOT be heard
    79.                         _automaticWeaponAudioSources[l].mute = true;
    80.                         _automaticWeaponAudioSources[l].gameObject.GetComponent<Renderer>().material.color = _redColor;
    81.                     }
    82.                     else
    83.                     {
    84.                         // DONT mute the sound source so the weapon CAN be heard
    85.                         _automaticWeaponAudioSources[l].mute = false;
    86.                         _automaticWeaponAudioSources[l].gameObject.GetComponent<Renderer>().material.color = _greenColor;
    87.                     }
    88.  
    89.                     // this MUST be done last in this for() loop, if NOT 'isPlaying' anymore remove from list
    90.                     if (!_automaticWeaponAudioSources[l].isPlaying)
    91.                     {
    92.                         _automaticWeaponAudioSources[l].mute = false;
    93.                         _automaticWeaponAudioSources.Remove(_automaticWeaponAudioSources[l]);
    94.                     }
    95.                 }
    96.             }
    97.         }
    98.     }
    99. }
    100.  
    101. // -----------------------------------------------------------------
    102. // Name :   ByDistance
    103. // Desc :  
    104. // -----------------------------------------------------------------
    105. private int ByDistance(AudioSource a, AudioSource b)
    106. {
    107.     if (GameSceneManager.instance.player == null)
    108.         return 0;
    109.  
    110.     float dstToA = Vector3.Distance(GameSceneManager.instance.player.position, a.transform.position);
    111.     float dstToB = Vector3.Distance(GameSceneManager.instance.player.position, b.transform.position);
    112.  
    113.     return dstToA.CompareTo(dstToB);
    114. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Go to Window -> Analysis -> Profiler and check for yourself. Remember, readings in the editor have nothing to do with how it will perform on actual hardware (eg, a PC or iOS or Android or XBox or whatever). Always test on the target hardware if you are concerned.

    https://docs.unity3d.com/Manual/Profiler.html
     
    Griffo likes this.
  3. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    One thing that I notice is that you are looping forwards through a list, and you are potentially removing elements from that list while you loop through it.

    What removing an element will do, is it will change the indexes of every element lower down on the list, and you will skip elements in your list when you try to fetch the next element.

    Code (CSharp):
    1.  
    2. public class TestListLoop : MonoBehaviour
    3. {
    4.     private List<int> nums = new List<int>();
    5.    
    6.     void Start()
    7.     {
    8.         //Adds 0,1,2,3,4 to a list
    9.         for (int x = 0; x < 5; x++)
    10.         {
    11.             nums.Add(x);
    12.         }
    13.  
    14.         //prints 0,2,4 from the list
    15.         for (int n = 0; n < nums.Count; n++)
    16.         {
    17.             Debug.Log(nums[n]);
    18.             nums.Remove(n);
    19.         }
    20.     }
    21. }
    22.  
    You can remove the current element from your list while looping backwards without changing the indexes of the elements that you haven't looped yet.

    Code (CSharp):
    1.         //prints 4,3,2,1,0 from the list
    2.         for (int n = nums.Count-1; n >= 0; n--)
    3.         {
    4.             Debug.Log(nums[n]);
    5.             nums.Remove(n);
    6.         }
    But it is considered bad practice to remove elements from a collection while you are looping through it, regardless of how you do it.
     
    Griffo likes this.
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Looping backwards probably has better performance, but I generally just make a copy of the collection and loop over the copy while modifying the original. List.ToArray() is pretty handy for this.
     
    Griffo and Kurt-Dekker like this.
  5. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    I'm curious why you're using a main list as opposed to having the enemies just monitor their distance to the player and mute/unmute accordingly? Both ways can work, just wondering.

    Having a lot play at once can cause clipping, so volume is a factor. If it becomes an issue, you could track how many are playing at a time and adjust accordingly. Also you'll want to try careful listening on mobile devices and possibly tweak their DSP settings if you get audio dropouts caused by too many sounds playing at once. I ran into this with a note-based app I've been working on, and making the sounds shorter and tweaking Android's DSP settings helped a lot---though the buffer size tweak was in the opposite direction I expected...making it *smaller* caused less dropouts, and the reverse was true for PC (?).

    Also you can use PlayOneShot(), I seem to remember it's better for lots of sounds at once, maybe someone can speak to that.
     
    Last edited: Apr 2, 2021
    Griffo and Kurt-Dekker like this.
  6. Griffo

    Griffo

    Joined:
    Jul 5, 2011
    Posts:
    700
    Hi, thanks for the reply, you say 'having the enemies just monitor their distance to the player and mute/unmute accordingly' wouldn't this also need a List/Array for the enemy to loop through to see if they are one of the closest xx in the List/Array, I'll look into the DSP settings, cheers.
     
    seejayjames likes this.
  7. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    You'd need a list to see if they were the closest, but I thought it was more based on absolute distance, so that would just be each enemy individually. Not sure how you want it set up exactly though. As always, several ways to do things, pros and cons to each...

    I only tweaked the DSP buffer size and the number of voices (as there were a lot of overlapping sounds). It did make a noticeable difference on Android at least. YMMV ;)
    https://docs.unity3d.com/Manual/class-AudioManager.html
     
    Griffo likes this.