Tutorial zur Automatischen Ausrichtung von Tilesets
"An einem Beispiel von Bergen"
"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
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 )
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
GML-Quellcode
- //Flesen Kreuzung / Mitte / Einzelstein
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1+1))
- switch crypt
- {
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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 \
- 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 /
- //3 Stücke 00,10,01,11 Kanten seiten wie bei Polygonen
- 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
- 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
- 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
- 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
- }
- //Horizontal- / Vertikal & Einzellfelsen
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))
- switch crypt
- {
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- }
- //T kreuzungen Oben
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1-1))
- switch crypt
- {
- 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
- 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
- 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
- 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
- }
- //T kreuzungen Rechts
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1-1))+
- string(ds_grid_get(level_grid,argument0+1,argument1+1))
- switch crypt
- {
- 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
- 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
- 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
- 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
- }
- //T kreuzungen Unten
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1+1))+
- string(ds_grid_get(level_grid,argument0-1,argument1+1))
- switch crypt
- {
- 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
- 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
- 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
- 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
- }
- //T kreuzungen links
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0-1,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1+1))
- switch crypt
- {
- 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 }
- 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
- 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
- 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
- }
- //Kurve Unten Rechts
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1+1))
- switch crypt
- {
- 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 }
- 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 }
- }
- //Kurve Unten Links
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0-1,argument1+1))
- switch crypt
- {
- 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 }
- 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 }
- }
- //Kurve Oben rechts
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+1,argument1-1))
- switch crypt
- {
- 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 }
- 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 }
- }
- //Kurve Oben links
- crypt= string(ds_grid_get(level_grid,argument0+1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1-1))+
- string(ds_grid_get(level_grid,argument0-1,argument1))+
- string(ds_grid_get(level_grid,argument0,argument1+1))+
- string(ds_grid_get(level_grid,argument0+-1,argument1-1))
- switch crypt
- {
- 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 }
- 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 }
- }
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.
-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
MFG x-sascha
Meine Signatur hat kein Visum für das GM Forum erhalten.