Objekte auf zufälligen Positionen in einem Raster spawnen

  • Objekte auf zufälligen Positionen in einem Raster spawnen

    Ein Hallo in die Runde!

    In dem Spiel an dem ich gerade sitze, möchte ich auf einem 5x5 Raster nach und nach Objekte spawnen. Ich konnte hierzu keine Anleitung finden, daher meine Fragen:

    - sind DS Grids die beste Möglichkeit oder gibt es bessere Alternativen?

    Quellcode

    1. ​grid = ds_grid_create(5, 5);
    2. ds_grid_set_region (grid, 0, 0, 4, 4, -1);

    - wie lege ich die Größe(Pixel) der einzelnen Zellen fest?
    - wie wähle ich im Zufallsprinzip eine der Zellen aus?
    - wie überprüfe ich vor jedem Spawnvorgang, ob die ausgewählte Zelle frei ist?

    Ich bin noch ein GamerMaker Rookie und erst mit den Basics vertraut, daher verzeiht die simplen Fragen.

    Über eine hilfreiche Antwort würde ich mich sehr freuen.
  • Galan schrieb:



    - sind DS Grids die beste Möglichkeit oder gibt es bessere Alternativen?

    Quellcode

    1. grid = ds_grid_create(5, 5);
    2. ds_grid_set_region (grid, 0, 0, 4, 4, -1);

    - wie lege ich die Größe(Pixel) der einzelnen Zellen fest?
    - wie wähle ich im Zufallsprinzip eine der Zellen aus?
    - wie überprüfe ich vor jedem Spawnvorgang, ob die ausgewählte Zelle frei ist?



    Hi,
    Ein ds_grid ist eine gute Wahl für sowas.
    In einem Grid gibts nicht wirklich Pixel, sondern Koordinaten.
    Bei einem 5 x 5 grid kannst du eine Zufallszahl für jede Achse wählen z.B:

    GML-Quellcode

    1. zufall_x = random(5);
    2. zufall_y = random(5);
    3. //dann muss man nur noch die position auswählen
    4. var zufallsposition = ds_grid_get(grid, zufall_x, zufall_y);
    5. // die erstellte lokale variable (zufallsposition) enthält dann die zufällig gewählte Position des grids
    6. // wenn diese aber nicht frei ist, wird sie wohl nicht -1 ergeben sondern das was du ihr gesetzt hast.
    7. if (zufallsposition == -1)
    8. {
    9. // die Zelle scheint frei zu sein.
    10. // jetzt können wir etwas hineintun.
    11. // beim Spawnen des Objekts können aber nun die Koordinaten skaliert werden.
    12. ds_grid_set(grid, zufall_x, zufall_y, instance_create(zufall_x * 16, zufall_y * 16, objekt);
    13. // Ich habe jetzt als Skalierung 16 genommen.
    14. // wenn zufall_x = 3, zufall_y = 1 ist und die zelle an dieser Position frei ist, wird dort die ID des Objekts gespeichert und zugleich das Objekt an Position x = 48 und y = 16 im Raum gespawnt.
    15. }
    16. else
    17. {
    18. // da scheint nicht -1 drin zu stehen, die Zelle ist nicht frei
    19. // den Vorgang wiederholen...
    20. // ... bis irgendwann mal eine Position gefunden wird welche frei ist.
    21. }
    Alles anzeigen


    Hoffe das ist verständlich formuliert.
  • Die Objekte werden so nicht auf einer der 25 möglichen Positionen kreiert, sondern wahrlos innerhalb des erweiterten Gridbereichs (siehe verlinkter Screenshot).

    Eigentlich sollte bei jedem Durchlauf eine der 25 Gridpositionen zufällig ausgewählt werden und diese wird dann mit dem Muliplikator multipliziert. Somit hätte ich immer noch 25 feste Positionen, wobei nur die Größe der einzellnen Zelle erweitert wurde. EIne Zelle = eine mögliche Position für ein Obejekt.
    Wenn ich deinen Code richtig verstehe, tut er eigentlich genau das. Bei einem Durchlauf mit deinem Code scheint GameMaker jedoch das 5er Grid zu vernachlässigen und innerhalb des Grids mal Multiplikator (in unserem Beispiel 5* 16 = 80px Höhe und Breite) aus 80x80 mögliche Positionen zu wählen.
  • Galan schrieb:

    Die Objekte werden so nicht auf einer der 25 möglichen Positionen kreiert, sondern wahrlos innerhalb des erweiterten Gridbereichs (siehe verlinkter Screenshot).

    Eigentlich sollte bei jedem Durchlauf eine der 25 Gridpositionen zufällig ausgewählt werden und diese wird dann mit dem Muliplikator multipliziert. Somit hätte ich immer noch 25 feste Positionen, wobei nur die Größe der einzellnen Zelle erweitert wurde. EIne Zelle = eine mögliche Position für ein Obejekt.
    Wenn ich deinen Code richtig verstehe, tut er eigentlich genau das. Bei einem Durchlauf mit deinem Code scheint GameMaker jedoch das 5er Grid zu vernachlässigen und innerhalb des Grids mal Multiplikator (in unserem Beispiel 5* 16 = 80px Höhe und Breite) aus 80x80 mögliche Positionen zu wählen.


    Hab den Screenshot im dropbox zwar nicht öffnen können, aber ich versuch trotzdem dir helfen:
    In dem Grid das du erstellt hast sind lediglich nur die IDs von den Objekten. Die Objekte werden aber größtenteils außerhalb gespawnt weil wir die Positionen mit 16 multipliziert haben.
    Ich bin mir nicht ganz sicher wie dein Projekt aufgebaut ist aber da gibts 2 Möglichkeiten:
    1. Lass die skalierung weg.
    2. Skalier alles andere auch mit 16.
  • Galan schrieb:

    Ich versuchs nochmal mit einem WeTransfer Download Link:
    wetransfer.com/downloads/26dc2…3acc20170329211032/e24249

    Habe versucht auch alles andere mit zu skalieren, hat das Ergebnis jedoch nicht erkennbar verändert.


    Hab kurz selber das Projekt versucht aufzubauen und habe gemerkt, dass bei:

    GML-Quellcode

    1. zufall_x = random(5);
    2. zufall_y = random(5);
    3. // eigentlich dies:
    4. zufall_x = irandom(5);
    5. zufall_y = irandom(5);
    6. // stehen sollte

    Ich dachte das Positionen in einem ds_grid auch, wie in einem Array, automatisch abgerundet werden. Anscheinend ist dem nicht so.
  • Galan schrieb:

    Wenn ich jetzt wieder einzelne Objekte aus dem Grid zerstöre, schaffe ich es nicht in der jeweiligen Zelle den Basiswert -1 (leere Zelle) herzustellen.

    Ich habe es wie folgt versucht:

    Quellcode

    1. ds_grid_clear(objekt, -1);
    2. instance_destroy();


    Heisst dein grid jetzt "objekt"?
    wo genau liegt der code, ist er in den objekten?

    Naja egal,
    um eine Position im grid auf -1 umzustellen und das jeweilige Objekt zu löschen geht man so vor:

    GML-Quellcode

    1. ds_grid_set(object.grid, x/16, y/16, -1)
    2. instance_destroy();
    3. // da musst du einfach den grid des Objektes mit dem grid mit dem "punkt" Operator ansteuern und dann die skalierten x und y werte wieder umkehren damit du die Position findest.
    4. // dann muss das Objekt zerstört werden
    5. // diesen Code in dem zu zerstörenden Objekt ausführen

    um das gesamte grid zu löschen

    GML-Quellcode

    1. with (obj_cell) // der objektname der in den grids drin ist.
    2. {
    3. instance_destroy();
    4. }
    5. // jetzt nur noch den grid clearen
    6. ds_grid_clear(grid, -1);
    7. // diesen Code in dem Objekt ausführen bei dem das grid erstellt wurde.
  • Du benötigst kein ds_grid_clear um eine Zelle zurückzusetzen. Es reicht auch grid[# x, y] = wert;

    Edit:
    @Simon Gust ds_list_clear setzt alle Werte auf einen bestimmten Wert, löscht das Grid aber nicht.
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Husi012 schrieb:


    @Simon Gust ds_list_clear setzt alle Werte auf einen bestimmten Wert, löscht das Grid aber nicht.


    Technisch korrekt, wollte den grid aber auch nicht löschen das er weg ist sondern nur das alle inhalte "gelöscht" sind.

    GML-Quellcode

    1. ds_grid_destroy(grid);

    hier, der grid ist jetzt weg.
  • Wollte dich auch nur in der Ausdrucksweise korrigieren :P
    Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
    Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

    Willst du mit mir auf Discord Chatten/Quatschen?
    Meine Husi's Tutorial Reihe
  • Ich danke Euch für die schnelle Hilfe.
    Habe deinen Code ausprobiert. Da aber auf den wieder freien Zellen im Grid keine neuen Objekte kriert werden, habe ich vermutlich noch einen Fehler drin. Ich führe daher nochmal genauer auf, wo die Aktionen ausgelöst werden:

    Das ds_grid entwerfe ich im obj_game. In diesem kreiere ich in regelmäßgen Abständen über einen Alarm einen von vier unterschiedlichen Objekten (Auswahl zufällig).
    In den jeweiligen Objekten habe ich in einem Mouse Event(left pressed) den Code, welcher die jeweilige Position des Objekts im Grid wieder auf -1 setzen soll und dann das Objekt zerstört.


    Wenn ich es richtig verstehe, dann muss ich in jedem der vier Objekte das obj_game (in dem das Grid kreiert wurde) ansteuern:

    Quellcode

    1. ds_grid_set(obj_game.grid, x/16, y/16, -1)

    und oben unter "Applies to" Obejct:obj_game auswählen?
  • Galan schrieb:


    Wenn ich es richtig verstehe, dann muss ich in jedem der vier Objekte das obj_game (in dem das Grid kreiert wurde) ansteuern:

    Quellcode

    1. ds_grid_set(obj_game.grid, x/16, y/16, -1)

    und oben unter "Applies to" Obejct:obj_game auswählen?


    Rate davon ab, dass du irgendein code jemals dort unter "applies to" umstellst. Ich kann mir vorstellen das wenn man für eine Zeit ein Projekt pausiert, sich diese Einstellung nicht merkt und dann denn Fehler sucht.
    Aber mit einem "dot-operator" (.) können variablen, Datenstrukturen usw. aus anderen Objekten angesteuert werden. Wenn ich z.B. Objekt A und B habe, Objekt B hat eine Variable names "health". Das könnte ein Spieler sein oder so. Objekt A ist ein gegner. Wenn im Code von Objekt A spielerkollisionen ausgeführt werden, dann müsste man von dort aus die Variable "health" von Objekt B abziehen. Da gibt es zwei möglichkeiten:

    Quellcode

    1. objekt_B.health -= 10;

    oder

    Quellcode

    1. with (objekt_B)
    2. {
    3. health -= 10;
    4. }

    temporäre Variablen sind da die Ausnahme da sie einen anderen Scope benutzen. Diese solltest du nie so ansteuern, da man nie weiss ob sie noch existiert. Diese können direkt angesteuert werden:

    Quellcode

    1. var num = 10;
    2. with (objekt_B)
    3. {
    4. health -= num;
    5. }