Homebound / Scripts / MainMenu.cs
MainMenu.cs
Raw
using TMPro;
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class MainMenu : MonoBehaviour
{
    public static bool IsPaused;                        // Static indicator for if the game should pause due to the main menu opening

    [Header("Canvas Attributes")]
    [SerializeField] Canvas menuCanvas;                 // Reference to the primary menu canvas
    [SerializeField] Canvas optionsCanvas;              // Reference to the secondary options canvas

    [Header("Options Canvas Attributes")]
    [SerializeField] TextMeshProUGUI musicTextField;    // Reference for the text field that changes between specific level types 
    [SerializeField] RectTransform contentRect;         // Reference for the content rectangle that the music buttons will be located in
    [SerializeField] GameObject musicButtonPrefab;      // Refernece for the music button prefab used in the music selection part of the options screen
    [SerializeField] Slider volumeSlider;               // Reference to the volume slider for the player volume preferences
    [SerializeField] Toggle loopingToggle;              // Reference to the looping toggle value

    AudioManager musicManager;                          // Reference to the current scene's audio manager
    int currentIndex;

    void Awake()
    {
        // Checks if player prefs are available
        if (!PlayerPrefs.HasKey("Volume")) PlayerPrefs.SetFloat("Volume", .7f);     // Volume aspect is set to around 70 percent
        if (!PlayerPrefs.HasKey("Looping")) PlayerPrefs.SetInt("Looping", 0);       // 0 to false for the looping aspect
    }

    void Start()
    {
        musicManager = AudioManager.Instance;
        InitiatePlayerPreferences();

        if (musicManager.GetLevelMusic().Equals(string.Empty))  // If the scene does not have a specific level name simply return { Guard Clause }
            return; 
        else                                                    // Sets the music text field for the options screen upon game start
            musicTextField.text = musicManager.GetLevelMusic();

        // Indicates the name of each music option available for the level
        string[] nameList = ShowMusicList();

        // Instantiate enough buttons to create a list of various music selections for the user to choose
        foreach (string name in nameList)
        {
            GameObject reference = Instantiate(musicButtonPrefab, contentRect);

            reference.GetComponentInChildren<TextMeshProUGUI>().text = name;
            reference.GetComponent<Button>().onClick.AddListener(() => ChangeMusic(name));
        }
    }

    void RefreshMusicList()
    {
        musicTextField.text = musicManager.GetLevelMusic();
        string[] nameList = ShowMusicList();
        foreach (Transform trans in contentRect)
        {
            Destroy(trans.gameObject);
        }
        foreach (string name in nameList) 
        {
            GameObject reference = Instantiate(musicButtonPrefab, contentRect);

            reference.GetComponentInChildren<TextMeshProUGUI>().text = name;
            reference.GetComponent<Button>().onClick.AddListener(() => ChangeMusic(name));
        }
    }

    /// <summary>
    /// Initiates the volume and looping preferences for the player's music 
    /// </summary>
    void InitiatePlayerPreferences()
    {
        // Initiates the player preferences for the player such as volume and looping
        musicManager.SetVolume(PlayerPrefs.GetFloat("Volume"));
        volumeSlider.value = PlayerPrefs.GetFloat("Volume");

        // Checks if the player pref for looping the selected music is enabled and if so to set the loop, otherwise set it to false
        if (PlayerPrefs.GetInt("Looping") == 0)
        {
            SetMusicLoop(false);
            loopingToggle.isOn = false;
        }
        else
        {
            SetMusicLoop(true);
            loopingToggle.isOn = true;
        }
    }

    void Update()
    {
        CheckLevelIndex();

        if (Input.GetKeyDown(KeyCode.Escape) && SceneManager.GetActiveScene().buildIndex != 0)
        {
            IsPaused = !IsPaused;   // The static variable for if the other objects in the scene should be paused is switched to the opposite of the current value of the variable

            if (IsPaused) 
                PauseGame();        // Pause
            else          
                UnpauseGame();      // Unpause
        }
    }

    void CheckLevelIndex()
    {
        if (musicManager.GetLevelIndex() != currentIndex)
        {
            currentIndex = musicManager.GetLevelIndex();
            RefreshMusicList();
        }
    }

    /// <summary>
    /// Freezes the time scale as well as opens the main menu while playing
    /// </summary>
    void PauseGame()
    {
        Time.timeScale = 0f;
        menuCanvas.enabled = true;
    }

    /// <summary>
    /// Unfreezes the time scale as well as closes the menu while playing. Made public for accessibility with the close button on the canvas
    /// </summary>
    public void UnpauseGame()
    {
        Time.timeScale = 1f;
        menuCanvas.enabled = false;
        optionsCanvas.enabled = false;

        if (IsPaused) IsPaused = false; // For the exit button at the top of the menu being used
    }

    /// <summary>
    /// Loads the Title Screen
    /// </summary>
    public void GoToTitleScreen() => SceneManager.LoadScene("MainMenu");

    /// <summary>
    /// Quit the application
    /// </summary>
    public void ExitGame() => Application.Quit();

    /// <summary>
    /// Sets the player prefs volume for the user's system
    /// </summary>
    /// <param name="volume">Float parameter based on the slider in the options menu</param>
    public void ChangeVolume(float volume)
    {
        PlayerPrefs.SetFloat("Volume", volume);
        musicManager.SetVolume(volume);
    }

    /// <summary>
    /// Creates a list of names based on the audio clips in the current scene
    /// </summary>
    /// <returns>String list of the current names of the audio clips in the scene</returns>
    /// <exception cref="IndexOutOfRangeException">The value of the parameter gathered from the level type retrieval prompted a strange behaviour</exception>
    public string[] ShowMusicList()
    {
        int int_Parameter = musicManager.GetLevelType();

        if (int_Parameter == 0)         // Menu Music
            return GenerateMusicList(3);
        else if (int_Parameter == 1)    // Jungle Music
            return GenerateMusicList(3);
        
        throw new IndexOutOfRangeException("Unexpected int_Parameter value in ShowMusicList. int_Parameter = " + int_Parameter);
    }

    /// <summary>
    /// Expect a list of names based on the parameter passed from the audio manager audioclips list
    /// </summary>
    /// <param name="numberOfNames">Number of names to be expected</param>
    /// <returns>List of audioclip names from the current scene audioclip list</returns>
    /// <exception cref="Exception">Out-Of-Range Exception</exception>
    string[] GenerateMusicList(int numberOfNames)
    {
        string[] musicList = new string[numberOfNames];

        try // Take each value in the list of audio clips from the audio manager and create a list of names from the manager
        {
            for (int i = 0; i < numberOfNames; i++)
                musicList[i] = musicManager.GetAttachedMusicNameAtPoint(i);
        }
        catch (Exception e)
        {
            throw new Exception("Number of names expected is out of range of what is available in the AudioManager. numberOfNames = " + numberOfNames, e);
        }

        return musicList;
    }

    /// <summary>
    /// The music changes to the audio clip based on the name passed through the function
    /// </summary>
    /// <param name="audioClipName">Name of the Audio Clip that is being called</param>
    public void ChangeMusic(string audioClipName) => musicManager.SetMusic(audioClipName);

    /// <summary>
    /// The music loops depending on the state parameter passed
    /// </summary>
    /// <param name="state">Sets if the music is looping or is not looping</param>
    public void SetMusicLoop(bool state)
    {
        musicManager.SetIsLooping(state);

        if (state) 
            PlayerPrefs.SetInt("Looping", 1);
        else 
            PlayerPrefs.SetInt("Looping", 0);
    }
}