Automatische Tileset ausrichtung

    • GM 8

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

    • Automatische Tileset ausrichtung

      Tutorial zur Automatischen Ausrichtung von Tilesets
      "An einem Beispiel von Bergen"


      Hallo alle zusammen. Ich möchte heute mit euch auf das Theme Tilesets ein gehen.
      In vielen Spielen wird es eingesetzt. Klar es ist ja auch eine einfach Art sein Level zu erstellen.

      Doch was ist wenn sich die Welt per zufall erstellt wird. Denn das Thema "World Generator" bekommt man ja immer öfter hier zu lesen.

      Daher habe ich aus einem Älteren Projekt das Script für ein Kleines aktuelle Projekt, für euch als Tutorial heraus genommen.

      Ziel des Tutorials
      Spoiler anzeigen

      Eine Welt in der Berge Automatisch aus gerichtet werden.



      Tileset Basis


      Was braucht man dafür
      Im grune braucht man nur ein solches Tileset wie ich es oben gezeichnet habe "Vorbild war Minicraft" und ein Grid
      -Tileset
      -Grid

      Zum Tileset ist noch eines sehr wichtig. Ihr müst euch im Klaren sein wie viele Teile es haben wird.
      Ich sage nicht soll sondern wird.
      Denn es kommen oft Konstelltionen zustande an die man vorher nicht denket. All diese Möglich keiten müssen vorher gezeichnet werde.
      Ich selber habe beim Zeichnen des Tilesets so ca 13 Teile Vergessen. Dieverse Kurevn möglichkeiten an die ich nicht gedacht hatte.

      Und so geht es

      Zu erst erstellt ihr euer Grid in der gewünschten Größe.
      Ich habe hier mein Grid auf 64*64 Zellen gestellt. ( Je nach Level Größe )

      GML-Quellcode

      1. level_grid=ds_grid_create(64,64)


      Euer Grid Füllt ihr dann mit 0 und 1.
      0=Frei
      1=Berg.
      Das könnt ihr mit einem World Generator machen wie ihr ihn haben wollt.
      Aber das ist ein anderes Thema.
      Bei mir ist es Purer Zufall um das Script zu Testen.

      Nun nach dem ihr euer Grid erstellt habt kommt der 2 Durchgang.
      Ihr geht jede Zelle durch und Prüft ob die Zelle auf 1 steht oder 0.
      Wenn sie auf 1 ist soll ein Script auf gerufen werden.
      ( Das Geht auf meinem low rechner alles innerhalb von 3-5 Sekunden )

      Das Script
      Aufruf
      Spoiler anzeigen

      GML-Quellcode

      1. w=0
      2. h=0
      3. do
      4. {
      5. do
      6. {
      7. val=ds_grid_get(level_grid,w,h)
      8. if val>0 then scr_check_grid(w,h)
      9. w+=1
      10. }
      11. until(w=ds_grid_width(level_grid))
      12. h+=1
      13. w=0
      14. }
      15. until(h=ds_grid_height(level_grid))
      Alles anzeigen


      Spoiler anzeigen

      GML-Quellcode

      1. //Flesen Kreuzung / Mitte / Einzelstein
      2. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      3. string(ds_grid_get(level_grid,argument0,argument1-1))+
      4. string(ds_grid_get(level_grid,argument0-1,argument1))+
      5. string(ds_grid_get(level_grid,argument0,argument1+1))+
      6. string(ds_grid_get(level_grid,argument0+1,argument1-1))+
      7. string(ds_grid_get(level_grid,argument0-1,argument1-1))+
      8. string(ds_grid_get(level_grid,argument0-1,argument1+1))+
      9. string(ds_grid_get(level_grid,argument0+1,argument1+1))
      10. switch crypt
      11. {
      12. case "11110000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,3*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Gerad x
      13. case "11111111":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,1*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Gerad x
      14. case "00000000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Einzelstein
      15. case "11111101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Kurve innen Links unten
      16. case "11111011":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Kurve innen Links oben
      17. case "11111110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Kurve innen rechts unten
      18. case "11110111":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//Kurve innen rechts oben
      19. case "11111001":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,7*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//T Offen Links
      20. case "11110110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,7*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//T offen rechts
      21. case "11111100":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,7*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//T offen unten
      22. case "11110011":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,7*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//T offen oben
      23. case "11110101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Knochen \
      24. case "11111010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//Knochen /
      25. //3 Stücke 00,10,01,11 Kanten seiten wie bei Polygonen
      26. case "11110001":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,0*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//00
      27. case "11110010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,1*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//10
      28. case "11111000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,0*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//01
      29. case "11110100":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,1*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//11
      30. }
      31. //Horizontal- / Vertikal & Einzellfelsen
      32. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      33. string(ds_grid_get(level_grid,argument0,argument1-1))+
      34. string(ds_grid_get(level_grid,argument0-1,argument1))+
      35. string(ds_grid_get(level_grid,argument0,argument1+1))
      36. switch crypt
      37. {
      38. case "1010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,3*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//Gerad x
      39. case "0101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,3*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Gerad x
      40. case "0000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,6*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Einzelstein
      41. case "0001":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,3*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Endstück oben
      42. case "0100":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,3*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Endstück unten
      43. case "1000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,4*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Endstück links
      44. case "0010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,5*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Endstück rechts
      45. }
      46. //T kreuzungen Oben
      47. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      48. string(ds_grid_get(level_grid,argument0,argument1-1))+
      49. string(ds_grid_get(level_grid,argument0-1,argument1))+
      50. string(ds_grid_get(level_grid,argument0,argument1+1))+
      51. string(ds_grid_get(level_grid,argument0+1,argument1-1))+
      52. string(ds_grid_get(level_grid,argument0-1,argument1-1))
      53. switch crypt
      54. {
      55. case "111000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,4*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Oben
      56. case "111011":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,1*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Oben
      57. case "111010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,8*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      58. case "111001":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,9*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      59. }
      60. //T kreuzungen Rechts
      61. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      62. string(ds_grid_get(level_grid,argument0,argument1-1))+
      63. string(ds_grid_get(level_grid,argument0-1,argument1))+
      64. string(ds_grid_get(level_grid,argument0,argument1+1))+
      65. string(ds_grid_get(level_grid,argument0+1,argument1-1))+
      66. string(ds_grid_get(level_grid,argument0+1,argument1+1))
      67. switch crypt
      68. {
      69. case "110100" :{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,5*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Rechts
      70. case "110111" :{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,0*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Rechts
      71. case "110101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,9*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      72. case "110110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,9*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      73. }
      74. //T kreuzungen Unten
      75. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      76. string(ds_grid_get(level_grid,argument0,argument1-1))+
      77. string(ds_grid_get(level_grid,argument0-1,argument1))+
      78. string(ds_grid_get(level_grid,argument0,argument1+1))+
      79. string(ds_grid_get(level_grid,argument0+1,argument1+1))+
      80. string(ds_grid_get(level_grid,argument0-1,argument1+1))
      81. switch crypt
      82. {
      83. case "101100": {tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,4*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//unten
      84. case "101111":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,1*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Rechts
      85. case "101110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,8*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      86. case "101101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,9*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      87. }
      88. //T kreuzungen links
      89. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      90. string(ds_grid_get(level_grid,argument0,argument1-1))+
      91. string(ds_grid_get(level_grid,argument0-1,argument1))+
      92. string(ds_grid_get(level_grid,argument0,argument1+1))+
      93. string(ds_grid_get(level_grid,argument0-1,argument1-1))+
      94. string(ds_grid_get(level_grid,argument0-1,argument1+1))
      95. switch crypt
      96. {
      97. case "011100":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,5*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      98. case "011111" :{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,1*16,16,16,argument0*16,(argument1*16),1)}break;//Rechts
      99. case "011101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,8*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      100. case "011110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,8*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Offene L formen
      101. }
      102. //Kurve Unten Rechts
      103. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      104. string(ds_grid_get(level_grid,argument0,argument1-1))+
      105. string(ds_grid_get(level_grid,argument0-1,argument1))+
      106. string(ds_grid_get(level_grid,argument0,argument1+1))+
      107. string(ds_grid_get(level_grid,argument0+1,argument1+1))
      108. switch crypt
      109. {
      110. case "10011":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,0*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      111. case "10010":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,4*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      112. }
      113. //Kurve Unten Links
      114. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      115. string(ds_grid_get(level_grid,argument0,argument1-1))+
      116. string(ds_grid_get(level_grid,argument0-1,argument1))+
      117. string(ds_grid_get(level_grid,argument0,argument1+1))+
      118. string(ds_grid_get(level_grid,argument0-1,argument1+1))
      119. switch crypt
      120. {
      121. case "00111":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,0*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      122. case "00110":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,5*16,3*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      123. }
      124. //Kurve Oben rechts
      125. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      126. string(ds_grid_get(level_grid,argument0,argument1-1))+
      127. string(ds_grid_get(level_grid,argument0-1,argument1))+
      128. string(ds_grid_get(level_grid,argument0,argument1+1))+
      129. string(ds_grid_get(level_grid,argument0+1,argument1-1))
      130. switch crypt
      131. {
      132. case "11001":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,0*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      133. case "11000":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,4*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      134. }
      135. //Kurve Oben links
      136. crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
      137. string(ds_grid_get(level_grid,argument0,argument1-1))+
      138. string(ds_grid_get(level_grid,argument0-1,argument1))+
      139. string(ds_grid_get(level_grid,argument0,argument1+1))+
      140. string(ds_grid_get(level_grid,argument0+-1,argument1-1))
      141. switch crypt
      142. {
      143. case "01101":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      144. case "01100":{tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,5*16,4*16,16,16,argument0*16,(argument1*16),1)}break;//Links }
      145. }
      Alles anzeigen



      Das war vom Programm auf wand schon alles wenn man ein solches Script schon hat.
      Aber was macht das Script genau.

      Das Script und wie es arbeitet


      Das Script sammelt in Grunde Informationene über die Belegung der Benachbarten Grid Zellen um die Aktuelle herum.
      Und erstellt aus den Werten einen Zahlen Code. Wo bei Jeder einmalig ist.
      Es sei nuch gesagt das ich in meinem Falle im Urzeige sind mit Recht,Oben,Links,Unten anfang und dann erst die Diagonalen wie Rechtsoben,Linksoben,Linksunten und Rechts unten zusammen fasse.

      Aber was heist das genau für uns.

      Hier sind mal ein Paar Beispiele für ein Paar Tileset Teile


      Jeder Zahlen Code ist Einmalig und ist nur für ein Bestimmtes Puzzelteil geeignet.
      Und wer genau hin schaut, hat auch bemerkt, sowie auf dem Bild als auch in dem Script, werden Verschieden Codes erfast.
      Denn es ist nun mal so das ich für eine Kurve nicht alle Werte brauche.
      Da sie für bestimmte Fälle egal sind.

      Wenn wir uns ein Beispiel mal genau dazu, anschauen werden wir sehen das es volkommen egal ist ob an bestimmten Stellen eine Zelle belegt ist oder nicht.


      In Diesem Falle würde die Vertikal Bergkette so oder so enstehen.
      Aus diesem Grund werden Verschieden Muster Abgefragt


      Für einiege Teile sind halt mal mehr oder wenige Information Relevant.

      Zum Ende nehmen wir noch mal die Code Zeile hinter einem Zahlencode aus ein ander.

      GML-Quellcode

      1. {tile_layer_delete_at(1,argument0*16,(argument1*16));tile_add(tile_hill,2*16,2*16,16,16,argument0*16,(argument1*16),1)}break;//Links }


      -tile_layer_delete_at(1,argument0*16,(argument1*16))
      Hier wird ein Tileset an der Grid Stelle auf der Karte mit einem Depth 1 gelöscht
      -tile_add(tile_hill,2*16,2*16,16,16,argument0*16,(argument1*16),1)
      Hier wird das Tileset aus einem Grid auf der Karte erstellt.

      Mein Tileset hat eine Größe von 16*16 Pixeln. Somit Multipliziere ich einfach die Grid Position mit 16.
      Denn Gridwert bekommt das Script aus der Schleife oben als Arguemnt0 und Arguemnt1

      Anwendungs Beispiel
      Sowohl wie auf dem Bild kam diese Technik auch in "The City" zum einsatzt. Mit ihr habe ich die Straßen Ausrichten lassen und auch dort die Berge.

      Der Vorteil ist einfach das man sich nicht mehr die Mühe machen muss um ein Level zu bauen ,wenn man im Falle eines Zufall vorher nicht weis wie das Level auszusehen hat.
      "Siehe Minicraft"
      Der 2 Punkt ist. es es Komplet Obekte los ist. Da es immer noch viele gibt die alles mit Obejkten machen statt mit guten und Übersichtlichen GML Codes.
      Soll heißen das die Straßen keine Objekte mehr waren, sondern alles Tilesets.

      Der Driite und lettze punkt ist der ( Das habe ich noch nicht fertig ) Das sie Welt Jder Zeit nach berchnet werden kann, falls mal ein Berg (Block) abgebaut wird.
      Dann wird einfach ein Teil des Grid geprüft und alles Richtet sich erneut aus.

      "Persönlicher Tip"
      Wer vor hat Straßen zu machen wie ich in "The City" der sollte beim Bau von Straßen die Grid Position in eine ds_list Speichern.
      So wird beim Prüfen nicht das Ganze Level durch geprüft sonden nur die Stellen die in der Liste Stehen. Das Spart Zeit, Rechenleistung und ist sehr viel Performanter.

      So ich hoffe ich konnt helfen. Fals Fragen sind oder ich einen Wichtigen Teil vergessen habe zu erklären der brauch einfach nur zu fragen.
      Ps Ja ich weis meine Rechtsschreibung ist nicht die beste da ich mich öfter mal Vertippe.
      Ich hoffe ihr habt nachsicht mit mir.

      Ich hoffe ich konnte euch Helfen und euch zu neuen Projekten anregungen verleiten

      MFG x-sascha
      Meine Signatur hat kein Visum für das GM Forum erhalten.
    • Benutzer online 1

      1 Besucher