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

christ schmuck.jpgSo 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

christ schmuck.jpgDen 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: , , , , , , , , ,

Dies könnte dich auch interessieren

Privacy Browser für mehr Sicherheit und Privatsphäre

Mehr Datenschutz, Sicherheit und vor allem mehr Privatsphäre im Internet wird von allen Seiten gefordert, und das nicht erst nach dem Inkrafttreten der EU-weiten Datenschutz-Grundverordnung (DSGVO / Datenschutz ). Generell kann man diesen Wunsch durchaus nachvollziehen, denn wer möchte schon freiwillig großen IT-Konzernen erlauben die eigenen Daten weiterzugeben, zu verkaufen und wer weiß was damit [...] Weiterlesen »


Telegram Messenger und die Bot API

Telegram ist im Prinzip ein Messenger ähnlich Whatsapp oder Threema , kostenlos und leicht zu bedienen. Ich möchte nicht sagen das dieser besser oder schlechter ist als andere Messenger, allerdings gefällt mir die Telegram Bot API sogut, dass ich an dieser Stelle ein kleines Tutorial dazu schreiben möchte. Inhaltsverzeichnis:Telegram Messenger Bot API programmierenSchritt 1 - [...] Weiterlesen »


VR Studie - Spielsteuerung ohne Controller

In den letzten Tagen habe ich mich etwas mit VR (Virtual Reality) und der Umsetzung einer Spielsteuerung beschäftigt, welche ohne Controller auskommt. Als Hardware diente die VR Box 3 (VR-Brille) sowie ein iPhone 6s+ . Inhaltsverzeichnis:VR Spielsteuerung ohne ControllerVR-Video bei Youtube - Demo - Spielsteuerung ohne ControllerVR BOX3 VR Spielsteuerung ohne Controller Ziel war es, sich [...] Weiterlesen »


KING OF KARTS 3D

Mach dich bereit, auf die Plätze, LOS! King of Karts ist ein faszinierendes 3D-Rennspiel! Besiege deine Freunde auf 8 Strecken. 3 unterschiedliche Spielmodi warten auf dich, wobei auch Mehrspieler-Partien mit bis zu 6 Geräten möglich sind. Sammle Power-Up-Items, entdecke Abkürzungen und verborgene Wege, benutze Boostfelder und Sprungschanzen und wage riskante Stunts und Drifts. King of [...] Weiterlesen »


iOS-Android-Converter

Lange Zeit habe ich bei neuen App-Projekten zunächst die Sprachdateien / Language-Files für iOS geschrieben, und diese dann für die Android-Version händisch umgeschrieben. Das war vom Aufwand her immer schnell gemacht solange die Anzahl der implementierten Sprachen und der Umfang der Textbausteine niedrig war. Abgesehen vom Zeitaufwand ist das ganz schön langweilige und stumpfe Arbeit, [...] Weiterlesen »