Objekte nacheinander zerstören

  • GM 8
  • Objekte nacheinander zerstören

    Hallo,

    ich habe da mal eine Frage. Bin inzwischen so weit, dass ich kein Drag- und Drop mehr benutze, sondern nur Codes, aber sehr viel weiter eben noch nicht. Zum Problem:
    Wenn die Gegner-Objekte zerstört werden, steht da

    GML-Quellcode

    1. with (obj_gegner) instance_destroy()


    bzw. könnte ich auch position_destroy schreiben. Das hat zur Folge, dass es "plöpp" macht und alle Gegner sind weg. Ich möchte aber, dass diese nacheinander verschwinden, also zuerst nur einer, wenn der weg ist (und seine Animation beendet), der zweite usw. Habe leider keine Ahnung, wie ich das angehen soll. Zumal ich ja vorher auch keinen blassen Schimmer habe, wieviele Gegner zu diesem Zeitpunkt im Spiel gerade anwesend sein werden.

    Kann mir bitte jemand sagen, wie ich das bewerkstelligen kann, dass die Gegner nacheinander zerstört werden?

    Danke,
    CB
  • Du könntest dafür ds_stacks verwenden. Stacks sind eine von vielen sehr praktischen Datenstrukturen.


    A stack data structure is a so called last-in-first-out (LIFO) structure. You can push values onto a stack and the remove them again by popping them from the stack, and the value that was pushed on the stack most recently is the first to be popped from it again (just think of a stack of coins, where each coin that you add has to be removed again first before you can get to the rest of the coins beneath). Stacks are often used when there are interrupts to handle, or when having recursive functions, or even when constructing a rudimentary AI for your games.

    Das eben Zitierte aus der Hilfe bedeutet einfach, dass man sich Stacks wie Stapel vorstellen kann (stack = Stapel auf Englisch),
    d.h. gibt man einen Wert hinzu (ds_stack_push(id,val)), kommt der ganz oben auf den Stapel hin.
    Nimmt man einen weg (ds_stack_pop(id)) dann wird der oberste Wert wieder genommen -> LIFO (last in first out)

    Also, du könntest jedes mal wenn klar ist, dass die Instanz zerstört werden soll die id der Instanz in den Stack speichern:

    with (obj_gegner) ds_stack_push(stack_destroying,id) - achte darauf, dass wenn der Stack nicht global ist (Normalfall), dass du den Punkt-Operator brauchst
    (z.B. wenn du den Befehl in einem Controllerobjekt ausführst dann entweder: ds_stack_push(obj_controller.stack_destroying,id) oder ds_stack_push(other.stack_destroying,id)
    sonst wird der Stack nicht erkannt.)

    Wenn wir diesen Schritt jetzt haben, füllt sich das Stack immer brav mit den ID's der Instanzen die es zu zerstören gilt.

    Vorher musst du den Stack natürlich initialisieren (z.B. im Create-Event vom Controllerobjekt):
    stack_destroying = ds_stack_create()

    Achte darauf, dass du den Stack wieder löscht wenn du ihn nicht mehr brauchst (zumindest am Ende des Spiels oder Rooms),
    ansonsten wird er nämlich nicht überschrieben, sondern existiert neben dem oder die alten Stack(s).


    GML-Quellcode

    1. if ds_exists(stack_destroying,ds_type_stack) then ds_stack_destroy(stack_destroying)

    Jetzt müssen wir nur noch schauen, dass sich der Stack automatisch "entleert" und die Instanzen, die durch die gespeicherten ID's
    repräsentiert sind, gelöscht werden:

    Im STEP-Event vom Controllerobjekt:

    GML-Quellcode

    1. if not ds_stack_empty(stack_destroying)
    2. {
    3. with ds_stack_pop(stack_destroying) instance_destroy()
    4. }

    Das sollte es gewesen sein. Schaut komplizierter aus als es ist.

    Anmerkung:
    Mit der Methode wird das jedem Step (Sekunde/roomspeed) ausgeführt.
    Wenn du z.B. nur jede halbe Sekunde den Code ausführen lassen willst, dann könntest du das Gleiche mit einem Alarm-Event machen
    und den Alarm auf z.B. 30 stellen wenn der Room-Speed 60 ist ...

    Counter-Bike schrieb:

    wenn der weg ist (und seine Animation beendet), der zweite usw.

    ... oder das Ganze eben so einstellen, dass wenn die Animation z.B. 12 Steps braucht, es alle 13 Steps durchgeführt wird.

    Ich hoffe der Roman den ich geschrieben habe hat dir jetzt geholfen und dich nicht verwirrt.^^
  • Uih. Danke erst mal für die ausführliche Antwort! Ich habe alles kopiert und werde versuchen, es umzusetzen, fürchte jedoch, dass das noch zu schwierig für mich sein könnte. Vielleicht sieht es aber auch nur schwierig aus... Man wird sehen.

    Eine Nachfrage noch: wenn es denn nicht global sein soll - gibt es eine Möglichkeit, zu überprüfen, ob der Stack noch besteht oder bereits gelöscht wurde?

    Also, thx noch mal für Deine Mühe,
    CB

    Edit, einen Tag später:
    Ähm, er kennt den Befehl "ds_exists" bei

    GML-Quellcode

    1. if ds_exists(stack_destroying,ds_type_stack) then ds_stack_destroy(stack_destroying)


    nicht. Leider gibt es auch "ds_stack_exists" oder etwas in dieser Art nicht. Wie kann man dann einen Stack noch zerstören? Scheint ja nicht ganz unwichtig zu sein... :D
    CB

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Counter-Bike ()

  • Counter-Bike schrieb:

    Edit, einen Tag später:
    Ähm, er kennt den Befehl "ds_exists" bei

    GML-Quellcode

    1. if ds_exists(stack_destroying,ds_type_stack) then ds_stack_destroy(stack_destroying)

    nicht. Leider gibt es auch "ds_stack_exists" oder etwas in dieser Art nicht. Wie kann man dann einen Stack noch zerstören? Scheint ja nicht ganz unwichtig zu sein... :D

    Wie es aussieht benutzt du eine ältere Version vom Gamemaker.
    Ich habe bei mir Gamemaker-Studio 1.2 installiert, und da ist dieser Befehl vorhanden.
    Scheinbar fehlt die Abfrage in den älteren Versionen leider, was sich z.B. hier zeigt. :/

    Da musst du leider herumprobieren. Eventuell sind Arrays in dem Fall eher das Richtige, da diese in Gamemaker 8 noch schneller als in GM-Studio waren.
    (Mittlerweile hat sich das umgedreht. Datenstrukturen sind in GM-Studio deutlich schneller geworden.)
    Heute habe ich leider keine Zeit mich damit auseinanderzusetzen, aber du erhältst morgen Abend von mir eine Alternativlösung.
    Gib mir nur bitte bekannt welche GM-Version du benützt, oder stelle es in deinem Profilmenü ein (unter "Profil bearbeiten" in der "Persönlichen Box" links).
    Macht generell Sinn, wie man an dieser Problemstellung sieht.^^
    Thx.

    EDIT/

    Okay, hier folgt eine alternative Lösung mit Arrays:

    Im Create-Event vom Controller-Objekt müssen wir das Array erst mal erstellen.
    Der Nachteil hierbei im Vergleich zu Stacks, oder auch einigen anderen Datenstrukturen, ist dass man die Größe des Arrays wissen muss.
    Zwar nicht zwangsläufig, aber es macht das Hinzufügen von Werten schneller:

    Create-Event (obj_controller):

    GML-Quellcode

    1. for (i=99; i>=0; i-=1)
    2. {
    3. array_destroying[i] = -1
    4. }
    5. //99 ist in dem Fall die maximale Anzahl an Objekten die behandelt wird - diesen Wert kannst du natürlich an deine Bedürfnisse anpassen.
    6. //Die For-Schleife rückwärts zu initialisieren ist schneller, daher habe ich das hier so gemacht.
    7. //Den Wert -1 verwende ich in dem Fall als "leeren" Wert, also wenn eine Position des Arrays leer ist steht -1 an der Stelle.


    Arrays muss man übrigens nicht von Hand löschen. Die werden gelöscht wenn das Objekt welches den Array als lokale Variable beinhaltet, einfach nicht mehr existiert.

    Das Hinzufügen von Instanz-ID's machen wir wie folgt:

    Im Step-Event vom Objekt das gelöscht werden soll, an der Stelle an der klar ist, dass es gelöscht werden soll:

    GML-Quellcode

    1. for (i=0; i<99; i+=1)
    2. {
    3. if obj_controller.array_destroying[i] == -1 //Nachdem das Array lokal ist, ist der Punkt-Operator notwendig.
    4. {
    5. obj_controller.array_destroying[i] = id
    6. break //unterbricht die Schleife nach dem ersten Eintrag, da das Array sonst sofort gefüllt wird.
    7. }
    8. }


    Nun das Ausleseverfahren im Controllerobjekt (Step-Event):

    GML-Quellcode

    1. for (i=0; i<99; i+=1)
    2. {
    3. if array_destroying[i] != -1 //Abfrage, ob die Position des Arrays besetzt ist / nicht -1 beinhaltet
    4. {
    5. with array_destroying[i] //with - verwendet die ID die in der aktuellen Position des Arrays gespeichert ist
    6. {
    7. instance_destroy()
    8. }
    9. array_destroying[i] = -1 //Position des Arrays auf "leer" setzen
    10. break //da ansonsten sofort alle ID's aus der Schleife ausgelesen werden, was den Sinn zunichte machen würde.
    11. }
    12. }
    Alles anzeigen


    Anstatt dem Step-Event kannst du natürlich auch hier Alarme, Timelines, o.ä. benutzen um das Timing der Objektzerstörung anzupassen.

    Ich hoffe das war hilfreich. Getestet habe ich das Ganze jetzt nicht, sollte aber (hoffentlich) funktionieren.

    /EDIT 2: Kleine Korrektur vorgenommen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von RLP ()