Zum Hauptinhalt springen

Overview


Role:   Lead-Programmer
Project Team:   8 Students
Version:   Unity 2018.4.18f1

Tasks:   - Task packages created for other programmers
  - Background music and ambience sound
  - Coin and Star collection
  - Character animations
  - Movement of the character
  - Bug fixing and performance optimization

Trailer

Story

Lethe was put into a deep sleep by a dark wizard.  To free herself she must travel through a magical land and faces various obstacles to find all the runes for the locked gate and activate it. In doing so, she'll have to fight her way from sector to sector to reach all the runes. Once she has uncovered the complete level and activated all the runes, she can continue her adventure.

Description

This project had to meet several requirements, including a pleasant movement and a good sound environment. I will go into more detail about the development with a well-rounded sound experience. Here a few problems arose that had to be solved.

The background music had to meet several criteria, which were determined by the game designer beforehand. 

These were:

  • The loop should not be heard -> No pause at the end and restart normally

  • The song should pivot with a nice transition when the world changes.
     
  • The song should not start over when you re-enter the world and vice versa.

 

Dynamic sound mixing

Since our background music consisted of two pieces of music, namely one song for inbound and one for outbound, four sound mixers and four audio sources are necessary for seamless playback.

Sound mixers are roughly responsible for the playback of sounds, such as volume or pitch, among other things. When the player adjusts the volume via the options menu, he always adjusts the mixers and never the audio sources. Even though the audio sources have their own pitch and volume controls, they are not affected by the player during the game. The audio sources are responsible for playing the sound clips, and the actual music.

As mentioned earlier, four mixers and four audio sources are necessary for this game. Another reason for the number is the gameplay. The player can switch between inbound and outbound at any time without being blocked, but this also means that the music can change at any time and this should of course happen without a break. I will explain more details about the setup.

But the sound controller is not only responsible for the background music, but also for the ambient sounds. However, there is also a small challenge here, because when the player enters a cave, the wind should no longer be played.

Figure 1

Sound controller

The setup consists of four components, namely four audio sources.

  1. Audio Source -> start for inbound music

  2. Audio Source -> Start for outbound music

  3. Audio Source  -> Looper 1

  4. Audio Source -> Looper 2

If the player starts inbound, i.e. within the sector, the music for inbound is started on the first audio source. If the player stays inbound and the song is coming to an end, three seconds before the end, the same song will start on audio source three, looper one, so there is no pause between songs. If the player remains inbound and the song is coming to an end, the song on audio source four is started three seconds before the end. From this moment on, the loopers only alternate towards the end of the song, which means that when the song in looper two slowly approaches the end, the song on looper one starts, and so on.

When the player now goes outbound, both loopers are muted and audio source two is started. From this moment on the procedure continues as inbound. If the player stays outbound longer and the song comes to an end, audio source three starts with the outbound music and so on.

Here again graphically illustrated with a loop inbound:

Figure 2

Start function - SoundController.cs

Figure 3

The start function controls all settings for the audio sources that are to be set at the beginning of the game. This includes, for example, that the looper should repeat. I also save the default volume to be able to fall back on this value. Furthermore, the wind sound is started and I attach the function "StopAll" to the delegate "OnEnterPortal". This will happen more often, so I will go into more detail here. In the instance of "m_portal" there is a delegate with the name "OnEnterPortal which is triggered when the player walks through a portal. If this happens, the "StopAll" function is executed in the sound controller. In this way I can use an event that is triggered in another script to execute a function. Furthermore the function "TryGetPlayer" is executed in the start function.


TryGetPlayer function

Figure 4

I use this function often in the project. With this function, I want to have an instance of the player since this is only created when the game is started. If the game is now started and the instance of the player could be determined, different delegates which are on the player will be linked to functions in the sound controller. For example the location of the player (inbound or outbound). Or what should happen when the player dies and respawns. This function is not only used to determine the instance of the player, but also the internal functions with the delegates of the player. 

PlayMusic function

Figure 5

As you could see in the "TryGetPlayer" function, the "PlayMusic" function is called when the player goes outbound. This function has four parameters.


1. Audio clip that should be played.

2. Audio source on which the audio clip is to be played.

3. Audio source which is to be switched off or turned down. 

4. It is a looper.


If it should be a looper, own coroutines for the looper are played, which has similarity with the normal in and out threading of the normal music. It is important to mention here that the music is always turned down before the music is paused or stopped.


FadeIn Coroutine

Figure 6

As already mentioned, the coroutines always differ only minimally. In the "FadeIn" coroutine it is checked at the beginning if certain conditions are fulfilled. If these are fulfilled, the routine is stopped. First, it is checked whether the volume has already reached the target volume because then a fade-in is no longer necessary. Also, it is checked if the script is started for the first time because I didn't want the music to fade in slowly at the beginning, but to start immediately. It also checks if the player is respawning. Next, I set the value for "currentTime" to 0, which I need later to fade slowly. Next, I check by the parameters, which audio source is currently running and set it to true by the variable, this is needed for the update function. If the music is already playing, I continue it, otherwise, the music should start from the beginning. Finally, I fade the volume to the desired volume with the value from "currentTime".


Fadeout Coroutine

Figure 7

In the "FadeOut" coroutine the same happens as in the "FadeIn" coroutine, only the other way around. Here it is checked at the beginning whether the player respawns and if so, the routine is to be aborted immediately. Then again the variable "currentTime" is set to 0 and the slider of the current volume is set to 0. Just like in the "FadeIn" routine, a parameter "_duration" is also specified here. This can be changed by the game designer to set the time individually.


Update function

Figure 8

I divide the "Update" function into several areas. In the beginning, the area that is responsible for the transfer from the audio source to the looper. In the beginning, I first query the variable that was set in the "FadeIn" coroutine, so that I know if the audio source one is currently playing. If there is a song playing, I store the length of the song minus three seconds to be able to start with the audio source three in time. If this time has been reached and the inbound song is playing in audio source one, then the inbound song starts on audio source three and fades out of audio source one.

The same procedure takes place here with audio source two. Only here it is checked whether the song for the outbound is played and then starts three seconds before the end on the looper one.

Figure 9

The second part of the "Update" function deals with the loopers. So the audio source three and audio source four. The procedure is almost the same, except that it checks which song is currently running in one looper and looper and passes it to the other looper.

Summary

With this constellation of mixers and audio sources, I was able to create a seamless system that allows me to change two different songs at any time without gaps and also to repeat them. Furthermore, I can let the game designer set how long it should take until a song how long it should take for a song to fade in or out, and thus I could do justice to the task.

  • What I have learned
    • Further knowledge of the Unity Engine.

    • How milestones are achieved in time.

    • Mathematical knowledge was expanded.

    • Close collaboration with the game designer to have a pleasant movement.
  • Further knowledge of the Unity Engine.

  • How milestones are achieved in time.

  • Mathematical knowledge was expanded.

  • Close collaboration with the game designer to have a pleasant movement.

Repository

Link to Subversion: ​https://christian-brueckl.de:8443/svn/Kelingan/​​​

_________________________

Username: showcase
Password: showcase