Search Unity

[ SOLVED ] How to add a dynamic float to a slider's OnValueChanged on Runtime?

Discussion in 'UGUI & TextMesh Pro' started by WiktorS, Nov 21, 2014.

  1. WiktorS

    WiktorS

    Joined:
    Nov 21, 2014
    Posts:
    3
    Hello everyone :)
    I have a problem with the new UI. In my Main Menu scene I have a Slider and an "AudioInstantiatior" GameObject, which instantiates a gameObject contatining AudioSource and makes it DontDestroyOnLoad() so the AudioSource's music can be looped between scenes and doesn't duplicate itself each time I enter Main Menu.

    And the problem is: how to add the AudioSource's GameObject to Slider's OnValueChanged event and select the dynamic float volume during runtime (by a C# script)? Normally, it's done in the editor, but I can't find how to do that during gameplay with an instantiated game object.

    Technicly, I could read the slider's value via another script, find the instantiated AudioSource and update its volume with the slider's value, but somehow I don't find this a "clean & elegant" way to do that and I'm convinced there must be a solution to do this "properly" via events just like in the Inspector.

    I did a lot of research before posting here and I've found, that there is a possibility to enter the EventTrigger component during runtime and add a function call to an UI object, but sadly the slider's OnValueChanged is in the Slider component, not in the EventTrigger and in that method I can only add a function name, I can not give the float volume, so back to square one. (Or I'm to weak programmer to understand how that code works:confused:)

    Does anybody have any ideas? I will be very grateful for every help, suggestions or clues.
    Thank you in advance to all involved helpers:). Best regards,
    W.
     
  2. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,261
    Create a script in the slider object that hooks into the OnValueChanged event(setting it in the editor.) This script would then do a GameObject.Find("AudioInstantiatior"); to get access to the audio and change the values via that.

    As an example
    Code (CSharp):
    1. GameObject audioObject;
    2. AudioSource audioSource;
    3. Slider slider;
    4.  
    5. void Start()
    6. {
    7.      audioObject = GameObject.Find("AudioInstantiatior");
    8.      audioSource = audioObject.GetComponent<AudioSource>();
    9.      slider = GetComponent<Slider>();
    10. }
    11.  
    12. public void UpdateAudio()
    13. {
    14.      audioSource.volume = slider.value;//if its 0.0-1.0;
    15. }
    16.  
    The second function you would set via the slider values in the editor in the events section.
     
  3. WiktorS

    WiktorS

    Joined:
    Nov 21, 2014
    Posts:
    3
    Chris Trueman - thanks for your reply; I know this way of getting workaround the problem, I've wrote it in my first post. The question was more likely how to do this via Events if it's possible. If not, I'll just stick to your solution :)
     
  4. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    Doesn't seem to be possible, frankly.
     
  5. WiktorS

    WiktorS

    Joined:
    Nov 21, 2014
    Posts:
    3
    Daniel_ - it is possible and most important - I've finally done it.;)

    Solving this issue was so simple, I'm ashamed of myself I didn't get it earlier:oops:
    I found a solution to a very similar problem in this topic and that's basicly what did the job. Here's my code:

    Code (CSharp):
    1. public class InstantiateAudio : MonoBehaviour {
    2.  
    3.   private   GameObject  musicCube;   // My object with AudioSource attached
    4.   public    Slider      musicSlider; // Slider added in Editor
    5.  
    6.   void Awake() {
    7.     if(GameObject.Find("_Music Box(Clone)") == null) {
    8.       musicCube = Instantiate(Resources.Load("Prefabs/MainMenu/_Music Box")) as GameObject;
    9.     }
    10.     // ... And the solution itself :)
    11.     musicSlider.onValueChanged.AddListener(delegate {
    12.       musicCube.GetComponent<AudioSource>().volume = musicSlider.value;
    13.     });
    14.   }
    15. } // EOF
    So, another problem solved, another day saved and another topic to close with success. :)
    Thanks to everybody involved in helping. :)
     
  6. User340

    User340

    Joined:
    Feb 28, 2007
    Posts:
    3,001
    Not so fast :) Not everything is correct
    The documentation is wrong, it doesn't state there to be an AddListener event, see:
    file:///Applications/Unity/Unity.app/Contents/Documentation/html/en/ScriptReference/UI.Slider.SliderEvent.html
     
  7. Caio_Lib

    Caio_Lib

    Joined:
    Mar 4, 2014
    Posts:
    83
    Another way to solve:

    Code (CSharp):
    1. public Slider slider;
    2. private GameObject audioObject;
    3. private AudioSource audioSource;
    4.  
    5. void Awake()
    6. {
    7.     audioObject = GameObject.Find("AudioInstantiatior");
    8.     audioSource = audioObject.GetComponent<AudioSource>();
    9.     slider.onValueChanged.AddListener((value) => { audioSource.volume = value; });
    10. }
    Daniel, you're right. AddListener is in documentation but only for UnityEvent without arguments:
    file:///Applications/Unity/Editor/Data/Documentation/html/en/ScriptReference/Events.UnityEvent.html
     
    WiktorS, User340 and adhdchris like this.
  8. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    here's a handy example. say you have many UI sliders (perhaps in a panel)

    for each of the sliders, have a Text underneath it that is a label for the slider ("Speed" "Angle" etc.)

    this code, with no further effort, makes each slider automatically change that text, when, you change the slider at runtime.

    Code (CSharp):
    1.         foreach (Slider sd in sds)
    2.             {
    3.             Transform thatLabel = sd.transform.Find("label");
    4.             if ( thatLabel != null )
    5.                 {
    6.                 Text tt= thatLabel.GetComponent<Text>();
    7.                 string baseText = tt.text;
    8.                 sd.onValueChanged.AddListener(
    9.                     (value) => { tt.text = baseText + " " + value; }
    10.                     );
    11.                 }
    12.             }
     
    DDeathlonger likes this.
  9. DDeathlonger

    DDeathlonger

    Joined:
    May 9, 2014
    Posts:
    73
    Awesome fix man. although the default, at least via Unity 2017.x.x is not a label called "label" it'd be a "label" called "Text" XD lol Thanks!

    Also, Hello from the future..... 2018!