Unity 2D Platformer - Level Generator

Amazon

Seit einiger Zeit experimentiere ich hier und da mit der 2D- und 3D Engine Unity. Insbesondere die Programmierung eines 2D-Platformers hat es mir aktuell angetan.

Allerdings ist das programmieren eines 2D-Games (sofern man Programmierer ist) nicht das größte Problem, sondern meiner Meinung nach die Optik, da ich kein Grafiker bin. :D

AmazonSo kommt man nicht drum herum, sich einige Tools zu bauen, wie z.B. einen Texture-Generator in Python Python oder wie in diesem Artikel beschrieben einen kleinen Level Generator in CSharp.

Wer seine Prefabs in Unity bereits angelegt hat und nun die leere Scene vor sich hat weiß wie mühsam es sein kann ein Level zu designen und in der Szene alles korrekt zu platzieren. Ebenen, Böden, Wände, Respawn-Point für den Spieler, Gegner, Items die man einsammeln kann um z.B. Punkte zu bekommen, und vieles vieles mehr.

Inhaltsverzeichnis:

Wie kann man also das erstellen eines Levels beschleunigen und alle Game-Objekte korrekt platzieren?!

Die Idee ist simpel und leicht in extrem kurzer Zeit umgesetzt. Man erstellt für jedes Level ein Bild bzw. eine zunächst transparente PNG-Datei in Photoshop oder GIMP und färbt die Pixel ein, an denen ein GameObject erstellt werden soll.

Zunächst legt man also die Farbwerte für seine Prefabs fest. Beispiel: Der Pixel für den Startpunkt des Spielers wird grün (RGBA: #00ff00ff). Böden werden blau (RGBA: #0000ffff) markiert, Gegner rot (RGBA: #ff0000ff) und Items zum Einsammeln Gelb (RGBA: #ffff00ff).

Man kann die Liste noch beliebig erweitern, je nachdem wieviele unterschiedliche Objekte ihr habt. Um nicht zuviele Farben nutzen zu müssen kann man z.B. Items sehr gut gruppieren indem man wie gehabt alle Items gelb setzt, beim laden später aber immer ein anderes per Zufall an die Position in das Level lädt. Nur ein Ansatz von vielen...

Ein solches Level PNG-File (GIMP-Screenshot - Breite 32px, Höhe 8px) sieht dann in etwa so aus:

2d platformer level generator

Man speichert also die Grafik im PNG-Format und zieht diese in seinem 2d Platformer Projekt in Unity in das Assets-Verzeichnis.

unity 2d platformer - Level GeneratorDie Level-Grafiken sollten später alle unter "Assets/Resources/Level/Level1.png" liegen.

(Level1.png, Level2.png, usw...)

WICHTIG: Damit das Ganze auch funktioniert wie es soll muss man zunächst die Texture-Einstellungen für jedes Level-PNG setzen.

+ Filter Mode: Point (no filter)
+ Compression: None!
+ Read/Write Enabled: true

Danach unten rechts auf Apply klicken. Soweit so gut.

Programmieren - Unity 2D Platformer - Level Generator

Jetzt müssen wir nurnoch etwas Code schreiben damit unser Spiel auch weiß was es mit diesen tollen Bildchen tun soll. Zunächst erstellt man also ein neues C#-Script und nennt die Klasse LevelGenerator. In der LevelGenerator.cs fügt man zunächst eine Struktur ein, welche die notwendigen Informationen (Prefab und Farbe) zu jedem Objekt speichern kann und erstellt eine ArrayList in die man die einzelnen Objekte legen kann.

private struct pixObject{
 public Color pixColor;
 public GameObject prefab;
}
private ArrayList pixToObject = new ArrayList();

Als nächstes benötigen wir eine Funktion um die Prefabs und Farbwerte in die ArrayList zu schreiben, damit wir daraus später per Instantiate die Clones der Objekte erstellen können. Ich habe die Funktion mal initPrefabs genannt:

public void initPrefabs(){
if (pixToObject.Count > 0) //skip if already initialized
return;

pixToObject = new ArrayList();

pixObject o = new pixObject();
o.pixColor = Color.blue; //ground blue
o.prefab = Resources.Load<GameObject>("Prefabs/GROUND_1x1"); //Fullpath: Assets/Resources/Prefabs/GROUND_1x1.prefab
pixToObject.Add(o);

o = new pixObject();
o.pixColor = Color.green; //Player green
o.prefab = Resources.Load<GameObject>("Prefabs/Player");
pixToObject.Add(o);

o = new pixObject();
o.pixColor = Color.red; //Enemy red
o.prefab = Resources.Load<GameObject>("Prefabs/Enemy");
pixToObject.Add(o);

o = new pixObject();
o.pixColor = new Color(1, 1, 0, 1); //Item/Collect yellow
o.prefab = Resources.Load<GameObject>("Prefabs/Collect");
pixToObject.Add(o);
}

In dieser Funktion befüllt man also seine ArrayList. Der Code sollte soweit selbsterklärend sein. Man erstellt ein pixObject, stellt die gewünschte Farbe ein, gibt ihm den passenden Prefab mit und schreibt das Objekt in die ArrayList.

Im nächsten Schritt erstellt man eine Funktion addObject welche einen gewünschten Pixel (xy Koordinate) aus der Level-PNG einließt, und je nachdem an die jeweilige Stelle im Spiel das passende Objekt setzt.

private void addObject(int x, int y, ref Texture2D tex){
Color pixColor = tex.GetPixel(x, y);
if (pixColor.a == 0) //ignore transparent pixels
   return;

 foreach (pixObject o in pixToObject){
   if (o.pixColor.Equals(pixColor)){
      Vector2 pos = new Vector2(x, y);
      Instantiate(o.prefab, pos, Quaternion.identity);
    }
 }
}

Jetzt habe ich eine Funktion namens loadLevel geschrieben, welche als Parameter die Nummer des gewünschten Levels entgegen nimmt. An der Stelle wird der Pfad zu der gewünschten Level-PNG gebildet. Der Inhalt der Datei wird in ein Byte-Array gelesen und im Anschluss per LoadImage in ein Texture2D Objekt geladen, welches wie oben gesehen das auslesen der Pixel sehr einfach macht.

Nachdem das Texture2D-Objekt mapTex nun startklar ist werden die einzelnen Pixel im Bild per For-Schleife durchlaufen und addObject (siehe oben) aufgerufen, um den jeweiligen Pixel auszuwerten.

Update - Pfadangaben auf Mobilgeräten (iOS, Android)

UPDATE: Auf Mobilgeräten mit Android oder auch iOS schlägt das Laden per ReadAllBytes fehl, da der Relative Pfad nicht korrekt war. Lädt man das Level PNG-Bild direkt über die Unity-Engine per Resources.Load as Texture2D funktioniert alles wie gewünscht und das Plattformunabhängig. Der Code wurde entsprechend angepasst.

public bool loadLevel(int levelNum){
string sFile = "Level/Level" + levelNum.ToString();
Texture2D mapTex = Resources.Load(sFile) as Texture2D;

for (int x = 0; x < mapTex.width; x++){
for (int y = 0; y < mapTex.height; y++){
addObject(x, y, ref mapTex);
}}
return true;
}

Das war es dann auch schon fast. Nicht vergessen in die void Start() noch die beiden Funktionen zum laden aufzurufen.

private void Start(){
initPrefabs();
loadLevel(GameControl.control.currentLevel);
}

Den LevelGenerator kann man dann als Komponente in ein leeres GameObject in seine Scene einfügen. Fertig! Das Ergebnis sieht bei mir dann so aus:

Unity Level Generator - 2D Platformer

AmazonDen Code habe ich hier zum Download hinterlegt: LevelGenerator.cs

Ich hoffe die herangehensweise, der Code und die Erklärungen sind einigermaßen verständlich. :-) Fragen, Lob, Kritik und sonstiges Feedback sind willkommen >> zum Kontaktformular.

Zuletzt bearbeitet: 23. Mai, 2019
Tags: , , , , , , , , ,

Weitere interessante Beiträge

App des Tages: Die Brille - Kinderbuch-App

Die Kinderbuch-App "Die Brille" entführt in das interaktive Abenteuer des kleinen Max, der an einem schönen Sommertag eine magische Brille findet. In neun abwechslungsreichen Szenen können Kinder die Brille selbst aufsetzen und in eine bunte und herrlich verrückte Abenteuerwelt mit liebevoll animierten Figuren eintauchen. Eine Sprecherin, Musik und Soundeffekte machen aus dem digitalen Kinderbuch ein [...] Weiterlesen »


Projekt: pi_robot - Raspberry Pi, iPad und etwas Code

Der Raspberry Pi ist nach wie vor einer der beliebtesten Mini-Computer, nicht nur unter Bastlern. Kostengünstig (je nach Modell um die 30 bis 40,- EUR), flexibel im Anwendungsbereich und spätestens seit dem Raspberry Pi 3 auch mit ausreichend CPU-Leistung und Arbeitsspeicher ausgestattet, um auch etwas komplexere Aufgaben zu lösen. Mit dem 1,2 GHz quad-core ARM [...] Weiterlesen »


Screen Recorder / Capture Software selber programmieren

Auf der Suche nach einem einfach zu bedienenen Screen-Recorder-Tool bin ich über allerhand kostenloser sowie kostenpflichtiger Softwarelösungen gestolpert. Aus meiner Sicht waren ziemlich alle entweder völlig überladen oder auch schlecht bzw. kompliziert zu bedienen. Andere waren auch einfach nur teuer im Verhältnis zum Funktionsumfang. Mein Fazit: Selber programmieren! Inhaltsverzeichnis:Screen-Recorder-Tool selber programmierenSchritt 1 - FFMPEG.NET Library [...] Weiterlesen »


App des Tages: Hunter & Co. - Dein digitaler Jagdgefährte

Heute mal eine kostenfreie App aus dem Bereich Sport - genauer gesagt aus dem Bereich der Jagd. Dein digitaler Jagdgefährte ist eine kostenlose App für iOS (iPhone) sowie Android-Mobilgeräte. Obwohl die App noch relativ "jung" ist, wurde Sie bereits weit über 10.000 mal in den Appstores heruntergeladen und auch schon knapp 100mal bewertet (nahezu positiv; [...] Weiterlesen »


Rezeptbuch-App - Rezepte verwalten, teilen und mehr

Mit der Rezeptbuch-App kannst du deine Rezepte komfortabel verwalten. Erstelle deine eigene wundervolle Rezeptsammlung mit leckeren Ideen zum Kochen, Braten, Grillen und Backen. Die aktuelle Version (iPhone, iPad und Android) der Rezeptbuch-App ist da. Nun ist es möglich, neben einem Backup deiner Rezepte in der iCloud (iOS) bzw. Google-Drive (Android), die Daten auch bei anderen [...] Weiterlesen »