Crab Meat: Basic Scripting
As a game designer, I would always have to script at some point, and I would have to be able to demonstrate that I can use C# to an industry standard. With that being said, I didn’t shy away from scripting during the development of Crab Meat.
Below is the script that I’ve created for the scene controller.
[SerializeField]private GameObject Loading;[SerializeField]private GameObject Pause;
Above, I have two variables with [SerializeField] and Private variables, as I wanted to avoid using too many public variables as I didn’t want it sitting in the memory. However, as this is for the UI, I did follow decent coding conventions, and used depracated C# Unity methods. To be specific;
public void MainMenu(){Application.LoadLevel("Main Menu");Time.timeScale = 1;if (Loading.activeInHierarchy == false){Time.timeScale = 1;Loading.SetActive(true);}}
The line Application.LoadLevel(“____”)has been deprecated since Unity 5 and I’ve had to start using the Scene.
I created the Audio Manager for the project and here is the code I came up with it. As I needed to access the Unity Scene Management function, so I’ve had to access using UnityEngine.SceneManagement; so I could return the Scene number from the Unity build settings. Below is every variable within the Sound;
public class SoundManager : MonoBehaviour{[Header("Sound Tracks")][SerializeField]private AudioSource Beach; //Drag a reference to the audio source which will play the sound effects.[SerializeField]private AudioSource Atlantis; //Drag a reference to the audio source which will play the music.[SerializeField]private AudioSource Cutscene; //Drag a reference to the audio source which will play the music.[SerializeField]private AudioSource Menu; //Drag a reference to the audio source which will play the music.[Header("Sound Effects")][SerializeField]private AudioSource soundFX; //Drag a reference to the audio source which will play the sound effects.[SerializeField]private float minPitch;[SerializeField]private float maxPitch;[SerializeField]public static SoundManager instance = null; //Allows other scripts to call functions from SoundManager.//Scene Detectionprivate int CurrentLevel;
I had to do [SerializeField] on every variable that didn't need to be public, as I also didn't want it loaded in the memory of the project. I wanted anyone to be able to open up the project and be able to change the sounds through the Unity inspector, so every soundtrack can be defined by the AudioSource variables, that is why they all have the [SerializeField] line for the private variables. Below is the code that stops the Audio from destroying on load;
void Awake(){OnLevelWasLoaded();//Check if there is already an instance of SoundManagerif (instance == null)//if not, set it to this.instance = this;//If instance already exists:else if (instance != this)//Destroy thisDestroy(gameObject);//Set SoundManager to DontDestroyOnLoad so that it won't be destroyed when scene loads.DontDestroyOnLoad(gameObject);}
On Awake, I run this function, where it will always check if this script exits in a scene and if it does, it destroys itself. This function, also calls the OnLevelWasLoaded();function, so that when ever a knew scene loads, it runs all the code that is within it.As long as the AudioSource attached to the parent object is set to ‘loop’, the soundtrack won’t restart or stop when a new scene is loaded.
The Variable public static SoundManager instance = null; is there as it is used to easily set up a constructor for other scripts to reference. Using this variable, I can call the SoundManager from another script using the following function;
private void PlaySingle(AudioClip clip, bool pitchChange){//Set the clip of our efxSource audio source to the clip passed in as a parameter.soundFX.clip = clip;if(pitchChange == true){float soundPitch = Random.Range(minPitch, maxPitch);soundFX.pitch = soundPitch;}//Play the clip.soundFX.Play();}
If another script uses the line SoundManager.instance.PlaySinglePitch(iceCrack, pitchChange);it will be able to play a single audioClip everytime it's told to play, but it will also play at different pitches each time it is played. During play testing, we received feedback that the movement audio was too repetitive, so I tried changing the pitch each time an AudioClip was played to add some variation. Adding the function that does the following allowed me to add variation to each sound played and during the playtest, the audio wasn’t seen as repetitive;
soundFX.clip = clip;if(pitchChange == true){float soundPitch = Random.Range(minPitch, maxPitch);soundFX.pitch = soundPitch;}//Play the clip.soundFX.Play();
The minPitch and maxPitch variables allowed me to change the pitch variables in the inspector, and easily change the pitches to allow for more sound variation.
There is one function that I will admit is a tad convoluted and may be more complicated than it needs to be. OnLevelWasLoaded(); does the following;
private void OnLevelWasLoaded(){CurrentLevel = SceneManager.GetActiveScene().buildIndex;if (CurrentLevel >= 0 && CurrentLevel <= 1){if (!Menu.isPlaying){Menu.Play(); //Play this sound}Beach.Stop();Atlantis.Stop();Cutscene.Stop();}if (CurrentLevel == 2){if (!Cutscene.isPlaying){Cutscene.Play(); //Play this sound}Beach.Stop();Atlantis.Stop();Menu.Stop();}
The line CurrentLevel = SceneManager.GetActiveScene().buildIndex; sets the CurrentLevel variable to be the same int as the buildIndex. Doing this allows me to do the if statement if (CurrentLevel >= 0 && CurrentLevel <= 1), that checks if the current scene is inbetween the two defined ints. The reason I used SceneManager.GetActiveScene().buildIndex instead of Application.LoadScene("____") as it is not depracated with Unity 2017 whilst Application.LoadScene("____") has been since Unity 5. Once the bool for the if statements passes as true, I do a check for if the Soundtrack is currently playing by doing the following;
if (CurrentLevel >= 0 && CurrentLevel <= 1){if (!Menu.isPlaying){Menu.Play(); //Play this sound}Beach.Stop();Atlantis.Stop();Cutscene.Stop();}
If the current soundtrack is playing, play the sound track and stop every other sound track. I repeated this for every scene group that needed the same soundtrack to avoid the audio restarting and the incorrect song playing.
Apart from the gamecontroller that deals with the hazards and obstacle mechanics of Crab Meat, this is the bulk of the scripting I did for the project. I do think I need to do more, but for now I believe that I am meeting at least a few industry best practice.