I have got song functionality/song selection working, and I have also concepted and created a death screen, as well as other small UI improvements.
Published on January 13, 2020 by Amy Elliott
C# Programming Unity User Interface Dev Blog College
12 min READ
Please note: The code and content within this blog post is not representative of my current skills.
I plan to get the death UI on my game completed, and polish up on my UI so it’s all complete, I then plan to make my song selection functional so it works in my game and uses any users songs. I also plan to get my UI all nice and animated! Which will mean I need to watch a few more videos on Unity Animation.
What did I do this week and why did I do it?
I began by looking at scripts which Ashley had done trying to get this to work, he got very close to getting this working but it just didn’t work in the end.
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
public class MusicSearch : MonoBehaviour
{
private DirectoryInfo directoryInfo;
private List<FileInfo> musicInfo;
private List<AudioClip> audioClips = new List<AudioClip>();
public GameObject buttonPrefab;
public RectTransform parentPanel;
public AudioSource audSource;
void Awake()
{
directoryInfo = new DirectoryInfo(Application.streamingAssetsPath);
musicInfo = new List<FileInfo>(directoryInfo.GetFiles("*.wav"));
if (musicInfo.Count > 0)
{
foreach (FileInfo song in musicInfo)
{
GameObject buttonGO = Instantiate(buttonPrefab);
buttonGO.transform.SetParent(parentPanel, false);
buttonGO.GetComponentInChildren<TextMeshProUGUI>().SetText(song.Name);
Button tmpButton = buttonGO.GetComponent<Button>();
WWW url = new WWW(string.Format("file://{0}", song.FullName.ToString()));
AudioClip tmpClip = url.GetAudioClip(false, false);
tmpClip.name = song.Name;
audioClips.Add(tmpClip);
print(tmpClip.name);
tmpButton.onClick.AddListener(() => SelectMusic(tmpClip));
}
}
else
{
print("No Music");
}
}
private void SelectMusic(AudioClip song)
{
audSource.clip = song;
audSource.Play();
}
}
This never worked because, you would click on the button where the music was and then an audio clip would go into the audio source, but it would be empty, and wouldn’t play anything, you click on the actual audio in the inspector and the music would play, it was quite a difficult problem, and I didn’t know what to do to fix it, so I took the problem to a friend to see if he had any idea, and he did know how to do this! So I asked him for help and he helped me write this script, explaining to me how everything works.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.UI;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
public class MusicSelect : MonoBehaviour
{
// For this script to work:
// I had to use the namespaces System.IO to access system files,
// UnityEngine.UI to access the UI components in Unity,
// UnityEngine.Networking to use the UnityWebRequest functionality for audio streaming,
// and UnityEngine.SceneManagement to change scenes.
private List<string> musicList;
public GameObject buttonPrefab;
public RectTransform parentPrefab;
public bool currentlyLoading;
public AudioClip audioClip;
IEnumerator LoadMusic(string fileName)
{
// This script uses www from MonoBehaviour and needs a private list of strings
// which we call musicList, which has nothing assigned to it since we assign it each time with our Awake function.
// It also has a public GameObject named buttonPrefab, which we use to instantiate the buttons for each song.
fileName = Path.GetFullPath(fileName);
// Using UnityWebRequestMultimedia to load an audio clip.
using (UnityWebRequest loader = UnityWebRequestMultimedia.GetAudioClip(fileName, AudioType.OGGVORBIS))
{
yield return loader.SendWebRequest();
if (loader.isNetworkError || loader.isHttpError)
{
Debug.Log(loader.error);
}
else
{
// Sets the audioClip with the data downloaded.
audioClip = DownloadHandlerAudioClip.GetContent(loader);
MusicCache.musicToPlay = audioClip;
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
}
void ButtonPress(string songName)
{
// This is a simple use function which returns the music in the UI when the player presses the button for it.
// Currently, it loads the selected music and moves to the next scene.
if (currentlyLoading)
{
return;
}
currentlyLoading = true;
StartCoroutine(LoadMusic(songName));
}
private void Awake()
{
// In this Awake function, it assigns the music in the Music folder to the musicList,
// so it makes a list of every file with the extension of .OGG.
// So, every song you want to use with the game will have to be a .OGG file.
musicList = new List<string>(Directory.GetFiles("Resources/Music", "*.ogg"));
if (musicList.Count > 0)
{
// This foreach loop checks if the musicList count is more than 0 and if it is,
// it instantiates a button, sets its text for each different song in the musicList.
foreach (string song in musicList)
{
GameObject newButton = Instantiate(buttonPrefab, parentPrefab);
newButton.GetComponentInChildren<Text>().text = song;
newButton.GetComponent<Button>().onClick.AddListener(() => ButtonPress(song));
}
}
else
{
// If no music is found, it prints "No Music".
print("No Music");
}
}
}
This is the Unity Documentation which was used to help me understand:
And these are the other two scripts which work alongside it to make it all work:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MusicSelectButton : MonoBehaviour
{
public MusicSelect musicSelect;
public string songName;
public void buttonPress()
{
musicSelect.startLoadMusic(songName);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MusicCache
{
public static AudioClip musicToPlay;
}
I only had to get the Death Screen UI done, and I had to edit some of the text on the Song Select, I also had to make sure everything UI-Related is polished and pretty before I animate it.
I began by drawing out quick concepts for my Death Screen, getting interest from a pinterest board I made.
Death Screen Game UI Pinterest Board
After making these two concepts, I went with the 2nd concept since I liked it more. And I began production for this death screen.
I began by making a separate canvas, which is where the death screen is going to be on, and then I also made a separate camera which is where I’m going to have the death camera and then I’m going to use a culling mask which would block out the whole game besides the death UI, which is useful instead of switching around all of the UI.
And then I wrote a script which hides the UI and game, and then displays the Death UI whenever the player hits the ground.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class _CharCollision : MonoBehaviour
{
[Header("Functions")]
private bool touchingGround = false;
[Header("Cameras")]
public Camera playerCamera;
public Camera altCamera;
[Header("Canvases")]
public Canvas gameCanvas;
public Canvas deathCanvas;
void Update()
{
if (touchingGround)
{
altCamera.gameObject.SetActive(true);
deathCanvas.gameObject.SetActive(true);
playerCamera.gameObject.SetActive(false);
gameCanvas.gameObject.SetActive(false);
}
else
{
// Add any behavior for the 'else' condition if needed
}
}
}
This was a pretty simple script, since I just needed to setActive(false) to the component which we need to hide whenever the player dies, and then I just added a menu button to the death screen which leads you back to the main menu.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class UI_Deathscreen : MonoBehaviour
{
public void Menu()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex - 1);
}
}
I decided with this one I wanted to copy a Kingdom Hearts type style and then replicate something similar to that for my game with the player cube rotating in the air as it dissolves, and I used a shader which I hadn’t used in my game yet to achieve that, so I’m glad to have used the shader there.
I’m also planning to have a Game Over screen display once the players music has finished playing, displaying what score they got and displaying all of their game stats, and once the menu button is clicked, their gold and score data would be saved, so they can always try and get a higher score, I’m hopefully able to also use the gold to make a shop system where the player can buy upgrades to make the game easier.
Another thing I added (this wasn’t on the list) was improvements to the menu screen UI.
On the play and quit buttons, I added a highlight to them which had a gradient png image which I made in photoshop to make selecting the button feel better.
Another thing I added was buttons which take you to my social media. This is the script I used to make it work on click.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SocialMediaButtons : MonoBehaviour
{
public void twitterURL()
{
Application.OpenURL("https://twitter.com/AmyElliott_");
}
public void instagramURL()
{
Application.OpenURL("https://www.instagram.com/amy.m.elliott/");
}
}
I found getting the song selection functional hard since I’ve never used some of the syntax in there, so it was a lot of research and talking to friends to get this to work, but I am SO glad that I did get it to work, since I feel like it’s a very big and important part of the game to have it working.
Everything else was pretty much polish, so that was pretty simple to get done.
I left the UI animation since I feel like it’s fine as it is.
I plan to finish up everything by next week and get to publishing and polishing final bits so the game is ready to upload to Itch.io.