Error in function real() beim Laden von Levels (universelles Levelspeicherformat)

  • GM 8

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Error in function real() beim Laden von Levels (universelles Levelspeicherformat)

    Hallo Leute,

    die Ferien stehen vor der Tür, und damit ist es höchste Zeit alte Bugs zu entfernen die einem schon länger quälen.
    Es geht um folgendes:

    Ich habe einen Levelspeichermechanismus entwickelt, mit dem ich (theoretisch) abwärtskompatible Maps speichern kann.
    D.h. wenn man sie später mit einer neueren Version des Spiels öffnet, liest er immer noch korrekt alle Positionen und/oder Variablen der einzelnen Objekte aus.
    Ich habe das so gelöst, dass im Levelspeicherskript zuerst alle globalen Variablen, bzw. für das gesamte Level relevanten Variablen abgespeichert werden,
    und dann bei den Objekten immer der object_index an erster Stelle steht, und danach alle lokalen Variablen, die zum Objekt dazugeladen werden sollen.
    Das Ganze ist in mehreren do-until-Schleifen verpackt mit Wörtern wie "start" und "end" um die Schleifen einzugrenzen.

    Ein gespeichertes Level (in diesem Fall nur mit 2 Objekten) sieht dann so aus:

    Spoiler anzeigen

    global_start //beginn der ersten schleife
    filename
    Maps/testlevel.spr
    rmheight
    10
    rmwidth
    1
    global_end //ende der ersten schleife
    blocks_start //beginn der zweiten schleife
    199 //object_index des ersten objektes
    start //beginn der dritten schleife, welche in der zweiten schleife ist
    x
    0
    y
    128
    end //ende der dritten schleife, welche in der zweiten schleife ist
    200 //object_index des zweiten objektes
    start //beginn der dritten schleife (für das 2. objekt), welche in der zweiten schleife ist
    x
    128
    y
    128
    end //ende der dritten schleife (vom zweiten objekt), welche in der zweiten schleife ist
    blocks_end //ende der zweiten schleife


    Mit dem Abspeichern der Levels funktioniert alles, nur beim Laden gibt es ein Problem:

    ___________________________________________
    ERROR in
    action number 2
    of Draw Event
    for object obj_controller_editor:

    Error in function real().


    Das Seltsame dabei ist nur, dass im besagten Event, sowohl kein Skript, als auch irgendein file_text-Befehl aufgerufen wird.
    Wenn der GM etwas präzisere Error-Reports schreiben würde, würde das vieles erleichtern ...

    Wenn ich jetzt auf "Ignore" klicke, dann hängt sich das Spiel auf,
    also meine Vermutung ist, dass irgendwas mit den Schleifen nicht stimmt, oder mit der Konvertierung von Reals oder Strings.

    Könnt ihr euch irgendeinen Reim darauf machen? Das Problem verhindert nun schon seit 3 Wochen ca. die Weiterentwicklung des Spiels,
    weil sehr viel auf diesem Levelspeichermechanismus aufbaut ...
    Ich wäre sehr sehr dankbar wenn sich jemand mit dem Problem ordentlich befassen würde.
    Wer mir hier am besten weiterhilft bekommt einen Ehreneintrag in den Credits des Spiels! ;-)

    Hier noch das Problemscriptchen:

    Spoiler anzeigen

    GML-Quellcode

    1. //lvl_load(filename)
    2. var file, currentobject;
    3. stringcheckhead = ""
    4. stringcheckheadreal = 0
    5. stringcheckcontent = ""
    6. //file name
    7. filename = argument0
    8. if (filename == "")
    9. exit;
    10. if (filename_ext(filename) != ".spr")
    11. filename += ".spr";
    12. if file_exists(filename)
    13. {
    14. //delete all objects
    15. instance_activate_all()
    16. file = file_text_open_read(filename)
    17. with (all)
    18. {
    19. if object_index != obj_controller and object_index != obj_contr_play and object_index != obj_contr_test_rm13 and object_index != obj_controller_editor and object_index != obj_controller_globvars and object_index != obj_contr_editorviewsnap
    20. instance_destroy()
    21. }
    22. //global
    23. //where is "global_start"
    24. do
    25. {
    26. stringcheckhead = file_text_read_string(file)
    27. file_text_readln(file)
    28. }
    29. until (stringcheckhead == "global_start")
    30. //global
    31. do
    32. {
    33. stringcheckhead = file_text_read_string(file)
    34. if stringcheckhead != "global_end"
    35. {
    36. file_text_readln(file)
    37. stringcheckcontent = file_text_read_string(file)
    38. if string_isdigits(stringcheckcontent) and not string_isletters(stringcheckcontent)
    39. variable_local_set(stringcheckhead,real(stringcheckcontent))
    40. else
    41. variable_local_set(stringcheckhead,stringcheckcontent)
    42. }
    43. file_text_readln(file)
    44. }
    45. until (stringcheckhead == "global_end");
    46. //where is "blocks_start"
    47. do
    48. {
    49. stringcheckhead = file_text_read_string(file)
    50. file_text_readln(file)
    51. }
    52. until (stringcheckhead == "blocks_start")
    53. //blocks
    54. do
    55. {
    56. if stringcheckhead != "start"
    57. {
    58. stringcheckhead = file_text_read_string(file) //object_index lesen
    59. stringcheckheadreal = real(stringcheckhead)
    60. currentobject = instance_create(0,0,stringcheckheadreal)
    61. file_text_readln(file)
    62. stringcheckhead = file_text_read_string(file) //"start" lesen
    63. file_text_readln(file)
    64. }
    65. if stringcheckhead == "start"
    66. {
    67. do
    68. {
    69. file_text_readln(file)
    70. stringcheckhead = file_text_read_string(file) //variablennamen lesen
    71. objektvariable = stringcheckhead
    72. if stringcheckhead != "end"
    73. {
    74. file_text_readln(file)
    75. stringcheckcontent = file_text_read_string(file)
    76. if string_isdigits(stringcheckcontent) and not string_isletters(stringcheckcontent)
    77. {
    78. with (currentobject)
    79. {
    80. variable_local_set(stringcheckhead,real(stringcheckcontent))
    81. }
    82. }
    83. else
    84. {
    85. with (currentobject)
    86. {
    87. variable_local_set(stringcheckhead,stringcheckcontent)
    88. }
    89. }
    90. }
    91. file_text_readln(file)
    92. }
    93. until (stringcheckhead == "end")
    94. }
    95. else
    96. {
    97. do //do until stringcheckhead = "start"
    98. {
    99. stringcheckhead = file_text_read_string(file) //"start" lesen
    100. file_text_readln(file)
    101. }
    102. until (stringcheckhead == "start")
    103. }
    104. }
    105. until (stringcheckhead == "blocks_end");
    106. //closing file at the end
    107. file_text_close(file)
    108. }
    109. //correcting room dimensions
    110. rmheight = rmheight*256
    111. rmwidth = rmwidth*1280
    112. if rmheight != room_height or rmwidth != room_width
    113. {
    114. BASS_ChannelStop(global.hstream)
    115. if room == editor_11 or room == editor_12
    116. lvl_save("Maps/temp.spr")
    117. if room == editor_11 //editorroom 1
    118. {
    119. room_set_height(editor_12,rmheight)
    120. room_set_width(editor_12,rmwidth)
    121. room_set_height(editortest_13,rmheight)
    122. room_set_width(editortest_13,rmwidth)
    123. room_goto(editor_12)
    124. }
    125. if room = editor_12 //editorroom 2
    126. {
    127. room_set_height(editor_11,rmheight)
    128. room_set_width(editor_11,rmwidth)
    129. room_set_height(editortest_13,rmheight)
    130. room_set_width(editortest_13,rmwidth)
    131. room_goto(editor_11)
    132. }
    133. //room 13 = testing room
    134. if room = playlevel_14 //playing room 1
    135. {
    136. room_set_height(playlevel_15,rmheight)
    137. room_set_width(playlevel_15,rmwidth)
    138. room_goto(playlevel_15)
    139. }
    140. if room = playlevel_15 //playing room 2
    141. {
    142. room_set_height(playlevel_14,rmheight)
    143. room_set_width(playlevel_14,rmwidth)
    144. room_goto(playlevel_14)
    145. }
    146. }
    Alles anzeigen
  • Also die einzige Stelle wo der Fehler auftreten könnte ist in dem Bereich:

    GML-Quellcode

    1. if stringcheckhead != "start"
    2. {
    3. stringcheckhead = file_text_read_string(file) //object_index lesen
    4. stringcheckheadreal = real(stringcheckhead)
    5. currentobject = instance_create(0,0,stringcheckheadreal)


    Wieso prüfst du hier nicht auch nach ob isdigits rue ist, also nur Zahlen ausgelesen wurden?
    Lass dir mal mit show_message anzeigen was der real() Funktion übergeben wird bevor der Fehler auftritt.

    Willst du auf diese Drachen und -eier klicken?
    Sie werden sich freuen ;)
  • Deine Mühen in Ehren, aber der Ansatz hat einige gefährliche Mängel:
    1. Er mag abwärtskompatibel sein, aber er ist nicht aufwärtskompatibel. Die variable_-Funktionen fehlen in Studio.
    2. Dritte könnten mit so einem Levelformat viele Probleme verursachen, schon indem sie Teile versehentlich löschen und somit das Spiel zum Absturz bringen.
    3. Wirklich universell ist das Format auch nicht (und das ist auch nahezu unmöglich bzw. wäre nicht praktikabel), da du nicht alle Optionen des Room-Editors abspeicherst.


    Nun aber zu deinem Problem:
    Schreibe eine eigene Real-Funktion, die zunächst untersucht, ob der String überhaupt eine Nummer beinhaltet. Wenn ich mich recht entsinne, wirft die Funktion schon bei einem String wie " " einen Fehler. Ich weiß ehrlich gesagt nicht, ob sich die Implementierung dieser Funktion in Studio gebessert hat, aber sie ist ein echtes Problemkind und man sollte von ihr nach Möglichkeit die Finger lassen. Die read und write Befehle der Datenstrukturen bieten sich da eher an.

    Da du du sowieso den Standard-GM benutzt: Warum nicht einfach diverse Maps/Listen anlegen? Jeweils eine für object_index, x, y, und so weiter. Dann packst du nur noch die paar ds_map_write-Strings in die Dateien.
    Dieser Ansatz hat auch eingie Probleme, schützt dich aber vor real() und anderen Problemen.
  • Danke für eure Antworten!

    Ich hab das jetzt komplett anders gelöst, und zwar teilweise so, wie ich es vorher gehabt hatte.
    Zuerst werden die Variablen ganz normal hintereinander, und je nach Kriterium übereinander abgespeichert.
    Danach kommen die Objekte und zwar in etwa so:

    object_index
    x y image_index image speed image_angle

    Beim Laden werden die Objekte dann anhand des object_index erstellt und die Variablen darunter zugewiesen.

    Es ist jetzt zwar dadurch weniger universell, aber wenigstens kann ich jederzeit neue Blöcke in neuen Versionen
    des Spiels implementieren. Wenn es neue Variablen geben sollte, müsste ich halt einen Converter für alte Maps
    schreiben.
    Ich werde mich mal später wieder um ein etwas universelleres Format kümmern,
    aber derzeit habe ich 3 große Projekte die simultan in Entwicklung sind, und es geht sowieso zu wenig weiter.^^

    Deine Mühen in Ehren, aber der Ansatz hat einige gefährliche Mängel:
    Er mag abwärtskompatibel sein, aber er ist nicht aufwärtskompatibel. Die variable_-Funktionen fehlen in Studio.


    Das war jetzt auch ziemlich ausschlaggebend, dass ich mein System geändert habe, denn ich habe tatsächlich vor,
    das Spiel (was schon seit langem in GM 8.1 in Entwicklung ist) für Studio zu portieren.

    Da du du sowieso den Standard-GM benutzt: Warum nicht einfach diverse Maps/Listen anlegen? Jeweils eine für object_index, x, y, und so weiter. Dann packst du nur noch die paar ds_map_write-Strings in die Dateien.
    Dieser Ansatz hat auch eingie Probleme, schützt dich aber vor real() und anderen Problemen.


    Mit Maps und Listen habe ich noch zu wenig Erfahrung, momentan reicht mein aktuelles System aus denke ich, aber ich sollte mir das mal
    in nächster Zeit anschauen, dann überdenke ich mein Map-Speichersystem.

    Wieso prüfst du hier nicht auch nach ob isdigits rue ist, also nur Zahlen ausgelesen wurden?
    Lass dir mal mit show_message anzeigen was der real() Funktion übergeben wird bevor der Fehler auftritt.


    Es sind dann auch noch andere Probleme aufgetreten, und aus den Gründen die MewX genannt hat lasse ich es erst mal,
    aber danke für deine Hilfestellung.
    Du bist hier mitunter einer der schnellsten der auf Probleme antwortet, das finde ich ziemlich cool!