Jump to content
Unity Insider Forum
Rogan

Fehler nach dem Build, der nicht im Play Mode auftaucht

Recommended Posts

Hallo,

Ich habe folgendes Problem. Wenn ich mein Spiel in Unity direkt starte, dann taucht keine Fehlermeldung auf, aber wenn ich das Spiel builde und die exe starte, dann taucht folgender Fehler im output_log auf: 

NullReferenceException: Object reference not set to an instance of an object
  at GameController.StartNewLevel () [0x000cc] in C:\Users\Daniel\Documents\tanks 3\Assets\Own Assets\Scripts\GameController.cs:303 
  at GameController.Update () [0x00081] in C:\Users\Daniel\Documents\tanks 3\Assets\Own Assets\Scripts\GameController.cs:631 

output_log.txt

vielen Dank in voraus für eure Hilfe.

Share this post


Link to post
Share on other sites

Könntest ja mal die entsprechenden Scriptzeilen (mit ein paar Zeilen drumherum) posten, wird sonst schwer mit dem Raten.

Share this post


Link to post
Share on other sites

Ja, das würde helfen.
Aber es sieht so aus, als würde es im GameController Script in Zeile 303 zu finden sein. Dort will das Script auf ein Objekt zugreifen, welchen aber nicht bekannt ist.
Und bevor Unity sich tot sucht, sagt es einfach wo was nicht stimmt. ;)

Share this post


Link to post
Share on other sites

Habe übersehen, dass ihr schon geantwortet habt. Ich habe gedacht, man bekommt eine E-Mail, wenn jemand Antwortet :)

Unter meinen Text hatte ich doch die output_log.txt angehängt, merkwürdig. Ich schreibe es hier mal rein: 

// edit: ne danke

 

das wiederholt sich eig. nur etliche mal der selbe Fehler. 

Edited by Sascha
Log entfernt

Share this post


Link to post
Share on other sites

Ja gut, ich hab das dann mal wieder gelöscht.

vor 41 Minuten schrieb Rogan:

Unter meinen Text hatte ich doch die output_log.txt angehängt, merkwürdig.

Was ist daran merkwürdig? Die bringt uns nur halt nix. Wir reden von deinem Code.

Share this post


Link to post
Share on other sites

Au Backe. Über 700 Zeilen Spaghetticode, wie beim Italiener. Das zu Debuggen ist nahezu unmöglich... es sei denn man schreibt dafür alles neu.

Alles, was ich da sagen kann ist, dass das Spieler-Objekt offenbar keine "Shoot"-Komponente hat, während diese Zeile ausgeführt wird. Warum das im Play mode nicht ist, im Build aber schon, ist echt schwer zu sagen. Ich nehme jedenfalls an, dass du keine Preprocessor-Direktiven in einer der anderen Klassen hast?

Share this post


Link to post
Share on other sites

Ich verstehe leider nicht ganz, was du meinst, sry. Könnte es aber irgendwie damit zusammenhängen, dass ich das GameObject, an was ich das gehangen habe, Don't Destroy on Load gesetzt habe und das irgendwelche Probleme verursacht? 

Share this post


Link to post
Share on other sites

Sollte damit nichts zu tun haben, eigentlich. Aber das ist das Problem mit dreistellig Zeilen langen Gottklassen - man kann die Zusammenhänge nicht erkennen, die Struktur nur erraten und eine der besten Techniken beim Debuggen - das Isolieren der Fehlerquelle, sodass man sich nur noch mit wenigen Zeilen beschäftigen muss, von denen man weiß, dass der Fehler in ihnen steckt - steht nicht zur Verfügung.

Share this post


Link to post
Share on other sites

dann muss ich wirklich in Zukunft mehrere Scripts machen. Was mir aufgefallen ist: Egal, welchen unterschiedlichen feindlichen Panzer ich in die Scene stecke, er findet das entsprechende Script, was ich den  zugewiesen habe, dafür nicht. Ich gehe jetzt aber erstmal off, bis morgen dann.

Share this post


Link to post
Share on other sites

Könnte es sein, dass irgendeine Datei im Projekt beschädigt ist oder dass irgendein Import von einen Asset vom Assetstore sowas verursachen könnte? Ich verstehe halt nicht, wie so was passieren kann, dass etwas im Play Mode funktioniert, aber nach dem Build nicht mehr. Der Play Mode ist doch eig. dafür da, um zu testen, ob das Spiel bis dorthin funktioniert. Was sollte man generell vermeiden, damit zukünftig in einen anderen Projekt so ein Problem nicht mehr auftaucht?

Share this post


Link to post
Share on other sites

Klar kann auch ein Asset nicht in Ordnung sein.
Aber das glaube ich eher nicht.
Wenn du in Unity dein Spiel testest und es wäre z.B. keine Verknüpfung im Code zu einem Objekt oder einer Komponente aufgebaut, dann läuft das Spiel in der Regel weiter. Es haut die aber in der Konsole eine "ROTE" Fehlermeldung raus.
Machst du dann ein Build vom Spiel und dort ist dieser Fehler immer noch vorhanden, dann kann es dazu kommen, dass das Spiel komplett abschmiert. Je nach dem auf welchem Betriebssystem du bist. So habe ich es selber erlebt, dass ein Abfragen eines Arrays über seine länge hinaus auf dem PC keinen Abbruch verursacht hat, aber auf iOS ist das Spiel einfach abgestürzt. Ohne Meldung, einfach weg!

Also schau einfach mal ob du wirklich keine Fehlermeldung siehst, wenn du es im Editor startest und genau so durch die Szenen gehst, als wenn du das Build spielst. Ich könnte wetten, dass du auch da die gleiche Fehlermeldung hast.

Share this post


Link to post
Share on other sites

Ich habe Windows 10. Das GameObject mit dem Script, was ich gepostet hatte, habe ich mal zum testen deaktiviert. Ich habe eine neue Scene erstellt und nur den Spieler, den Feind und ein paar Cubes ohne Scripts hinzugefügt. Der Feind verhält sich, wenn er eine direkte Sichtline hat so, dass er nur schießt und ein Hindernis im Weg ist, schießt er Granaten über das Hindernis. Wenn ich auf den Play Mode drücke, dann kommt keine Fehlermeldung in der Konsole und da ich direkt vor ihm stehe, schießt er nur seine normalen Geschosse. Wenn ich das Spiel builde, dann schießt er komischerweise aber die Granaten und er dreht sich teilweise komisch oder gar nicht richtig. Allein, dass er sich nach dem build anders verhält, finde ich komisch. 

Share this post


Link to post
Share on other sites

Das finde ich auch komisch. Das kann viele Ursachen haben und da bin ich echt überfragt.
Da musst du jetzt einfach mal durch deine Scripte gehen und gucken, wann er Granaten werfen darf und was die Ursache sein könnte, dass er im Build anders agiert. Die Bedingungen für diverse Sachen sind scheinbar jetzt anders. Finde heraus warum.
 

Share this post


Link to post
Share on other sites

Wenn ich etwas builde, dann müsste doch alles im Ordner, wo das Projekt "gebaut" wird, vom heutigen Datum sein, oder? Bei mir ist es, auch wenn ich einen neuen Ordner mache, die Daten zum teil von heute, aber auch zum teil vom 11.04 zu verschiedenen Uhrzeiten. Wenn ich das mit einen anderes Projekt mache, passiert das selbe. 

Share this post


Link to post
Share on other sites

Wenn du einen neuen Ordner erstellst, der leer ist, und dann da drin Daten unterschiedlichsten Datums sind. Dann sind diese Daten dann auch zum letzten mal zu diesem Zeitpunkt erstellt oder verändert worden.
Alles ganz normal.

Verabschiede dich davon, dass Unity beim Build etwas falsch macht. Der Fehler liegt in "deinen" Daten!

 

Share this post


Link to post
Share on other sites

ok, ich habe den Fehler endlich gefunden :) Ich habe in verschiedenen Scripts mein Spieler über den Befehl: GameObject.FindGameObjectWithTag  mit den Tag "Player" gesucht. Leider habe ich wohl irgendwann mal versehentlich ein GameObject, was ein Kind Object vom Spieler ist, auch den Tag "Player" gegeben. Also gab es 2 Objekte mit dem selben Tag. Er hat aber im Editor immer das GameObject mit dem Tag herausgesucht, was ich haben wollte, während der im Build immer das andere Gameobjekt mit dem selben Tag herausgesucht hatte, welche ich nicht wollte. Das erklärt dann die Fehlermeldungen bzw. die unterschiedlichen Verhalten im Build im Vergleich zum Editor. Leider habe ich lange gebraucht, um diesen Fehler zu finden, aber besser jetzt als nie. Nur schade, dass Unity keine Warnung ausgibt, wenn man nach nur einen Objekt mit dem Tag sucht, aber mehrere Objekte mit diesen Tag in der Scene sind. 

Share this post


Link to post
Share on other sites

Das ist natürlich hart! Aber schön, dass du diesen Fehler gefunden hast.

Für Unity ist das jetzt nichts Außergewöhnliches, wenn der gleicheTag öfters vorkommt, denn ganz oft hat eine ganze Gruppe von Objekten den gleichen Tag. Z.B. Enemy.
Beim Suchen macht Unity eigentlich immer das Gleiche. Es sucht ein Objekt mit Tag, Namen oder eines gewissen Typs  und das erste Objekt, welches gefunden wurde, wird genutzt. Warum im Editor immer das Richtige gefunden wurde, aber im Build nicht, kann ich nicht sagen.
Aber leider weiß man eh nie welches Objekt das Erste sein wird.
Wie dem auch sei: du solltest immer gegen null testen, und nur dann code ausführen, wenn das Gewünschte eben nich null ist. Und falls es so ist, solltest du eine Warnmeldung raus hauen. Dann würde zwar nicht das passieren, was im Spiel eigentlich passieren soll, aber das Spiel würde wenigstens nicht abschmieren und dir zusätzlich eine Info geben, die beim Bugfixen hilft.
Hier mal ein Beispiel:
 

SteamStatsAndAchievements SteamSender;

void Awake(){
  SteamSender = GameObject.FindObjectOfType<SteamStatsAndAchievements>();
  if(SteamSender==null){
    Debug.Log("SteamSender wurde nicht gefunden");
  }
}

void Update(){
  if(Steamsender!=null){
    //code ausführen
  }
}


 

Share this post


Link to post
Share on other sites

Ja, das muss ich zukünftig unbedingt öfters machen, weil ich mir der Fehlermeldung im Build nicht so viel anfangen konnte. Danke für die Antworten. Der Fehler hat mich richtig frustriert, da ich erstmal überhaupt nicht wusste, wie ich vorgehen soll, um den zu finden.

Share this post


Link to post
Share on other sites

Auf lange Sicht ist auch klar die Empfehlung, diese String-Funktionen (GameObject.Find, GameObject.FindGameObjectWithTag, Resources.Load usw) komplett liegen zu lassen. Genau solche Fehler passieren nur bei diesen Funktionen, für die es auch Alternativen gibt. Kleiner Artikel dazu: http://blog.13pixels.de/2019/why-strings-are-not-your-friend/

Share this post


Link to post
Share on other sites

Danke für den Artikel, Sascha. Das ist schon sehr interessant und hilfreich, was da so drin steht. In irgendein Forum Eintrag hattest du ja mal erwähnt, dass es nicht gut ist, mit Tags zu arbeiten, jetzt habe ich verstanden, warum. Wenn ich aber mit FindObjectOfType<> arbeite, dann habe ich auch das Problem, dass er sich irgendein beliebiges heraussucht, wenn mehr als 1. vorhanden ist. Allerdings sucht er sich dann sowohl im Build als auch im Editor das selbe heraus, während das beim FindGameObjectWithTag im Build sich ein anderes heraussucht, als beim Editor. Das habe ich gerade getestet. 

@malzbie: Was ich meinte: Wenn man mit sowas wie FindGameObjectWithTag oder FindObjectOfType<> arbeitet, dann macht man das ja eig. deswegen, weil man davon ausgeht, dass nur eins davon in der Scene ist. Deswegen wäre es meiner Meinung gut, wenn Unity in den Fall untersucht, ob mehr als eins davon vorhanden ist und wenn das der Fall ist, dann eine Warnung ausgibt. Das macht er ja auch z.B. dann, wenn man mehr als 1. AudioListener in der Scene hat. Man könnte das ja so verhindern, dass sowas passiert.

if (GameObject.FindGameObjectsWithTag("Player").Length == 1)
       player = GameObject.FindGameObjectWithTag("Player");
                        
else
      Debug.LogWarning("Entweder existiert kein GameObject mit diesen Tag in der Scene, oder es ist mehr als 1. vorhanden");  // Will ich beides nicht, erst recht nicht den 2.Fall

 

Share this post


Link to post
Share on other sites
vor 3 Stunden schrieb Rogan:

Wenn ich aber mit FindObjectOfType<> arbeite

FindObjectsOfType ist auch doof, aber mit einer anderen Begründung - diese ist leider etwas komplexer als die Begründung gegen Strings. Für Anfänger (und wohl auch eine Weile für Fortgeschrittene) ist das ne heftige Nummer. Ich arbeite seit über zehn Jahren mit Unity und habe erst letztes Jahr wieder ein richtig dickes "Klick" gehabt, was dieses Thema angeht.

Ich versuche aber mal, das zu erklären.

Unity ist ein dickes, fettes "Dependency Injection"-Framework. Stelle dir vor, du hättest den Unity-Editor nicht. Dann müsste deine Player-Kamera mit sowas wie GameObject.Find den Player finden, um ihm zu folgen. Stattdessen kannst du ein serialisiertes Feld in dein Kamera-Script packen, dem Script beibringen dem Ding zu folgen, das von der Variable referenziert wird, und den Player reinziehen. Das bedeutet, dass Unity irgendwie für dich dafür sorgt, dass das richtige Ding referenziert wird, ohne dass du dafür selber Code schreiben musst. Unity "injiziert" hier das Objekt, von dem das Verhalten der Kamera abhängt ("Dependency"), denn die Kamera fliegt anders, je nachdem, wem sie folgt. Darum "Dependency Injection".

Ich merk grad schon, da sollte ich auch mal einen Artikel drüber schreiben :)

Jedenfalls bewirkt Unity als Dependency Injection-Maschine zwei Dinge:

  1. Du kannst als Designer arbeiten, ohne zu coden. Gute Scripts lagern Abhängigkeiten, die als Teil des Gamedesign-Prozesses festgelegt werden, aus dem Code aus, sodass man keinen Code mehr braucht, um das Spiel letztenenedes zu verkabeln. Das macht Designarbeit angenehmer, weil richtig gute Scripts und Editor-Tools komplettes WYSIWYG machen, aner es erlaubt es auch, Teammitglieder zu haben, die nicht coden können und trotzdem Gamedesign machen.
  2. Es nimmt die Verantwortung aus den Scripts. Das Kamera-Script hat keine Verantwortung mehr, sich mit dem Aufbau der Szene zu beschäftigen. Gibt es ein Player-Objekt? Gibt es mehrere? Was passiert, wenn es mehrere gibt? Folge ich dann dem erstbesten? Statt das Kamera-Script sich über so etwas Sorgen machen zu lassen, sagst du ihm: "Das wird dir dann schon gesagt, wem du folgen musst". Das sorgt für schlanke Scripts, die einfach nur das machen, was sie machen, und nicht noch Ahnung von lauter anderen Teilen des Projekts haben müssen.

Teil 2 ist hier das Wichtige. Wann immer dein Script nach etwas sucht, bedeutet das, dass es ein Mindestmaß an Ahnung haben muss, wie dein Projekt augebaut ist. Dazu gehört zum Beispiel ein bisschen Code, der definiert, was passiert, wenn es mehrere Player gibt, sofern du nicht irgendwie anderweitig sicherstellen kannst, dass es immer nur einen gibt... oder du lässt Unity pseudo-zufällig einen auswählen. Daher ist es immer schlecht, wenn dein Script etwas sucht, sei es nun mit Strings oder anderweitig.

Was meiner Meinung nach einen richtigen Unity-Coding-Pro ausmacht ist die Fähigkeit, für jede Situation eine elegante Art zu finden, wie Objekte sich "kennenlernen", ohne dabei Scripts zu erstellen, die mehr von der Welt wissen als das, was sie notwendig für ihre eigene Aufgabe benötigen. Wenn es z.B. darum geht, mit dem Player zu arbeiten, dann gibt es da direkt mehrere Möglichkeiten, die ohne das eigenständige Finden des Player-Objekts auskommen. Die erste Verbesserung wäre ein Pseudo-Singleton, über das ich auch schon einen Artikel habe: http://blog.13pixels.de/2019/unity-and-the-mysterious-singleton/

Wenn man nach Singletons sucht, findet man hin und wieder die Info, dass man die Finger davon lassen sollte. Letztenendes sind die auch nicht das Gelbe vom Ei, aber sie sind schonmal ein Stück besser als das Suchen von Objekten in der Szene. Mein Artikel hat als Konklusion auch, dass man die Dinger ruhig benutzen kann. Es wird etwas heftig, etwas besseres zum Laufen zu kriegen (das was mein "Klick"-Moment letztes Jahr), und bis man soweit ist, kann man ruhig Pseudo-Singletons benutzen.

Share this post


Link to post
Share on other sites

@Sascha

Du hast ja vollkommen Recht. Find ist nicht gut und mit Strings zu arbeiten schon gar nicht. Und meistens kann man das Umgehen.
Aaaber:
Hast du denn auch schon eine andere Lösung für Objekte, die nicht von Beginn an in der Szenen sind, aber unbedingt mit anderen Objekten, die schon vorher da waren,  interagieren wollen?
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×