Kojote Geschrieben 27. Oktober 2017 Melden Share Geschrieben 27. Oktober 2017 Grüß! Ich habe gerade ein kleiens Problem. In Scene 1 habe ich eine Hintergrundmusik laufen. Dafür ist GameObjakt "Musik" mit der Componente Audio Source zuständig, steuerung über mein Hauptmenü Script. Wenn ich das Theme wechsel, soll die Musik weiter gespiel werden. In Scene 2 habe ich ebenfalls ein GameObjekt "Musik" mit der Componente Audio Source. Hier soll nun die Musik Natlot in einander übergehen, beim Wechsel wird die Musik aber neu gestartet. Was kann ich dagegen unternehmen?^^ Grüße von Kojote Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
malzbie Geschrieben 27. Oktober 2017 Melden Share Geschrieben 27. Oktober 2017 Ja, das ist klar. Dein Musikabspieler wird beim entladen der ersten Szene zerstört und das neue Objekt fängt halt gerade erst an. Erstelle einfach ein Musikobjekt, welches per Code eben nicht zerstört wird, also durch alle Szenen mitgeschleift wird. Wenn es dann doch mal zerstört werden soll, musst du das manuell, wieder per Code machen. DontDestroyOnLoad ist dein Schlüssel zum Ganzen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 27. Oktober 2017 Autor Melden Share Geschrieben 27. Oktober 2017 OK wird probiert! Aber wie ist das mit dem DontDestroyOnLoad? Wenn ich dann zwischen den Szenen hin und her wechsel wird der ja immer mit geschliffen, summiert sich das ganze dann nicht? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
malzbie Geschrieben 27. Oktober 2017 Melden Share Geschrieben 27. Oktober 2017 Ja, das würde es machen. Du kann das Object enteder zum singleton machen. Oder aber du erzeugst es einmalig in einer Szene, die wirklich nur einmal geladen wird. Meist hat man ja ne Startszene, die vor dem Menü und allen Spielszenen geladen wird und dann nicht mehr. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 27. Oktober 2017 Autor Melden Share Geschrieben 27. Oktober 2017 Ich habs mal so versucht: if(GameObject.FindGameObjectsWithTag("Musik").Length > 1) { GameObjekt zerstoeren = GameObject.Find("Musik"); Destroy(zerstoeren); } DontDestroyOnLoad(musikObjekt); musikObjekt = GameObject.Find("Musik"); audioSourceSound = musikObjekt.GetComponent<AudioSource>(); Jedoch landet das musikObjekt nicht in DontDestroyOnLoad, wenn ich das Spiel starte. EDIT: Ja ne, is klar, erst das Objekt mit DontDestroyOnLoad sichern und danach finden. Umgekehrt klappts vielleicht deutlich besser! Vielen Dank @malzbie Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 28. Oktober 2017 Melden Share Geschrieben 28. Oktober 2017 Lass mal das mit den GameObject.Find-Funktionen, die sind böse. Lieber ein Unity-Singleton benutzen: public class MusicPlayer : MonoBehaviour { private static MusicPlayer singleton; void Awake() { if(singleton) { Destroy(gameObject); } else { singleton = this; DontDestroyOnLoad(this); } } } Bei Fragen gerne fragen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 28. Oktober 2017 Autor Melden Share Geschrieben 28. Oktober 2017 Zitat Lass mal das mit den GameObject.Find-Funktionen, die sind böse. Merk ich glaube ich gerade, dass steht in meiner Hauptmenüsteuerung, in Awake: if (GameObject.FindGameObjectsWithTag("Musik").Length > 1) { GameObject zerstoeren = GameObject.Find("Musik"); Destroy(zerstoeren); } musikObjekt = GameObject.Find("Musik"); DontDestroyOnLoad(musikObjekt); audioSourceMusik = musikObjekt.GetComponent<AudioSource>(); Das in meiner Spielesteuerung, in Awake: if (GameObject.FindGameObjectsWithTag("Musik").Length > 1) { GameObject zerstoeren = GameObject.Find("Musik"); Destroy(zerstoeren); } musikObjekt = GameObject.Find("Musik"); DontDestroyOnLoad(musikObjekt); audioSourceMusik = musikObjekt.GetComponent<AudioSource>(); Am Anfang macht er alles richtig, das Objekt "musikObjekt" wird in DontDestroyOnLoad geladen. Das Spiel wird geladen und übernommen. Wenn ich nun aber zurück ins Hauptmenü wechsel, wird das Musikobjekt nicht mehr in DontDestroyOnLoad geschoben und wenn ich das nächste mal ein Level lade, findet er kein musikObjekt -> ERROR! Warum übernimmt er das nicht? Jetzt probier ich mal den Script von @Sascha aus. Gleich mal ne Frage, wie greife ich nun auf die Audio Komponente zu, die in diesem Gameobjekt ist? Des weiteren, wie funktioniert der Spaß? Anscheinend löst das zumindest das Problem, was ich oben schrieb. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 28. Oktober 2017 Melden Share Geschrieben 28. Oktober 2017 Ich hab Sascha's Klasse mal erweitert: [RequireComponent(typeof(AudioSource))] public class MusicPlayer : MonoBehaviour { private static MusicPlayer singleton; private AudioSource audioSource; //Store a reference to our AudioSource. void Awake() { if(singleton) { Destroy(gameObject); } else { singleton = this; DontDestroyOnLoad(this); // Get a component reference to the attached AudioSource audioSource = GetComponent<AudioSource>(); } } } Deine Audiosource hängst du nun an das gleiche Objekt, wo auch das Skript "MusicPlayer" hängt. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 28. Oktober 2017 Autor Melden Share Geschrieben 28. Oktober 2017 So richtig verstehe ich das jetzt nicht. Ich muss ja trotzdem von einem anderen Script auf AudioSource zugreifen. Wie würde da der Zugriff darauf aussehen? Derzeit mache ich das so: AudioSource audioSourceMusik = GameObject.Find("Musik").GetComponent<AudioSource>(); Man könnte es auch so machen: Aufruf: audioSourceMusik = HEX_Musik_Steuerung.audioSourceMusik; Klasse: [RequireComponent(typeof(AudioSource))] public class Musik_Steuerung : MonoBehaviour { private static Musik_Steuerung singleton; public static AudioSource audioSourceMusik; void Awake() { if (singleton) { Destroy(gameObject); } else { singleton = this; DontDestroyOnLoad(this); audioSourceMusik = GetComponent<AudioSource>(); } } } Nur weiß ich nicht, ob das immer klappt. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 28. Oktober 2017 Melden Share Geschrieben 28. Oktober 2017 Da ist schon wieder dieses GameObject.Find...! vor 21 Minuten schrieb Kojote: Ich muss ja trotzdem von einem anderen Script auf AudioSource zugreifen. Warum solltest du das müssen? Es gibt dafür Möglichkeiten, aber da ich den Verdacht habem dass du das nur zu müssen glaubst, weil du das mit dem Singleton noch nicht verstanden hast, verrate ich erstmal nix Zur Funktionsweise: Das Keyword "static" ist eine der größten Verursacher von Missverständnissen bei Programmieranfängern. So sehr, dass ich schon viele Beiträge geschrieben habe, die static erklären. Und ein Tutorial. Das ist zwar mit JS und nicht C#, aber das Konzept ist dasselbe. Die Kurzfassung: Eine statische Variable existiert exakt einmal, und nicht einmal pro Objekt wie eine normale Variable. Die Variable "singleton" aus meinem Code speichert also global und für alle Objekte gleichermaßen gültig die Referenz auf exakt ein Objekt vom Typ MusicPlayer. Das MusicPlayer-Objekt, das ganz zu Anfang als erstes Existiert, schaut, ob es bereits "den" MusicPlayer gibt: if(singleton) // was dasselbe wäre wie if(singleton != null) Wenn noch kein vorheriger MusicPlayer den Platz als Singleton-Objekt für sich beansprucht hat, dann krallt sich das Ding den Platz und referenziert sich selbst: singleton = this; und macht sich mit DontDestroyOnLoad resistent gegenüber Szenenwechseln. Wenn dann irgendwann später ein neues MusicPlayer-Objekt auftaucht (weil du zurück ins Hauptmenü gehst, wo das Ding in der Hierarchie steckt), hast du zwei. Das neue führt Awake aus, das alte nicht. Dabei stellt das neue fest, dass "singleton" nicht gleich null ist, und zerstört sich und sein gesamtes GameObject selbst. Destroy(gameObject); Durch die statische Variable kannst also tracken, ob es "das eine Objekt" bereits gibt. Und wenn ja, zerstören sich alle Nachmacher selbst. Und da das alles Code stattfindet, brauchst du in Unity keine Namen oder Tags mehr zu vergeben. Du brauchst damit keine Kommunikation zwischen den verschiedenen Objekten mehr. Falls du deine Aussage, dass du da von außen drauf zugreifen musst, wegen etwas anderem meintest, dann sag bescheid. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 28. Oktober 2017 Autor Melden Share Geschrieben 28. Oktober 2017 Ist schon klar, dass Static nur einmal existiert, es ist recht unschön ausgedrückt, eine Globale Variable, die nur einmal existiert. Jedoch, wie greife ich nun bei AudioSource auf Volume zu, um die Lautstärke zu ändern, ohne einen Zugriff zu schaffen? Ohne Objekt Find, ist das schlecht möglich. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 28. Oktober 2017 Melden Share Geschrieben 28. Oktober 2017 Wenn ich nicht irgendwo noch einen Syntaxfehler drin hab: [RequireComponent(typeof(AudioSource))] public class MusicPlayer : MonoBehaviour { private static MusicPlayer singleton; private AudioSource audioSource; //Store a reference to our AudioSource. void Awake() { if(singleton) { Destroy(gameObject); } else { singleton = this; DontDestroyOnLoad(this); // Get a component reference to the attached AudioSource audioSource = GetComponent<AudioSource>(); } } public static void setVolume(float vol) { audioSource.volume = vol; } } Aufruf: MusicPlayer.setVolume(0.5f); Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Kojote Geschrieben 28. Oktober 2017 Autor Melden Share Geschrieben 28. Oktober 2017 Sehr interessant, man lernt immer was dazu! Vielen Dank! Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 28. Oktober 2017 Melden Share Geschrieben 28. Oktober 2017 vor 2 Stunden schrieb Kojote: es ist recht unschön eine Globale Variable, die nur einmal existiert. Dasja quatsch. Das ist wunderschön! Aber @Zer0Cools Code hat einen Kleinen Fehler. Es muss heißen public static void SetVolume(float vol) { singleton.audioSource.volume = vol; } audioSource ist ja nicht static, daher kann darauf nicht direkt von SetVolume zugegriffen werden. Eine Alternative ist das Folgende: Aus private static MusicPlayer singleton; mach public static MusicPlayer singleton { private set; get; } Ist dasselbe bis auf den Vorteil, dass man public lesend drauf zugreifen kann. Dann könnte man von außen schon MusicPlayer.singleton.audioSource.volume = 0.5f; Anstatt für alles, was man so mit ner AudioSource machen kann, eine neue Methode in MusicPlayer zu schreiben. Ob du das jetzt besser findest oder schlechter als zer0s Vorschlag, ist absolut Geschmackssache. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
MaZy Geschrieben 17. November 2017 Melden Share Geschrieben 17. November 2017 EDIT: Oh man jetzt sehe ich erst, dass dieser Thread ja schon fast ein Monat her ist ^^. Ich habe so fast wie in den letzen Post gemacht. Also Volume und so verändere ich auch nur durch audioSource selber ohne extra Methoden. Bei Singleton würde ich aufpassen. Ich persönlich würde nicht mit bei dem Beispiel mit GetComponent arbeiten. Aber ist Geschmacksache. Wieso? Ich lasse diese Sachen "vorladen" also schon bereits in der erste Scene (was ganz leer sein kann, quasi Ladebildschirm/Splashscreen mäßig beim Spielstart). Dort ist nun meine AudioSource Einstellung bereits gemacht. Ich lasse daher bei Singleton eher eine Error ausgeben, dass es nicht existiert. Theoretisch müsste ja dieser immer vorhanden sein. Wie gesagt ist Geschmacksache bzw. kommt drauf an. Bei vielen anderen Dingen braucht man wie bei mir nicht vorgehen. Folgendes existiert bei mir noch extra. Die Musikdateien. Eigentlich reicht auch private und [SerializeField], aber wollte damals Public haben public AudioClip[] clips; Paar Methoden um mein Leben leichter zu machen public void PlayMusicID(int id) { if (clips == null || id >= clips.Length) return; if (source.clip == clips[id]) return; source.clip = clips[id]; source.Play(); } public void PlayMusicID(int id, float volume) { if (clips == null || source.clip == clips[id]) return; source.volume = volume; PlayMusicID(id); } Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Archiviert
Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.