In diesem Tutorial zeige ich euch, wie man in Unity eine Audiodatei abspielt und vor allem, wie ich ein Problem mit sich überlappender Audiowiedergabe durch eine Audio Source gelöst habe.
Die Videoversion dieses Tutorials ist derzeit in dieser Sprache nicht verfügbar.
Videotranskript
Hallo zusammen! In diesem Tutorial zeige ich euch, wie man in Unity eine Audiodatei abspielt und vor allem, wie ich ein Problem mit sich überlappender Audiowiedergabe durch eine Audio Source gelöst habe. Bitte beachtet, dass die im Video gezeigte Lösung lediglich mein gewählter Ansatz für dieses Problem ist. Es gibt mit Sicherheit auch andere und möglicherweise bessere Lösungen. Betrachtet die hier gezeigten Informationen also nicht als einzig richtigen Weg.
Das Tutorial wurde mit Unity 2022 erstellt. Konkret möchte ich eine Schrittgeräusch-Datei abspielen, wenn sich der Charakter in der Szene bewegt. Die Datei stammt aus dem ersten Prince of Persia Spiel von Jordan Mechner, das meine erste PC-Spielerfahrung war. Diese Aufgabe wirkt zunächst einfach, enthält aber eine kleine Herausforderung.
Um die Schrittgeräusche abzuspielen, muss zunächst eine Audio Source dem Charakter hinzugefügt werden. In dieser Komponente legen wir die abzuspielende Audiodatei fest und konfigurieren weitere Wiedergabeeigenschaften.
Eine Audio Source ist eine Komponente, die einem Objekt in der Szene hinzugefügt werden muss. Das kann der Charakter sein, eine Tür, ein Ball oder auch ein unsichtbares Objekt, etwa um eine Audiodatei abzuspielen, wenn der Charakter einen bestimmten Raum betritt oder sich einem Objekt nähert.
Damit der Ton von der Main Camera gehört werden kann, benötigt die Camera eine aktive Audio Listener Komponente. In neuen Unity-Projekten besitzt die Main Camera standardmäßig eine aktive Audio Listener Komponente, da davon ausgegangen wird, dass Audio wiedergegeben werden soll. Falls der Audio Listener fehlt, kann er im Inspector der Main Camera hinzugefügt werden.

In meinem Fall soll die Audiodatei mit dem Charakter verknüpft werden.
In meinem Projekt gibt es ein Player-Objekt, das als Parent der Main Camera dient. Das Bewegungsskript ist dem Player-Objekt zugeordnet, während die Kamera ein eigenes Skript besitzt, um das Umsehen zu ermöglichen. Deshalb füge ich dem Player-Objekt eine AudioSource-Komponente hinzu.

Wenn ihr die neu erstellte Komponente öffnet, seht ihr sofort das Feld AudioClip, das zunächst auf None gesetzt ist.
Außerdem gibt es die Checkbox Play on Awake, die standardmäßig aktiviert ist. Diese Option spielt die Audiodatei beim Start des Spiels ab. Das kann in bestimmten Situationen sinnvoll sein, ist für unseren aktuellen Anwendungsfall jedoch nicht notwendig, daher deaktiviere ich sie.

Eine Audiodatei in das Projekt zu importieren ist sehr einfach. Zieht die Datei aus einem File Browser in den Project-Tab oder wählt sie über Assets - Import New Asset von eurer Festplatte aus.

Unity unterstützt verschiedene Audioformate wie mp3 und zeigt im Project-Fenster ein Notensymbol neben der entsprechenden Datei an.
Wie ihr seht, enthält mein Projekt bereits mehrere Audiodateien für unterschiedliche Situationen. Die Datei, die uns interessiert, heißt PoP---walk.
Zuerst wähle ich den Player in der Hierarchy aus.
Anschließend klicke und halte ich die Maustaste auf dem Asset PoP---walk im Project-Fenster gedrückt.

Dann ziehe ich dieses Element in das AudioClip-Feld der AudioSource-Komponente des Player-Objekts.
Wie bereits erwähnt, soll der Ton abgespielt werden, wenn sich der Charakter bewegt.
Dazu öffne ich das Skript, das für die Bewegung des Charakters zuständig ist, und füge den erforderlichen Code ein.
Zunächst erstelle ich eine AudioSource-Variable und initialisiere sie in der Start-Funktion, indem ich sie mit der AudioSource-Komponente des Player-Objekts verknüpfe.
Dazu schreibe ich folgenden Code:
private AudioSource playerAudioSource;
und innerhalb der Start-Funktion:
playerAudioSource = GetComponent();
Zusätzlich erstelle ich eine AudioClip-Variable, die mit der abzuspielenden Audiodatei verknüpft wird. Ich nenne sie myAudioClip und verwende das Attribut SerializeField, damit sie im Inspector sichtbar ist. Nach dem Speichern des Skripts ziehe ich das Asset PoP---Walk in das Feld myAudioClip im Inspector.
Direkt nach der Definition von playerAudioSource schreibe ich folgende Codezeile:
[SerializeField] private AudioClip myAudioClip;

Nach dem Speichern kehre ich in den Unity Editor zurück und ziehe wie beschrieben das Asset PoP---Walk in das Feld myAudioClip des Skripts.

Im Moment wird der Ton noch nicht abgespielt.
In der Update-Funktion des Skripts befinden sich Anweisungen, die die Tasteneingaben des Benutzers erkennen und die Bewegung des Charakters steuern.
Wenn sich der Charakter bewegt, kann der Wert von Input.GetAxis für Horizontal und Vertical, die ich zur Vereinfachung in x und y umbenannt habe, je nach Richtung entweder -1 oder 1 sein.
Man könnte nun folgenden Code schreiben:
if ((Mathf.Abs(x) == 1) || (Mathf.Abs(z) == 1))
playerAudioSource.PlayOneShot(myAudioClip);

und das Spiel starten. Das wäre jedoch ein großer Fehler, denn Unity würde die Audiodatei in JEDEM EINZELNEN FRAME DES SPIELS abspielen.
Das Ergebnis verbessert sich auch nicht, wenn man die Funktion PlayOneShot in eine Coroutine verschiebt und eine Verzögerung von einer Sekunde mit yield return new WaitForSeconds(1) einfügt. Das Problem bleibt bestehen, da Update die Coroutine in jedem Frame aufruft und wir wieder beim gleichen Fehler landen.
Die Coroutine ist also nicht notwendig. Stattdessen müssen wir eine einfache Prüfung der AudioSource implementieren: Der Ton soll nur abgespielt werden, wenn die AudioSource ihn gerade nicht bereits wiedergibt.
Das kann innerhalb der Update-Funktion geschehen, indem wir folgenden Code in den if-Block einfügen, der die Werte von x und y überprüft:
if (!(playerAudioSource.isPlaying))
playerAudioSource.PlayOneShot(myAudioClip);

Nun können wir das Skript speichern, das Spiel starten und das Ergebnis beobachten beziehungsweise anhören.
Zum Abschluss noch ein Gedanke: Das AudioClip-Feld der AudioSource-Komponente kann selbstverständlich auch per Skript geändert werden.
Das bedeutet, ihr könnt dieselbe AudioSource verwenden, um ein Standard-Schrittgeräusch abzuspielen und während des Spiels die Audiodatei austauschen, etwa wenn der Charakter über Kies, am Strand oder auf anderen Oberflächen läuft. Solche Oberflächen lassen sich zum Beispiel mithilfe von Colliders erkennen.
Außerdem könnt ihr die AudioSource deaktivieren, wenn euer Charakter fliegen kann, sodass kein Ton abgespielt wird.
Das war es für dieses Tutorial. Ich hoffe, es war hilfreich. Bis bald!