Wegfindung mit den „mp_grid“ - Funktionen

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

    • Wegfindung mit den „mp_grid“ - Funktionen

      Wegfindung mit den „mp_grid“ - Funktionen


      von Fabian Nicolay a.k. „Glowing Orb“
      Version 1.0
      Benötigte GM-Version: 5.3a oder 6.0
      Bearbeitet von: Cygnus und MewX



      In diesem Tutorial geht es darum, wie man die „mp_grid“ – Funktionen zur Wegfindung verwenden kann.
      Dazu werden wir als Beispiel ein rundenbasierendes Maze-Game erstellen, in dem der Spieler das Ziel erreichen muss, während drei Gegner versuchen ihn zu fangen.

      Hierfür erstellen wir erstmal fünf Objekte inklusive Sprites (32x32 Pixel):
      • obj_Wand
      • obj_Gegner
      • obj_Spieler
      • obj_Ziel
      • obj_Controller (nicht sichtbar!)

      Nun bauen wir uns damit ein kleines Labyrinth, bestehend aus je einem obj_Spieler, obj_Ziel, obj_Controller, ein paar obj_Gegner und vielen obj_Wand (siehe Screenshot).

      Dann Scripten wir erstmal die Bewegung für den Spieler und rufen sie vom Step Event des obj_Spieler auf.

      scr_SpielerBewegung:

      Quellcode

      1. {
      2. if (global.SpielerZug)
      3. {
      4. switch (keyboard_key)
      5. {
      6. case vk_left: if (place_free(x-32,y)){x-=32;global.SpielerZug = false}; break;
      7. case vk_right: if (place_free(x+32,y)){x+=32;global.SpielerZug = false}; break;
      8. case vk_up: if (place_free(x,y-32)){y-=32;global.SpielerZug = false}; break;
      9. case vk_down: if (place_free(x,y+32)){y+=32;global.SpielerZug = false}; break;
      10. }
      11. }
      12. }
      Alles anzeigen

      Außerdem scripten wir gleich noch etwas für das Room-Start Event des Controllerobjekts:

      scr_RoomStart:

      Quellcode

      1. {
      2. global.SpielerZug = true;
      3. global.GegnerZug = false;
      4. }


      Später werden wir noch mehr dazuscripten.
      Bevor es jetzt zum spannenden Teil geht, sollten wir das Spiel mal testen.
      Wenn alles richtig war, müsstens wir uns jetzt genau einen Schritt fortbewegen können.

      Jetzt öffnen wir erneut scr_RoomStart und fügen folgende Zeile ein:

      Quellcode

      1. global.Netz = mp_grid_create(0,0,20,15,32,32);


      Damit erstellen wir ein Netz, bestehend aus 20x15 Feldern der Größe 32x32, dessen Koordinaten 0,0 sind.
      Dieses werden wir für sämtliche mp_grid-Funktionen benötigen. Die Globale global.Netz brauchen wir, um auf das eben erstellte Netz zuzugreifen.


      mp_grid_create(left,top,hcells,vcells,cellwidth,cellheight) This function creates the grid. It returns an index that must be used in all other calls. You can create and maintain multiple grid structures at the same moment. left and top indicate the position of the top-left corner of the grid. hcells and vcells indicate the number of horizontal and vertical cells. Finally cellwidth and cellheight indicate the size of the cells.


      Nun erstellen wir ein Script für das Step-Event des obj_Controller:

      scr_GridAktualisierung:

      Quellcode

      1. {
      2. if (!global.SpielerZug)
      3. {
      4. mp_grid_clear_all(global.Netz);
      5. mp_grid_add_instances(global.Netz,obj_Wand,0);
      6. global.GegnerZug = true;
      7. }
      8. }


      Mit mp_grid_clear_all machen wir das gesamte Netz frei.
      Mit mp_grid_add_instances wird jedes Feld, auf dem ein obj_Wand liegt blockiert.
      Die beiden mp_grid-Funktionen hätten wir natürlich auch in ein Room_Start – Event packen können, allerdings ist es von Vorteil, dies wie hier zu machen, falls man auch zerstörbare oder bewegliche Wände einbauen will.


      mp_grid_clear_all(id) Mark all cells in the grid to be free.
      mp_grid_add_instances(id,obj,prec) Marks all cells that intersect an instance of the indicated object as being forbidden. You can also use an individual instance by making obj the id of the instance. Also you can use the keyword all to indicate all instances of all objects. prec indicate whether precise collision checking must be used (will only work if precise checking is enabled for the sprite used by the instance).


      Jetzt noch ein Script für das StepEvent der Gegner (obj_Gegner):

      Quellcode

      1. scr_GegnerBewegung:
      2. {
      3. if (global.GegnerZug)
      4. {
      5. mp_grid_path(global.Netz,Pfad,x,y,obj_Spieler.x,obj_Spieler.y,0);
      6. path_start(Pfad,4,0,0);
      7. if (!InBewegung) {alarm[0] = 4};
      8. InBewegung = true
      9. }
      10. else
      11. path_end();
      12. }
      Alles anzeigen


      Mit mp_grid_path veranlasst man das Programm einem Pfad durch die nicht blockierten Felder des Netzes zu generieren.


      mp_grid_path(id,path,xstart,ystart,xgoal,ygoal,allowdiag) Computes a path through the grid. path must indicate an existing path that will be replaced by the computer path. xstart and ystart indicate the start of the path and xgoal and ygoal the goal. allowdiag indicates whether diagonal moves are allowed instead of just horizontal or vertical. The function returns whether it succeeded in finding a path. (Note that the path is independent of the current instance; It is a path through the grid, not a path for a specific instance.)


      Jetzt noch eins für das Create Event der Gegner (obj_Gegner):

      scr_GegnerIni:

      Quellcode

      1. {
      2. Pfad = path_add();
      3. InBewegung = false;
      4. }


      Hier muss ein Pfad erstellt werden, da die mp_grid_path Funktion immer einen schon bestehend Pfad verändert und keinen neuen erstellt.

      Und für das Alarm[0] Event:

      scr_GegnerStop:

      Quellcode

      1. {
      2. global.GegnerZug = false;
      3. global.SpielerZug = true;
      4. InBewegung = false;
      5. }


      Zur Veranschaulichung des Netzes kann man noch folgendes Script in das Draw-Event des obj_Controller packen (natürlich muss man dann den Controller sichtbar machen:

      scr_DrawNetz:

      Quellcode

      1. {
      2. if keyboard_check(vk_alt) {mp_grid_draw(global.Netz)}
      3. }


      Die Funktion mp_grid_draw zeichnet – wer hätte das gedacht – das Netz.


      mp_grid_draw(id) This function draws the grid with green cells being free and red cells being forbidden. This function is very slow and only provided as a debug tool.


      Und fertig!


      Zu guter Letzt...

      Ihr könnt dieses Beispiel erweitern indem z.B....
      ...etwas passiert, wenn man das Ziel erreicht.
      ...etwas passiert, wenn man einen Gegner berührt.

      Kleiner Bug:
      - Der Pfad für die Gegnerbewegung wird nicht in der Mitte der Gänge, sondern auch an den Rändern angelegt. Kann man das irgendwie beheben?


      So das war’s auch schon für heute, euer G. O.
      Bilder
      • image001.png

        10,12 kB, 640×480, 1.057 mal angesehen
      www.glowingorb.de
      „Wenn es im Universum noch irgendwo intelligente Lebewesen gibt, dann kennen sie vielleicht Schach, höchstwahrscheinlich jedoch GO

      (Schachweltmeister Emanuel Lasker)

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von MewX ()

    • Und hier noch das Beispiel dazu:
      Dateien
      • MPGT.zip

        (3,7 kB, 673 mal heruntergeladen, zuletzt: )
      www.glowingorb.de
      „Wenn es im Universum noch irgendwo intelligente Lebewesen gibt, dann kennen sie vielleicht Schach, höchstwahrscheinlich jedoch GO

      (Schachweltmeister Emanuel Lasker)
    • meine gegner wuseln jetzt in 4-pixel-schritten durch das labyrinth (obj_Gegner - Draw):

      Quellcode

      1. //if place_free(round(x/32)*32,round(y/32)*32) draw_sprite(spr_Gegner,0,round(x/32)*32,round(y/32)*32)
      2. //else if place_free(floor(x/32)*32,round(y/32)*32) draw_sprite(spr_Gegner,0,floor(x/32)*32,round(y/32)*32)
      3. //else if place_free(round(x/32)*32,floor(y/32)*32) draw_sprite(spr_Gegner,0,round(x/32)*32,floor(y/32)*32)
      4. //else if place_free(ceil (x/32)*32,round(y/32)*32) draw_sprite(spr_Gegner,0,ceil (x/32)*32,round(y/32)*32)
      5. //else if place_free(round(x/32)*32,ceil (y/32)*32) draw_sprite(spr_Gegner,0,round(x/32)*32,ceil (y/32)*32)
      6. rx=round(x/8)*8
      7. ry=round(y/8)*8
      8. if place_free(rx ,ry ) draw_sprite(spr_Gegner,0,rx, ry )
      9. else for(nn=4;nn<32;nn+=4)
      10. { if place_free(rx-nn,ry ) {draw_sprite(spr_Gegner,0,rx-nn,ry );break}
      11. else if place_free(rx+nn,ry ) {draw_sprite(spr_Gegner,0,rx+nn,ry );break}
      12. else if place_free(rx ,ry-nn) {draw_sprite(spr_Gegner,0,rx ,ry-nn);break}
      13. else if place_free(rx ,ry+nn) {draw_sprite(spr_Gegner,0,rx ,ry+nn);break}
      14. else if place_free(rx-nn,ry-nn) {draw_sprite(spr_Gegner,0,rx-nn,ry-nn);break}
      15. else if place_free(rx+nn,ry+nn) {draw_sprite(spr_Gegner,0,rx+nn,ry+nn);break} }
      Alles anzeigen
    • mit 6.0r getestet => funktioniert noch; keine Korrektur notwendig!
      www.glowingorb.de
      „Wenn es im Universum noch irgendwo intelligente Lebewesen gibt, dann kennen sie vielleicht Schach, höchstwahrscheinlich jedoch GO

      (Schachweltmeister Emanuel Lasker)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Glowing Orb ()

    • Ich weis dieser Threat ist schon Uralt allerdings habe ich eine Lösung zu oben genannten Bug gefunden, wie man diesen recht simpel lösen kann...

      GML-Quellcode

      1. mp_grid_path(global.Netz,Pfad,x,y,obj_Spieler.x,obj_Spieler.y,0);


      durch diese Funktion ersetzen

      GML-Quellcode

      1. mp_grid_path(global.Netz,Pfad,x+16,y+16,obj_Spieler.x,obj_Spieler.y,0);


      somit bewegen sich die Gegner nicht am Rande der Wall entlang sonder mittig,...

      ich hoffe ich konnte jemandem helfen der diesen Threat benutz um sich ein einfaches game zu basteln