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

How can I save Slider's to Player Pref's

Discussion in 'Scripting' started by CWadey, Oct 11, 2019.

  1. CWadey

    CWadey

    Joined:
    Apr 5, 2017
    Posts:
    6
    Im rather new to coding and im having trouble on the very last part of my game which saving the values of my voume sliders between scenes.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6.  
    7. public class ChangeVolumeLevels : MonoBehaviour
    8. {
    9.  
    10.     public Slider thisSlider;
    11.     public float musicVolume;
    12.     public float sfxVolume;
    13.  
    14.     public void SetSpecificVolume(string whatValue)
    15.     {
    16.         float sliderValue = thisSlider.value;
    17.  
    18.         if (whatValue == "Music")
    19.         {
    20.             musicVolume = thisSlider.value;
    21.             AkSoundEngine.SetRTPCValue("MusicVolume", musicVolume);
    22.         }
    23.  
    24.         if (whatValue == "SFX")
    25.         {
    26.             sfxVolume = thisSlider.value;
    27.             AkSoundEngine.SetRTPCValue("SFXVolume", sfxVolume);
    28.         }
    29.     }
    30. }
    31.  
    The actual volume itself changes between the scenes but the sliders reset to there defult position (60%). So if I turn the volume down to 0% in one scene in the next the volume will still be at 0% but the position of the slider in unity will be at 60%. I can only imagine I would save the values to player prefs but I have no idea how.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,521
    Generally you want a bidirectional hookup between the Slider and a floating point value, and then you back that value up to PlayerPrefs as you're doing now.

    In my Datasacks package I have that functionality in my DSUserIntentSlider.cs function. Here's a link directly to that file:

    https://github.com/kurtdekker/datas...s/Assets/Datasack/Input/DSUserIntentSlider.cs

    The timing is a bit fiddly, but with the Unity Order Of Execution documentation you can sorta trace the execution steps that synchronize the Slider to the .fValue of the Datasack:

    https://docs.unity3d.com/Manual/ExecutionOrder.html

    You can either use the entire Datasacks package too, as it supports flagging a Datasack as "Save" to make it go to player prefs, or else you can just replace the .fValue accesses in the above script with your own float that is stored to PlayerPrefs.

    Datasacks is presently hosted at these locations:

    https://bitbucket.org/kurtdekker/datasacks

    https://github.com/kurtdekker/datasacks

    https://gitlab.com/kurtdekker/datasacks
     
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    The very basic answer is: you need a script that sets your slider to the position you want it at when the slider is first initialized. You can adjust your slider through script by assigning to Slider.value.

    If you already have the actual volume set the way you want, you could probably just set the slider to the current volume in Awake.

    PlayerPrefs is normally used for saving data when your game exits and restarts. If some data only has to survive a scene transition and not a full exit, you would more typically store it in static variables or in objects marked DontDestroyOnLoad (using PlayerPrefs would still work, but it would have some extra overhead, and you might accidentally save it through an exit and restart even if you didn't mean to).

    I've got my project set up with a series of classes that allow a player preference (like volume) to be associated with a symbolic name, and for a slider to be automatically synchronized (both directions) with that pref based on the symbolic name. But a full working model involves about 5 inter-related classes and is probably too complicated to make a good learning example.
     
    CWadey likes this.
  4. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,966
    This. I'm currently using the following scripts. I have a component called GetPref which reads a value from PlayerPrefs when OnEnable() runs and fires an event. For audio volumes the event is hooked up to feed the value directly into the UI component's value.

    GetPref.cs:
    Code (csharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Events;
    6.  
    7. public class GetPref : MonoBehaviour
    8. {
    9.     [Serializable]
    10.     public class GetBoolEvent : UnityEvent<bool> {}
    11.  
    12.     [Serializable]
    13.     public class GetIntEvent : UnityEvent<int> {}
    14.  
    15.     [Serializable]
    16.     public class GetFloatEvent : UnityEvent<float> {}
    17.  
    18.     [Serializable]
    19.     public class GetStringEvent : UnityEvent<string> {}
    20.  
    21.     public enum PrefKeyType
    22.     {
    23.         Bool,
    24.         Int,
    25.         Float,
    26.         String
    27.     }
    28.  
    29.     public string prefKey;
    30.  
    31.     public PrefKeyType prefKeyType;
    32.  
    33.     public bool onEnable;
    34.  
    35.     public GetBoolEvent onGetBool = new GetBoolEvent();
    36.     public GetIntEvent onGetInt = new GetIntEvent();
    37.     public GetFloatEvent onGetFloat = new GetFloatEvent();
    38.     public GetStringEvent onGetString = new GetStringEvent();
    39.  
    40.     private void OnEnable()
    41.     {
    42.         if (onEnable && PlayerPrefs.HasKey(prefKey))
    43.         {
    44.             if (prefKeyType == PrefKeyType.Bool)
    45.             {
    46.                 if (PlayerPrefs.GetInt(prefKey) > 0)
    47.                     onGetBool.Invoke(true);
    48.                 else
    49.                     onGetBool.Invoke(false);
    50.             }
    51.             else if (prefKeyType == PrefKeyType.Int)
    52.             {
    53.                 onGetInt.Invoke(PlayerPrefs.GetInt(prefKey));
    54.             }
    55.             else if (prefKeyType == PrefKeyType.Float)
    56.             {
    57.                 onGetFloat.Invoke(PlayerPrefs.GetFloat(prefKey));
    58.             }
    59.             else if (prefKeyType == PrefKeyType.String)
    60.             {
    61.                 onGetString.Invoke(PlayerPrefs.GetString(prefKey));
    62.             }
    63.         }
    64.     }
    65. }
    GetPrefsEditor.cs:
    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. [CustomEditor(typeof(GetPref))]
    7. public class GetPrefEditor : Editor
    8. {
    9.     SerializedProperty prefKey;
    10.     SerializedProperty prefKeyType;
    11.  
    12.     SerializedProperty onEnable;
    13.  
    14.     SerializedProperty onGetBool;
    15.     SerializedProperty onGetInt;
    16.     SerializedProperty onGetFloat;
    17.     SerializedProperty onGetString;
    18.  
    19.     private void OnEnable()
    20.     {
    21.         prefKey = serializedObject.FindProperty("prefKey");
    22.         prefKeyType = serializedObject.FindProperty("prefKeyType");
    23.  
    24.         onEnable = serializedObject.FindProperty("onEnable");
    25.  
    26.         onGetBool = serializedObject.FindProperty("onGetBool");
    27.         onGetInt = serializedObject.FindProperty("onGetInt");
    28.         onGetFloat = serializedObject.FindProperty("onGetFloat");
    29.         onGetString = serializedObject.FindProperty("onGetString");
    30.     }
    31.  
    32.     public override void OnInspectorGUI()
    33.     {
    34.         serializedObject.Update();
    35.  
    36.         EditorGUILayout.PropertyField(prefKey);
    37.         EditorGUILayout.PropertyField(prefKeyType);
    38.  
    39.         EditorGUILayout.PropertyField(onEnable);
    40.  
    41.         GetPref.PrefKeyType pkt = (GetPref.PrefKeyType)prefKeyType.enumValueIndex;
    42.         if (pkt == GetPref.PrefKeyType.Bool)
    43.         {
    44.             EditorGUILayout.PropertyField(onGetBool);
    45.         }
    46.         else if (pkt == GetPref.PrefKeyType.Int)
    47.         {
    48.             EditorGUILayout.PropertyField(onGetInt);
    49.         }
    50.         else if (pkt == GetPref.PrefKeyType.Float)
    51.         {
    52.             EditorGUILayout.PropertyField(onGetFloat);
    53.         }
    54.         else if (pkt == GetPref.PrefKeyType.String)
    55.         {
    56.             EditorGUILayout.PropertyField(onGetString);
    57.         }
    58.  
    59.         serializedObject.ApplyModifiedProperties();
    60.     }
    61. }

    For saving the value I have the UI component's event hooked up to feed the current value into the relevant method on the following script.

    SetPref.cs:
    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SetPref : MonoBehaviour
    6. {
    7.     public string prefsKey;
    8.  
    9.     public void SetBoolValue(bool value) {
    10.         PlayerPrefs.SetInt(prefsKey, value ? 1 : 0);
    11.     }
    12.  
    13.     public void SetIntValue(int value) {
    14.         PlayerPrefs.SetInt(prefsKey, value);
    15.     }
    16.  
    17.     public void SetFloatValue(float value) {
    18.         PlayerPrefs.SetFloat(prefsKey, value);
    19.     }
    20.  
    21.     public void SetStringValue(string value) {
    22.         PlayerPrefs.SetString(prefsKey, value);
    23.     }
    24.  
    25. }
     
    Last edited: Oct 11, 2019
  5. CWadey

    CWadey

    Joined:
    Apr 5, 2017
    Posts:
    6
    Yeah this seems a better way of doing it but I honestly have no idea how to go about it. When I say new I mean like a few weeks so anymore help would be greatly appreciated!

    As far as code goes all I can think is that in the same script I could have on start some way of getting the infromation from the RTPC value to set the slider level but I honestly can't think how to do that!
     
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I don't know what AkSoundEngine is, but I see you are calling a function called SetRTPCValue. There's likely to be another function called GetRTPCValue. Check the documentation for AkSoundEngine (whatever that is).

    If you can't figure out a way to get the value from AkSoundEngine, you can instead remember the value somewhere else. Like I said above, you can store data across scenes by putting it in static variables or in an object marked DontDestroyOnLoad.

    Once you know the level that you want to set the slider to, you can write something along the lines of:

    Code (CSharp):
    1. void Awake()
    2. {
    3.     mySlider.value = whereEverYouWantTheSliderToStart;
    4. }