Erhalte Fehlermeldung "Unknown variable"

  • GM 8
  • Erhalte Fehlermeldung "Unknown variable"

    Ich erhalte beim starten des Spiels eine seltsame Fehlermeldung

    ERROR in
    action number 1
    of Create Event
    for object test2:

    Error in code at line 1:
    if global.produktion=1 and global.filmnr=0 then {global.film = global.film + global.filma}
    ^
    at position 35: Unknown variable filmnr

    Allerding habe ich eine Variable "global.filmnr=0" erstellt und in Hauptfenster gelegt.
    Gibt es sonst adhoc noch irgend welche Fehlerquellen?
  • Könnte eventuell daran liegen dass du beim prüfen nur ein " = " benutzt. (weiss nicht wie tollerant der GM in diesem Bezug ist.)

    Grundsätzlich ist es so dass das "=" für zuweisungen (ergo Variablendefinition) steht.
    Für das prüfen verwendet man "==".

    Also:

    GML-Quellcode

    1. if global.produktion==1 and global.filmnr==0 then {global.film = global.film + global.filma}


    Hast du die Variable auch im selben Objekt definiert?
  • Ja, es ist erforderlich, da der GM Objektorientiert ist.

    Wenn du z.B: in obj_player die Variable "Munition" prüfen willst, die im obj_controller definiert wurde, musst du beim Prüfen vor der Variable den Instanznamen angeben , der die entsprechende Variable enthällt..

    also z.B:
    im obj_player:

    GML-Quellcode

    1. if (obj_controller.Munition == 0){



    Bei Globalen Variablen sollte dies aber nicht nötig sein.
  • mhvox schrieb:

    Nein, im selben Objekt habe ich die nicht...ist das erforderlich???

    Erforderlich nicht, aber falls dieses andere Objekt erst nach dem Objekt erstellt wird, in dem die Abfrage stattfindet, kommt es zu diesem Problem. (Auch wenn beide Objekte "gleichzeitig" erstellt werden gibt es im GM intern noch eine Reihenfolge)
    Grundsätzlich gilt: Was im Room-Editor als erstes platziert wird, wird im Spiel als erstes erstellt.

    © 2008 by Teamgrill Productions
  • Das Problem ist: wenn du die Variable noch nicht erstellt hast, dann kann auch nicht gefragt werden, was für einen Wert sie hat.

    Bei global.Irgendwas = 1234 wird der Variablen der Wert zugewiesen / sie erstellt, falls sie noch nicht existiert.

    Wenn du dagegen global.Irgendwas += 5 oder if global.Irgendwas = 3 schreibst, und sie noch nicht existiert, kommt es logischerweise zu einem Fehler. Um das zu umgehen, kann man in den Gameeinstellungen nicht - initialisierte Variablen den Wert 0 zuweisen.
  • Chaos Creator schrieb:

    Wenn du dagegen global.Irgendwas += 5 oder if global.Irgendwas = 3 schreibst, und sie noch nicht existiert, kommt es logischerweise zu einem Fehler. Um das zu umgehen, kann man in den Gameeinstellungen nicht - initialisierte Variablen den Wert 0 zuweisen.


    Jah, kann man - aber das ist eine ziemlich eklige und unperformante Lösungsmethode. Sowas lässt sich viel einfacher handhaben, wenn man beim Coden die folgenden Regeln beachtet:

    • foo<operator>a löst einen "Unknown Variable"-Fehler aus, wenn foo nicht initialisiert ist (zwischen foo und a kann man die Rechenoperatoren wie +=, *= und << und die logischen Operatoren wie &&, || und ^^ einsetzen).
    • Der Relationsoperator foo.a löst den selben Fehler aus, wenn entweder das Objekt "foo" undefiniert ist (wenn man z.B. die ID einer bereits zerstörten Instanz benutzt) oder für foo keine lokale Variable a exisitert.
      Ausnahme: foo.a=b - denn damit wird a in foo initialisiert, egal wann und von wo dieser Code ausgeführt wird - siehe übernächster Punkt.
    • Für if-, switch-, while- und do-until-foo-Konstrukte gilt ebenfalls: Variable foo nicht initialisiert -> Fehler.
    • Keinen Fehler lösen sämtliche Operationen aus, in denen foo der Wert a zugewiesen wird. Mit anderen Worten: foo=a, wobei a alles sein kann. Und hierfür ist es auch völlig egal, ob man diesen Befehl ins Create-Event des entsprechenden Objektes setzt oder ihn im Linke-Maustaste-Event eines anderen Objektes ausführt.
    • Ebenfalls wird kein Fehler ausgelöst, wenn du zum Einleiten einer for-Schleife eine vorher unbekannte Variable benutzt. Denn im ersten Statement des Schleifenkopfes wird ja der neuen Variablen gleich ein Wert zugewiesen. Damit ist sie initialisiert, alles in Butter, Abfrage kann starten.
      Damit ergibt sich der letzte Punkt:
    • Jede Variable, die man nicht schon mit var oder globalvar initialisiert hat, wird automatisch initialisiert, sobald ihr zum ersten Mal ein Wert zugewiesen wird.


    Das ist im Prinzip schon alles, was man bedenken muss - wenn man diese Bedinungen erstmal verstanden hat, fällt einem das "ordentliche" Coden um einiges leichter. Diese "Treat uninitialized variables as 0"-Methode sollte man alleine schon deswegen nicht anwenden, weil sie beim Debuggen zu komplett irrsinnigen Fehlermeldungen führen kann, bei denen man sich erstmal nen Wolf nach dem Grund sucht. Denk dir z.B. mal einen Gegner, der in einem Alarm-Event (also in regelmäßigen Zeitabständen) eine Kugel in Richtung Spieler schießen will. Der Code im Alarm-Event sähe dann zum Beispiel so aus:

    GML-Quellcode

    1. meinekugel=instance_create(x,y,kugel);
    2. meinekugel.speed=4;
    3. meinekugel.direction=point_direction(x,y,spieler.x,spieler.y);

    An und für sich ja nichts kompliziertes, funktioniert auch einwandfrei, alles in Butter.
    ...bis das Spielerobjekt (zum Beispiel weil es keine HP mehr hat) zerstört wird.
    Denn dann gibt es plötzlich kein spieler.x und spieler.y mehr. Normalerweise würde der GM an dieser Stelle mit der Fehlermeldung "Unknown variable: spieler" abbrechen. Wenn er jetzt aber unbekannte Variablen als 0 ansieht, hauen einfach alle erstellten Kugeln in Richtung des Punktes (0;0) ab, also nach oben links.
    Wenn du genau nachvollziehen kannst, warum das passiert, ist das ja kein Ding - aber lass das Projekt mal sehr umfangreich werden und lass es dann vielleicht mal aus Zeitknappheit 3, 4 Monate stehen. Ich garantiere dir, dass du ernsthafte Schwierigkeiten damit kriegen wirst, bestimmte Verhaltensweisen deiner Objekte nachvollziehen zu können.

    Wenn du von vorneherein richtig rangehst, kannst du gleich für so viele Fälle wie möglich vorausplanen. Zum Beispiel könnte der Code von oben auch so aussehen:

    GML-Quellcode

    1. if instance_exists(spieler){
    2. meinekugel=instance_create(x,y,kugel);
    3. meinekugel.speed=4;
    4. meinekugel.direction=point_direction(x,y,spieler.x,spieler.y);
    5. }

    -> Wenn der Spieler noch existiert, schießen - ansonsten eben nicht. Du siehst: Nur eine einzige Abfrage mehr und du kannst auf die "Treat uninitialized Variables as 0"-Methode verzichten.

    Noch kurz ein weiterer Grund, warum man diese Methode nicht verwenden sollte: Denk dir mal eine for-Schleife, die folgendermaßen aussieht:

    GML-Quellcode

    1. for(1;foo>1;foo*=2){
    2. // Viel Code
    3. }

    Und jetzt stell dir vor, foo würde, weil sie nicht initialisiert ist, als 0 betrachtet.
    Die Schleife bricht erst ab, wenn foo größer als 1 ist. Aber weil foo nicht durch Addition, sondern durch Multiplikation erhöht wird, ergibt sich da ein kleines Problem. 2*0 ist schließlich immer noch 0. 'Ne hübsche Endlosschleife.
    Würde der GM hier mit "Unknown Variable: foo" abbrechen, wäre die Sache um einiges klarer und der Fehler ließe sich viel schneller finden.



    So, lange Rede, kurzer Sinn: Mach dir nicht ins Hemd, wenn dein Code Fehlermeldungen generiert. Es ist immer besser, eine Fehlermeldung zu kriegen, als merkwürdige Rückgabewerte irgendwelcher Funktionen. Umso mehr, da die Fehlermeldungen des GM ziemlich, ziemlich genau beschreiben, wann und wo der Fehler aufgetreten ist. Wenn dagegen irgendwo plötzlich durch Null geteilt wird, weil die Variable, durch die du teilst, unbekannt ist und deswegen als 0 betrachtet wird, ist das nicht sofort offensichtlich. Könnte ja immerhin auch daran liegen, dass ihr irgendwo der Wert 0 per Code zugewiesen wird. Das heißt, du hast da mehrere Möglichkeiten für den Grund deines Fehlers. Viel Spaß beim Suchen. :p
  • Benutzer online 1

    1 Besucher