Automatisierte Erstellung von Objekten

  • GM 7

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

  • Automatisierte Erstellung von Objekten

    Hallo, ich bin es wieder!

    Diesmal geht es um folgendes: Ich möchte meinen Spielern die Auswahl lassen, welche der 44 möglichen Fraktionen sie in meinem Spiel übernehmen wollen. Da ich das Programm von Anfang an auf die größtmögliche Schlankheit trimmen will, versuche ich, so oft wie möglich externe Grafiken zu laden. Für den besagten Auswahlbildschirm will ich das eben so handhaben und lade die verschiedenen Embleme nur für diesen Raum. Auch die nötigen Objekte will ich "on the fly" kreiern und habe dafür dieses Script geschrieben, das im jetzigen Zustand leider gar nichts tut:

    GML-Quellcode

    1. ox=x;oy=y;
    2. for (i=0;i<=43;i+=1){i=1datei=working_directory+"\bilder\wappen\"+global.stadt_daten[i,1]+".gif";spr_Auswahl[i]=sprite_add(datei,0, false, true, false, false, 0, 0);
    3. obj_auswahl[i]=object_add();object_set_parent(obj_auswahl[i],obj_stadt_auswahl);object_set_sprite(obj_auswahl[i],spr_Auswahl[i]);
    4. show_message(string(i)); //kontrolle
    5. obj_auswahl[i].x=ox;obj_auswahl[i].y=oy;
    6. ox=ox+35;if(floor(i/5)==i/5) //fünf Wappen pro Zeile{ oy+=35; ox=x;}


    Ich finde den Fehler (mal wieder) einfach nicht........ ?(
  • MewX schrieb:

    Objekte on-the-fly kreieren halte ich nicht wirklich für sinnvoll. Das sollte man mit schlauen Parents besser lösen können.
    Ich benutze ja ein Parentobjekt für die neuen Objekte, die nach dem Verlassen des Raums auch wieder gelöscht werden. Wenn es eine Möglichkeit gibt, noch ressourcenschonender vorzugehen, bin ich für Ideen immer offen.
    Abgesehen davon mag den zusammengestauchten Code keiner lesen.

    Ich habe hier schon zweimal gefragt, woran das liegt - ich kopiere den Code korrekt formatiert aus dem Scripteditor, nach dem Veröffentlichen des Beitrags ist er so verhunzt. Es wäre nett, wenn da jemand einen Tipp hätte, denn ich hab das Script korrigiert und wollte es der Vollständigkeit halber hier reinstellen. So macht es nur wenig Sinn.
  • Die Objekte, die jetzt anzeigt werden, erstellen die Auswahlbuttons für die 44 spielbaren Fraktionen. Der Spieler wählt aus, die erstellten Instanzen, Objekte und Sprites werden wieder gelöscht, der entsprechende Raum wird geladen und das Spiel beginnt.

    Ich benutze Opera, Firefox und Chrome - je nachdem wo ich gerade bin :) Der Fehler kam mit jedem Browser...
  • Die Variablen, die benutzt werden, sind doch fast alle die gleichen... oder nicht? Das sollte dann gar kein Problem darstellen. Wirklich Resourcen sparen tust du mit den dynamisch erstellen Objekten nicht - schließlich ist der Code, der diese erstellt, auch im Spiel drin.

    Wegen deinem Code: Mach mal nen Screenshot, wie der gleiche Code bei dir im GM aussieht.
  • @ OFFTOPIC
    Wegen deinem Code: Mach mal nen Screenshot, wie der gleiche Code bei dir im GM aussieht.
    Das problem kenne ich, das hängt mit dem Google Chrome zusammen. Es wird immer ein abstatz gelöscht. Wenn man nur einen absatzt macht (also nur in mal enter drückt) verschwindet er total. Wenn man zwei absätzte macht (also 2 mal auf enter drückt) bleibt einer übrig. Dies war übrigens der grund dazu, dass ich wieder zu FF zurückgegangen binn.

    MfG Ich
  • @Offtopic: irgendwann habe ich das schonmal jemanden geraten: Wenn du auf GM-d.de den Code strukturierst, dann solltest du das nicht mit dem Editior sondern mit dem Quellcode edtior machen (sieh Registerkarten).Da sieht man nähmlich wie der Code dann aussieht. Ich weiß aber nicht wie es mit dem einfügen ist, das sollte aber auch gehen.
  • Hier das funktionierende Script:

    GML-Quellcode

    1. ox=x;oy=y;
    2. for (i=0;i<=43;i+=1)
    3. {
    4. datei=working_directory+"\logos\"+global.daten[i,1]+".gif";
    5. spr_Auswahl[i]=sprite_add(datei,0, false, true, true, false, 0, 0);
    6. obj_auswahl[i]=object_add();
    7. object_set_parent(obj_auswahl[i],obj_stadt_auswahl);
    8. object_set_sprite(obj_auswahl[i],spr_Auswahl[i]);
    9. object_event_add(obj_auswahl[i],ev_create,ev_create,"stadt_id="+global.daten[i,0]+";");
    10. instance_create(ox,oy,obj_auswahl[i]);
    11. obj_auswahl[i].image_xscale = 0.5;
    12. obj_auswahl[i].image_yscale = 0.5;
    13. obj_auswahl[i].x=ox;
    14. obj_auswahl[i].y=oy;
    15. ox=ox+36;
    16. if(floor((i+1)/10)==(i+1)/10)
    17. {
    18. oy+=44; ox=x;
    19. }
    20. }
    Alles anzeigen


    Es funktioniert und da die Objekte und geladenen Bilder mit dem Raum-Ende-Event wieder gelöscht werden, halte ich das immer noch für eine ressourcensparende und vor allem flexible Möglichkeit. Einwänder sind trotzdem immer erwünscht.
  • Warum? Weil es funktioniert und das erwünschte Ergebnis erzielt.
    Meine Frage lautet also: Warum nicht? Mach einen Vorschlag, wie es einfacher/schneller/ressourcensparender etc. gemacht werden könnte und ich bin begeistert.
  • Aber hey da sparst du am falschen Ende.
    Schonmal an Wartungsfähigkeit gedacht?
    Wenn du deinen Code in Code packts, dann verlierst du definitiv irgendwann die Übersicht!
    Das ist auch gar nicht der Sinn von dieser Funktionalität und ich glaube kaum, dass du da Performance sparst.
    Spar lieber an Instanzen, an Sprites and whatever und mach schlaue Algorythmen, arbeite intelligent mit Parents und dann brauchst du son Scheiss nicht... echt... son Scheiss!
    "das war meine letzte flamewar PM an dich ."
  • GML-Quellcode

    1. ox=x;oy=y;
    2. for (i=0;i<=43;i+=1)
    3. {
    4. datei=working_directory+"\logos\"+global.daten[i,1]+".gif";
    5. spr_Auswahl[i]=sprite_add(datei,0, false, true, true, false, 0, 0);
    6. obj_auswahl[i]=instance_create(ox,oy,obj_stadt_auswahl);
    7. obj_auswahl[i].sprite_index=spr_Auswahl[i];
    8. obj_auswahl[i].stadt_id=global.daten[i,0];
    9. obj_auswahl[i].image_xscale = 0.5;
    10. obj_auswahl[i].image_yscale = 0.5;
    11. ox=ox+36;
    12. if(floor((i+1)/10)==(i+1)/10)
    13. {
    14. oy+=44; ox=x;
    15. }
    16. }
    Alles anzeigen


    Wär eigentlich sinnvoller. Alles was du mit unterschiedlichen Objekten machst geht auch mit einem Objekt.

    © 2008 by Teamgrill Productions
  • Sehr konstruktive Kritik. :D

    "mach schlaue Algorythmen" und "arbeite intelligent mit Parents" hätte ich mir auch selber denken können. Außerdem: Was gibt es an diesem Script zu warten? Und wenn - so lang und kompliziert ist es auch nicht.

    Ich habe 20 Zeilen Code gebraucht und von der Prozedur bleibt nichts übrig, außer ein paar lumpigen Variablen.
    Also: Wie geht es konkret besser?
  • Auch wenn ich diese Resourcensparerei nicht ganz verstehe (immerhin arbeitest du mit dem GM), so lässt sich das Ganze doch recht einfach optimieren.

    Als Beispiel:

    Du machst ein objPlayable, ein objUnit und ein objBuilding. Diese drei Objekte werden selbst im Spiel nie benutzt (außer, du machst nach objUnit und objBuilding keine weiteren Unterscheidungen mehr), sondern nur als Parents verwendet, wobei objUnit und objBuilding jeweils objPlayable als Parent haben.
    Zusätzlich dazu gibt es die lokalen Variablen faction und player, die jeweils angeben wem die Einheit gehört und welcher Fraktion sie zugehörig ist.
    Weitere Variablen für Lebenspunkte, Fähigkeiten, Schaden etc., kurz, alles was allgemeingültig ist, bekommen die natürlich im Create-Event auch und vererben diese entsprechend weiter.

    Welche Vorteile hat das bis jetzt? Einige. Möchtest du z.B. alle Einheiten eines Spielers, der verloren hat, zerstören, reicht dieser Code:

    GML-Quellcode

    1. with (objPlayable) {
    2. if (player != argument0) continue;
    3. instance_destroy();
    4. // oder andere sachen
    5. }

    Oder wenn du nur seine Gebäude vernichten willst:

    GML-Quellcode

    1. with (objBuilding) {
    2. if (player != argument0) continue;
    3. instance_destroy();
    4. // oder andere sachen
    5. }


    Das weitere Maß der Dinge sollte nun nicht die Einsparung von Resourcen sein (bringt beim Game Maker eh recht wenig, da das Ding schon etwas braucht um überhaupt zu laufen), sondern wie einfach es ist, mit der eigenen Engine umzugehen.
    Dies ist besonders bei der Frage wichtig, wie sinnvoll es noch ist, weiter zwischen Einheiten zu unterscheiden. Evtl. sind sich z.B. alle Gebäude so ähnlich, dass objBuilding reicht. Das bezeifle ich aber. Eine Möglichkeit wäre, dass ein Spieler verloren hat, wenn sein Haupthaus zerstört wurde. In diesem Fall wäre es durchaus praktisch, objTownHall als Child von objBuilding zu haben.
    Wo du da die Grenze ziehst ist dir überlassen, aber mach es so, wie es am einfachsten für dich ist. Zusammenstauchen kannst du alles noch am Ende, alles auseinander zu ziehen ist hingegen nicht so einfach.

    Beachte dabei aber auch, ob du nicht noch zusätzliche Variablen brauchst. Sobald das der Fall ist, solltest du eine weitere Unterscheidung machen. Das verlangt der gute Stil und die Übersicht. Du willst auch nicht, dass alle anderen Objekte mit einer ungenutzten Variable den Speicher zumüllen.

    Wenn man aber nun keinen Grund mehr hat, Kinderobjekte zu machen, wie unterscheidet man dann?
    Antwort: Indem man sämtliche Spielobjekte einfach über ein eigenes Script erstellt:

    GML-Quellcode

    1. // unit_create(x,y,numb,player,faction)
    2. var unit;
    3. unit = instance_create(argument0,argument1,objPlayable);
    4. unit.player = argument3;
    5. unit.faction = argument4;
    6. with (unit) {
    7. switch (argument2) {
    8. case 0: // Haupthaus (alle Völker)
    9. building_townhall(argument4); // Dieses Script setzt dann wiederum die Werte wie Lebenspunkte etc. Dann hätte man pro Gebäude ein Script mit allen Werten
    10. break;
    11. // ...
    12. case 121: // Berserker (Spezialeinheit von Volk x)
    13. unit_beserker();
    14. break;
    15. default:
    16. // Die Einheit gibts gar nicht :(
    17. break;
    18. }
    19. }
    Alles anzeigen

    Anstatt einfacher Zahlen wäre es vllt schlau, Konstanten mit entsprechendem Namen zu benutzen, auch für spätere Abfragen.


    Das ist nur eine grobe Skizze, das Ganze geht natürlich noch viel raffinierter. Aber im Allgemeinen solltest du wissen, dass in der objektorientierten Programmierung (in die einem der GM einen gewissen Einstieg geben soll) eine vernünftige Instanzierung das A und O ist. Auch wenn das im GM selbst nicht immer ganz optimal ist, wird es sich in professionellen Sprachen auszahlen.

    Und zum Schluss:
    Ich bin mir nicht ganz sicher, ob du das vielleicht missverstanden hast, deshalb erwähn ich es kurz: Dir ist schon klar, dass ein Objekt mehrere Instanzen haben kann, die trotzdem voneinander unterscheidbar sind?

    Edit: Code formatiert.
  • Ich mach das immer so, dass alle Objekte ein grosses Parent Objekt haben und alles ist komplett nach einer Hirarchie aufgebaut.
    Erstelle ich ein Objekt, regle ich alles Objekt spezifische im entsprechenden Objekt, das bewahrt absolute Übersicht.

    Ich hab dann Skripts zum Erstellen von Objekten:

    GML-Quellcode

    1. #CreateObject
    2. if (argument0 != oGameObject) return noone; //oder sowas
    3. inst = instance_create(argument1,argument2,argument0)
    4. return inst;
    5. #CreateBuilding
    6. if (argument0 != oBuilding) return noone;
    7. inst = CreateObject(argument0,argument1,argument2);
    8. inst.seite = Japaner;
    9. return inst;


    Ich kann auch einfach ein oBuilding mit CreateObject machen, oder mit CreateBuilding, egal... es kann auch ein Child von oBuilding sein:

    GML-Quellcode

    1. CreateBuilding(oBuilding,x,y)
    2. CreateBuilding(oManufactur,x,y)
    3. CreateBuilding(oSoldier,x,y) //Gibt noone (-4) zurück, da oSoldier kein Child von oBuilding ist.
    "das war meine letzte flamewar PM an dich ."
  • So: Ich habe MasterXY Verbesserungsvorschlag umgesetzt, aber noch einen echten Speicherfresser entdeckt: Das Laden von Dateien aller Art im Draw-Event. Bei mir wurden im 10-Sekundentakt 2MB zusätzlicher Arbeitsspeicher belegt. Das Laden der Dateien habe ich jetzt in den Spielstart ausgelagert und schon läuft alles auch auf alten Rechnern wie ein Uhrwerk.

    Danke nochmal an alle Beteiligten!!