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

Resolved Trying to Play Random Sound from an Array

Discussion in 'Scripting' started by scarletseer5, Oct 21, 2020.

  1. scarletseer5

    scarletseer5

    Joined:
    Oct 21, 2020
    Posts:
    3
    Hi, everyone! I'm sort of new to Unity, but I'm basically trying to make an asset bundle with elements that play a random sound once the element is triggered. The goal is to load it in Tabletop Simulator alongside lua code that generates a button for the element, and triggers a random sound when that button is clicked on.

    I found this tutorial and followed it to the letter: https://andrewmushel.com/articles/sound-effect-variation-in-unity/

    After applying it, my code has no errors and I am able to assign an array of sound effects to a single element that all have the same duration. However, even though the elements do appear in-game, nothing happens when I trigger them. From my understanding, this code assigns an array to an empty audio source, and ensures that the trigger will choose a random integer from the array to play a sound, while avoiding repetition so it doesn't choose the same sound twice from the same array.

    If anyone has any insights on what I could tweak, I'd greatly appreciate it! :)

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System;
    6. using Random=UnityEngine.Random;
    7. public class TTSAssetBundleEffects : MonoBehaviour
    8. {
    9.     [Serializable]
    10.     public class TTSSound
    11.     {
    12.         public AudioSource effectSource;
    13.         public AudioClip[] clipArray;
    14.         private int clipIndex;
    15.         public bool Positional3D = true;
    16.         public TTSSound()
    17.         {
    18.             Positional3D = true;
    19.         }
    20.     void PlayRoundRobin() {
    21.         if (clipIndex < clipArray.Length)
    22.         {
    23.             effectSource.PlayOneShot(clipArray[clipIndex]);
    24.             clipIndex++;
    25.         }
    26.         else
    27.         {
    28.             clipIndex = 0;
    29.             effectSource.PlayOneShot(clipArray[clipIndex]);
    30.             clipIndex++;
    31.         }
    32.     }
    33.     void PlayRandom()
    34.     {
    35.     clipIndex = Random.Range(0, clipArray.Length);
    36.     effectSource.PlayOneShot(clipArray[clipIndex]);
    37.     }
    38.     int RepeatCheck(int previousIndex, int range)
    39.     {
    40.         int index = Random.Range(0, range);
    41.         while (index == previousIndex)
    42.         {
    43.             index = Random.Range(0, range);
    44.         }
    45.         return index;
    46.     }
    47.     void PlayRandom2()
    48.     {
    49.         clipIndex = RepeatCheck(clipIndex, clipArray.Length);
    50.         effectSource.PlayOneShot(clipArray[clipIndex]);
    51.     }
    52. void Update ()
    53. {
    54.     if (Input.GetButtonUp("Fire1")) PlayRoundRobin();
    55.     if (Input.GetButtonUp("Fire2")) PlayRandom2();
    56. }
    57.     }
    58. [Serializable]
    59.     public class TTSEffect
    60.     {
    61.         public string Name;
    62.         public TTSSound Sound;
    63.     }
    64.     [Serializable]
    65.     public class TTSTriggerEffect : TTSEffect
    66.     {
    67.         public float Duration = 1f;
    68.     }
    69.     public List<TTSTriggerEffect> TriggerEffects = new List<TTSTriggerEffect>() { new TTSTriggerEffect() };  
    70. }
    71.  
     
    Last edited: Oct 21, 2020
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I don't see anything obvious from a quick look. Are you sure the various Play methods are even getting called on the correct instance of the component? Are you sure that the audio listener is within range of the audio source? (since it looks like you're using 3D audio, the position of both source and listener are critical)

    One note though, you say this is for an asset bundle, but asset bundles can't contain C# scripts. Those all have to go in the original build, and I don't believe Tabletop Simulator has shared their original project for you to make your own builds.
     
  3. scarletseer5

    scarletseer5

    Joined:
    Oct 21, 2020
    Posts:
    3
    Thank you for getting back to me so quickly!

    So, Tabletop Simulator's original project was shared with the public, and I retooled it a bit to remove the excess code so it would apply the above script instead: https://github.com/Berserk-Games/Tabletop-Simulator-Modding

    But you raise a great point that the tutorial I followed seem to have only a single element with an array, whereas I have set up several triggerable elements, each with their own array. It's probable that it doesn't know which array goes to which element.

    But if asset bundles can't contain C# scripts, then what do you think might be a feasible way to go about setting up multiple elements, each with one separate array, that trigger a random sound when the trigger element is selected?

    Also, I'm trying to test the script in Unity with this part of the code, as the tutorial suggests:
    Code (CSharp):
    1. void Update ()
    2. {
    3.     if (Input.GetButtonUp("Fire1")) PlayRoundRobin();
    4.     if (Input.GetButtonUp("Fire2")) PlayRandom2();
    5. }
    6.  
    7.     }
    But I'm pressing the keybind for Fire1 (left ctrl) and Fire2 (left alt) and nothing is happening. Do I need to be in a specific mode or window in order to press these buttons and activate the script?
     
    Last edited: Oct 21, 2020
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,514
    Make a ScriptableObject that has an array of clips in it, and drag the clips into it, then you can make an asset bundle out of just the ScriptableObject and the sounds referenced will automatically be included (by dependency) in the bundle.

    I do this with all my "collections" of like-things, such as my GameObjectCollection class, which I include here for grins. This one looks like I even made a custom editor for it, right inside the class file. Actually this one looks like it implements indexing direclty, plus it also implements shuffling and randomizing:

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. #if UNITY_EDITOR
    5. using UnityEditor;
    6. #endif
    7.  
    8. // @kurtdekker - part of Jetpack Kurt Space Flight
    9.  
    10. [CreateAssetMenu(menuName = "Collections/GameObjectCollection")]
    11. public class GameObjectCollection : ScriptableObject
    12. {
    13.     public string Description;
    14.  
    15.     public GameObject[] GameObjects;
    16.  
    17.     public GameObject this[int index]
    18.     {
    19.         get
    20.         {
    21.             return GameObjects[index];
    22.         }
    23.         set
    24.         {
    25.             GameObjects[index] = value;
    26.         }
    27.     }
    28.  
    29.     public    float    MasterScaling = 1.0f;
    30.  
    31.     public void InstantiateAll( Transform parent = null)
    32.     {
    33.         foreach( var go in GameObjects)
    34.         {
    35.             GameObject go2 = Instantiate<GameObject>( go);
    36.             go2.transform.SetParent( parent);
    37.         }
    38.     }
    39.  
    40.     public GameObject PickRandom()
    41.     {
    42.         return GameObjects[ Random.Range ( 0, GameObjects.Length)];
    43.     }
    44.  
    45.     int DeckPointer;
    46.     GameObject[] GameObjectDeck;
    47.  
    48.     void TryShuffle()
    49.     {
    50.         if (GameObjectDeck == null ||
    51.            (GameObjectDeck.Length != GameObjects.Length) ||
    52.            DeckPointer >= GameObjectDeck.Length)
    53.         {
    54.             DeckPointer = 0;
    55.  
    56.             GameObjectDeck = new GameObject[ GameObjects.Length];
    57.  
    58.             for (int i = 0; i < GameObjects.Length; i++)
    59.             {
    60.                 GameObjectDeck[i] = GameObjects[i];
    61.             }
    62.  
    63.             for (int i = 0; i < GameObjectDeck.Length - 1; i++)
    64.             {
    65.                 int j = Random.Range ( i, GameObjectDeck.Length);
    66.  
    67.                 var t = GameObjectDeck[i];
    68.                 GameObjectDeck[i] = GameObjectDeck[j];
    69.                 GameObjectDeck[j] = t;
    70.             }
    71.         }
    72.     }
    73.  
    74.     public GameObject PickNextShuffled()
    75.     {
    76.         TryShuffle ();
    77.  
    78.         GameObject result = GameObjectDeck [DeckPointer];
    79.  
    80.         DeckPointer++;
    81.  
    82.         return result;
    83.     }
    84.  
    85.     public int Length
    86.     {
    87.         get
    88.         {
    89.             if (GameObjects == null)
    90.             {
    91.                 return 0;
    92.             }
    93.             return GameObjects.Length;
    94.         }
    95.     }
    96.  
    97.     public int ConstrainIndex( int index, bool wrap = false)
    98.     {
    99.         if (GameObjects.Length < 1)
    100.         {
    101.             throw new System.IndexOutOfRangeException("GameObjectCollection.ConstrainIndex(): no GameObjects in " + name);
    102.         }
    103.  
    104.         if (index < 0) return 0;
    105.         if (index >= GameObjects.Length)
    106.         {
    107.             if (wrap)
    108.             {
    109.                 index = 0;
    110.             }
    111.             else
    112.             {
    113.                 index = GameObjects.Length - 1;
    114.             }
    115.         }
    116.         return index;
    117.     }
    118. }
    119.  
    120. #if UNITY_EDITOR
    121. [CustomEditor(typeof(GameObjectCollection))]
    122. public class GameObjectCollectionInspector : Editor
    123. {
    124.     Transform parent;
    125.  
    126.     void MakeContents()
    127.     {
    128.         GameObjectCollection goc = (GameObjectCollection)this.target;
    129.  
    130.         parent = new GameObject( "GOC:" + goc.name).transform;
    131.  
    132.         float spacing = 5.0f;
    133.         if (goc.MasterScaling >= 1.5f)
    134.         {
    135.             spacing = goc.MasterScaling * 1.1f;
    136.         }
    137.  
    138.         for (int i = 0; i < goc.GameObjects.Length; i++)
    139.         {
    140.             var go = goc.GameObjects[i];
    141.  
    142.             if (go)
    143.             {
    144.                 var go2 = (GameObject)PrefabUtility.InstantiatePrefab(go);
    145.                 if (go2)
    146.                 {
    147.                     go2.transform.SetParent( parent);
    148.  
    149.                     go2.transform.localScale = Vector3.one * goc.MasterScaling;
    150.  
    151.                     Vector3 pos = Vector3.right * (i - (goc.GameObjects.Length - 1) * 0.5f) * spacing;
    152.                     go2.transform.localPosition = pos;
    153.                 }
    154.             }
    155.         }
    156.     }
    157.  
    158.     public override void OnInspectorGUI()
    159.     {
    160.         this.DrawDefaultInspector ();
    161.  
    162.         GUILayout.Space (25);
    163.  
    164.         GUILayout.BeginHorizontal();
    165.         if (parent)
    166.         {
    167.             GUI.color = new Color( 1.0f, 0.5f, 0.5f);
    168.             if(GUILayout.Button("Clear Instantiated Prefabs"))
    169.             {
    170.                 DestroyImmediate( parent.gameObject);
    171.                 parent = null;
    172.             }
    173.         }
    174.         else
    175.         {
    176.             GUI.color = new Color( 0.5f, 1.0f, 0.5f);
    177.             if(GUILayout.Button("Instantiate Prefabs Above"))
    178.             {
    179.                 MakeContents();
    180.             }
    181.         }
    182.         GUILayout.EndHorizontal();
    183.     }
    184. }
    185. #endif
     
  5. scarletseer5

    scarletseer5

    Joined:
    Oct 21, 2020
    Posts:
    3
    That was incredibly informative, and thank you so much for all of your help.

    I consulted with a friend who also knows a little about Unity, and it turns out that Joe-Censored was right on the money; Tabletop Simulator was not going to play nice with my Unity code.

    So we decided to just set up the audio source in Unity to just play a sound when triggered, and then we handled the rest in lua on Tabletop Simulator by using the math.random function combined with ~= operators to hide specific buttons that were being called up in pairs as triggerable objects. The hidden elements at the end functioned as the range for math.random to use.

    Even though it was done in another program instead of Unity, I'm glad to mark this problem as solved! Thank you for everything! :D
     
    Joe-Censored likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,514
    @Joe-Censored does that a lot... he's a real credit to these forums.

    You're welcome! Thunder forward and onward now!
     
    Joe-Censored likes this.
  7. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'll lies, everyone knows I'm just knowledgeable enough to be dangerous. :p