"wand-algorithmus" - weg um wände um paths zu berechnen?

Hey Leute.
Ich arbeite momentan an „Pacman3d“.
Die Wege, auf denen sich der spieler bewegen kann sind durch einfache strecken nach dem schema
p1(x, z), p2(x, z) dargestellt, welche vor beginn aus einer datei gelesen werden.

Nun suche ich nach einem Weg, wände um diese pfade berechnen zu lassen.
Es ist schwer zu erklären, deshalb zeige ich einfach anhand eines beispiels, was ich meine.

Angenommen die gesamte Map besteht aus 3 Punkten und 2 Strecken:

p1 (100, 0)
p2 (0, 0)
p3 (0, 100)

verbunden sind p1 <> p2 und p2 <> p3.
Das heißt die map wäre von oben betrachtet eine ecke:

p3
|
p2___p1

Nun möchte ich wände berechnen, damit die map von oben so aussieht,
also um jede strecke eine wand gezogen ist, ohne eine andere strecke zu kreuzen
(punkt = wand)


.p3.
.| …
.p2___p1.

das heißt konkret ich hätte 6 wand - strecken.

Aber: wie könnte ich algorithmisch auf diese kommen? Es wird ja immer komplexer, je mehr strecken ich habe… hat jemand eine idee, wie man das erreichen kann?
Alternative wäre natürlich, die einfach manuell zur map dazuzuschreiben… aber das wäre ziemlich umständlich…

Danke fürs lesen! :wink:

*** Edit ***

Hmm… Beim schreiben des posts kam mir eine idee, aber ich wüsste nicht wie ich das genau umsetzen könnte…
wie wäre es, wenn ich erst mal um jede strecke 4 wand strecken mache,
also aus

p1----p2

wird


.p1—p2.

und anschließend alle wandstrecken „herausschneide“ die eine andere strecke kreuzen…
ginge das? wie könnte man das implementieren?

3D ist was anderes als 2D,
die guten alten Gitterstrukturen, schon für Schach & Co. bekannt, sind dir bewußt?

ist es eigentlich relevant, ob Wand-Strecken doppelt vorkommen?
einmal an Ecken wie P2, wenn Wände an beiden Wege voll berechnet werden,

oder im Extrem zwei erlaubte Wege parallel gedacht mit Abstand einer Wand dazwischen:

.p3___p4.
.| #####
.p2___p1.

die #-Wand könnte komplett 2x berechnet werden, problematisch oder egal?

wenn Gitter relevant ist/ noch werden könnte, bei 3D sicher nicht selbstverständlich,
dann stelle ich Strecken für Wände komplett in Frage,
einzelne Punkte als Wände sollten reichen, nach und nach gesetzt,


ansonsten halte ich deinen Edit für einen guten Ausgangspunkt,
1)
modelliere die Punkte als Objekte mit Informationen, aus allen Wegstrecken aufgebaut:
es muss eine Methode für Verbindung in die 4 (Himmels-)richtungen geben,
es braucht eine Enum Direction für N, O, S, W oder andere 4 Werte,
eine Methode isEnd() für Punkte wenn nur in eine Richtung verbunden

für jede ursprüngliche Wegstrecke 2x Suche nach Wänden,
zu jedem verbundenen Punktepaar A und B einmal mit A, B aufgerufen und einmal mit B, A

die Punkte A_______B, egal wie ausgerichtet, werden zurechtgedacht und es geht dann um die untere Wand davon,
je nach A und B ergibt sich eine generelle Blickrichtung,
2)1) bei A wird geschaut ob von dort nach unten abgebogen wird, dann die Wand dort um 1 zu verkürzen
2)2) bei B wird geschaut ob von dort nach unten abgebogen wird, dann die Wand dort um 1 zu verkürzen
2)3) Wand aus den beiden vorherigen Informationen, der Blickrichtung und den Punkten A und B zusammenrechnen :wink:

Beispiel 1:
p2___p1, noch ganz normal, Blickrichtung Norden
(wie bestimmen? Unterschied in x-Koordinate, also Nord oder Süd, p2 liegt westlich von p1, also Nord),
bei beiden Punkten kein Abbiegen nach der Suchrichtung Süden,
aus den Punkten (0,0) und (100,0) ist komplette Wand, etwa (0,-1) und (100,-1) zu berechnen,
die Blickrichtung Norden sorgt für -1 auf y-Koordinate

p1______p2, also andersrum, Blickrichtung nun Süden (da p1 östlicher ist),
nun ist interessant ob die Punkte nach Norden abbiegen
(das muss alles automatisch bestimmt werden, Enum Direction mit Attribut Gegenrichtung usw., einmalig gesetzt, oft benötigt)

p1 biegt nicht ab, p2 biegt aber nach Norden ab,
ohne Abbiegen wäre zu (100,0) und (0,0) die erstellte Wand zu (100,1) und (0,1) (1 auf y wegen Blickrichtung Süden), weil p2 abbiegt dort einen weniger, was durch kreuz und quer umrechnen über welchen der beiden Punkte und welche Blickrichtung zu x um 1 größer führt, also (100,1) und (1,1)

ok, an dieser Stelle auch für mich beim Aufschreiben mal wieder der Komplexitätspunkt erreicht,
aber das sind alles nur einzelne Bestandteile, die man nach und nach einbauen und anhand von Beispielen exakt korrigieren kann,

die Beispiele für Blickrichtung Osten/ Westen spare ich mir mal, dann eben die Wand generell nach x statt y versetzt,
an den Ecken evtl. Korrekturen um 1 für y statt x nun, alles gewechselt,

idealerweise darauf achten dass nicht zuviel Code wiederholt wird, sondern mit Variablen arbeiten,
ModiferWand = (0,1) oder (0,-1) oder (1,0) oder (-1,0) usw.

wichtig bleibt: nur ein Algorithmus dieser Sorte, der für jede Wegstrecke 2x abgespult wird = alle Wände zwischen Punkten gefunden

alle Punkte noch einzeln durchgehen,
wenn sie Endpunkte sind, dann noch passende 3er-Endwand ergänzen,
für p1 (100, 0) etwa (101, 1) und (101,-1),
die einzige vorhandene Verbindung solcher Endpunkte gibt wiederum eine gewisse Blickrichtung vor,
aus der sich die Lage der 3er-Wand genau bestimmt

Ein klassisches Problem aus der algorithmischen Geometrie. @mymaksimus : dein im Edit geschriebener Ansatz passt soweit. Eine naive Implementierung ist sehr einfach und liegt von der Komplexität in O(n²). Bei einer normalgroßen Pacman-Karte ist das sicherlich schnell genug berechnet.
Ein besserer Ansatz wäre in O(n log n) realisierbar, wenn du die Strecken vor dem Vergleichen auf Schnittpunkte nach Koordinaten sortierst.

Entscheidend ist auf jeden Fall die Wahl der richtigen Datenstruktur, damit du sie effizient traversieren / sortieren kannst.

Der naive Algorithmus wäre ungefähr so:

für jede Strecke von Punkt zu Punkt s:
    für jede Wandstrecke w:
        wenn s und w sich schneiden:
            entferne w aus der Menge der Wandstrecken

um meinem Posting nicht komplett unkommentiert die Ohrfeige zu geben :wink: :
ganz so einfach mit Entfernen ist es ja nun nicht,
nur weil p2 nach Norden weitergeht wird die nördliche Wand zu p2___p1 nicht komplett entfernt!

was wäre das n in O(n^2)? die Anzahl der Punkte im betrachteten Universum, 100x100 = 10.000 oben? das wäre etwas viel,

für die Anzahl der Punkte p1, p2, p3 n=3 sehe ich Notwendigkeit O(n^2) nicht, es müssen doch nur verbundene Punkte, vorhandene Strecken betrachtet werden,
(vorausgesetzt jede Strecke ist einzeln benannt, nicht ein Kreuz bzw. Pluszeichen + mit nur zwei Strecken, den 4 Außenpunkten beschrieben,
ohne den Mittelpunkt je zu erwähnen, dann wäre es in allen Fällen schwieriger, aber man könnte ja in Vorstufe Punkte und Strecken ergänzen/ normalisieren)

Sry, das war nicht meine Intention.

[QUOTE=SlaterB;109247]ganz so einfach mit Entfernen ist es ja nun nicht,
nur weil p2 nach Norden weitergeht wird die nördliche Wand zu p2___p1 nicht komplett entfernt![/QUOTE]
Du hast recht, die Wand muss gesplittet werden und nicht entfernt. Vom Aufwand her ist es aber nicht mehr, als im Pseudocode beschrieben. Der Algorithmus selbst lässt sich also in 4 Zeilen (wenn man Klammern und Methodensignatur nicht mitzählt) schreiben.
Wichtig ist, wie oben ja schon angedeutet, die Datenstruktur. Die Pfade sollten meiner Meinung nach eine Methode intersects(Wall) und die Wände eine split(Position) anbieten.
Ansonsten ist die Struktur wohl ziemlich einfach (irgendwas graphartiges sollte das wohl sein, wahrscheinlich doppelt verknüpfte Kanten, um die Aufsplittung effizient machen zu können).
Die von dir beschriebene Struktur halte ich für zu kompliziert - Richtungsinformationen sind gar nicht notwendig, da ja nur der Aufbau und kein unidirektionaler Weg beschrieben wird.

[QUOTE=SlaterB;109247]was wäre das n in O(n^2)? die Anzahl der Punkte im betrachteten Universum, 100x100 = 10.000 oben? das wäre etwas viel,

für die Anzahl der Punkte p1, p2, p3 n=3 sehe ich Notwendigkeit O(n^2) nicht, es müssen doch nur verbundene Punkte, vorhandene Strecken betrachtet werden,
(vorausgesetzt jede Strecke ist einzeln benannt, nicht ein Kreuz bzw. Pluszeichen + mit nur zwei Strecken, den 4 Außenpunkten beschrieben,
ohne den Mittelpunkt je zu erwähnen, dann wäre es in allen Fällen schwieriger, aber man könnte ja in Vorstufe Punkte und Strecken ergänzen/ normalisieren)[/QUOTE]
Ob man für die Anzahl n die Anzahl Punkte, Anzahl Strecken zwischen Punkten oder Anzahl Wände einsetzt, ist egal, weil das nur ein konstanter Faktor wäre. Exakter gesprochen wäre es eigentlich statt n² Anzahl Wände * Anzahl Strecken. Komplexitätstheoretisch betrachtet läuft es aber auf O(n²) heraus, da die Anzahl Wände in etwa der Anzahl Strecken * 4 entspricht und somit als konstanter Faktor wegfällt bzw. in der selben Komplexitätsklasse liegt.

Edit: 3D-Betrachtungen habe ich außen vor gelassen, weil ich denke, dass mit „3D-Version“ gemeint ist, dass die Darstellung dreidimensional erfolgt. Die Levels sollen aber, so wie ich es im ersten Posting lese, eine zweidimensionale Struktur haben.

nun, der Aufwand ist linear, O(n), dass ist schon ein ziemlich wichtiger Unterschied zu O(n^2) auf den es sich zu achten lohnt,

jeder neue einzelne Punkt/ Strecke hinzugefügt macht nur lokal dort neue Arbeit konstanter maximaler Größe,
mit den Nachbarpunkten, zu denen zum Glück Positionsangaben vorhanden sind,
es besteht am Anfang Beadarf für einmalig Suche für neue Elemente in bisherigen Modell/ Verlinkung, dafür mag O(n log n) ins Spiel kommen,

aber sobald das Modell in Objekten vorhanden ist, ist die Arbeit linear,

mit sämtlichen Elementen im evtl. sehr großen sonstigen Modell zu vergleichen wäre schrecklich,
anschaulich ist vielleicht Einfügen einer neuen Straße in OpenStreetMap

Aaalso Leute.
Ich Idiot merke gerade, dass sich pacman eigentlich nur mit einem gitter realisieren laesst, das heisst wenigstens vorgegebene schrittweise.
Das problem ist, bei freier bewegbarkeit kann man abzweigungen ueberhaupt nicht betreten, weil man sie einfach nicht treffen wuerde.

Aber selbst bei einem gitter bleibt dieses problem ja bestehen, nur dass das was ich eben schreiben wollte dann nicht zutrifft: was waere wenn strecken diagonal waeren und sich nicht auf die vier himmelsrichtungen beschraenken wuerden.

Ja, die erkentniss ist richtig, es ist eine 3d darstellung, aber eben in x, z aufteilung, y sorft nur fuer die… naja darstellung eben.

Ich versteh nicht wieso ich immer mit so kleinen problemchen, wie sie mir erst scheinen, so grosse themengebiete erwische… aber das klingt auf jedenfall interessant. Ich lese mir nachher in ruhe mal eure Vorschläge und ansätze durch, und versuche das mal zu implementieren. Danke euch! :slight_smile:

bei jedem solchen ‘was waere wenn’ wären manuelle Beispiele dazu ganz gut,

  • falls wirklich nur Diagonalen dazukommen, dann 8 statt 4 Richtungen,
  • falls beliebige Winkel: welche Art von Wänden sollten dann entstehen, wie die Ecken, spitz, wie in ‘Weg-Strecken’ ausgedrückt, welche Endpunkte?
  • falls man noch von Punkten in Gittern denken kann (statt hohe Auflösung und dann Koordination im Millionen-Bereich) dann wäre interessant, wo genau von einem Punkt x,y aus gesehen bei Ecken != 90 Grad Punkte in der Nähe auch frei sind oder Wände

xx  xxxx
xxx  xxx
      Ex
xxxxxxxx

grundsätzlich fiel mir bei meinem ersten Posting diese Variante auch ein, die Grundmechanismen funktionieren dabei noch,
per Vektorrechnung kann man aus den beiden betrachteten Punkten einer Strecke die “Blickrichtung” beliebig bestimmen und damit auch die Wandstrecke grundsätzlich,
das wird ja immer weniger trivial wenn schräg daneben, alles schon mit drin,

aus der Blickrichtung ergibt sich auch, auf welches Abbiegen (welcher Winkelbereich) zu achten ist,
je nach Art der Ecke ist dann auf irgendeine gewünschte Weise die Wand zu kürzen,
Details über Details, aber möglich


nein nein, ein Gitter ist viel schöner falls, wie gesagt, du dann nicht aus irgendeinem Grund immer noch die Wände als Strecken brauchst,

zeichne in ein Gitter von Punkt-Objekten erst die gegebenen Wegstrecken ein, alle entsprechenden Punkte markieren als ‘Weg’,
dann über sämtliche Gitterpunkte iterieren, schauen ob einer der 8 Nachbaren ein Weg ist, selber kein Weg -> Wand,
falls nicht gar schlicht sämtlich anderes im Gitter schon automatisch Wand ist,

für Anzeige und Spiellogik usw. reicht das vollkommen, es braucht keine Wand-Strecken

(das wäre dann nun wirklich als O(n^2) für überschaubares n an Gitterpunkten, oder schlicht konstanter Aufwand für Größe der Karte,
bei sehr weiten dünn besetzten Karten könnte man wiederum nebenbei bei Eintragung der Strecken arbeiten)

Naja doch. Bei 2d mag das der fall sein. Da hab ich einfach vierecke die ich zeichne. Aber wenn ich in 3d richtige waende haben will, mit eck verbindungen und so weiter, dann brauch ich da die genaue geometrie, also auch die strecken…

Genau daher kommen die O(n log n), von der Sortierung der Ausgangsmenge. Die Operation auf einer sortierten Menge kann dann in linearer Zeit erfolgen.

Das Problem dabei ist allerdings, dass der Algorithmus deutlich komplexer wird. Diesen Aufwand würde ich wahrscheinlich für eine Pacman-Map, die sicherlich aus weniger als 1000 Pfaden besteht, betreiben.

Meine natürlich “nicht betreiben”.

Also ich hab keine Ahnung von 3D Programmierung mit Java aber normalerweise gibt es für die Erstellung eines 3D Levels 2 Ansätze: Die Welt ist leer und baut etwas hinein (vergleichbar mit ein Haus bauen) oder die Welt ist voll und man schneidet was heraus (vergleichbar mit eine Mine graben).
Für ein Pacman würde ich hier eher den 2. Ansatz verfolgen. Du schneidest die Pfade zwischen deinen Punkten einfach raus. Dann musst du dich auch gar nicht großartig um Wände etc. kümmern. In wieweit das mit java geht weis ich aber nicht.

bertor, das klingt zwar interessant, aber ich habe nicht wirklich eine vorstellung wie man das konkret umsetzen könnte.
Es scheitert bestimmt nicht an java, aber ich habe keinen blassen schimmer wie genau du das meinst…

Also. Ich habe jetzt erst einmal das gemacht, was @SlaterB geschrieben hatte.
Sieht jetzt so aus:

das problem, wie gesagt, um die wände “1” dick zu machen, und nicht diese hässligen blöcke da stehen zu haben, brauche ich eben
doch die wandstrecken. Also muss ich doch eure erklärten algorithmen versuchen zu implementieren…

Na ganz einfach: Was du machst ist Objekte in eine leere Welt stellen. Überall wo kein Objekt ist, kann sich der Spieler hinbewegen.
Das Gegenteil ist, wenn die Welt voll ist. Das heisst, der Spieler kann sich nur dort bewegen, wo du einen Hohlraum aus der Welt herausschneidest.

ja, aber das bringt mir so nichts. ich schneide ja nur theoretisch etwas heraus, es kann ja nicht überall geometrie existieren.
letzten endes fügst du genauso 3d objekte zur welt hinzu wie bei der anderen methode.

unter “1” dick machen kann ich mir gerade gar nichts vorstellen,
ein Bild zu einem Beispiel mit manuell errechneten Wandstrecken wäre ungemein wertvoll,
auch etwas für den evtl. geplanten schrägen Fall oder bleibt es vorerst derart eckig?

ich bin guter Hoffnung, dass du mit meiner Antwort von #2 irgendwo hinkommen könntest,

wenn man die Bilder so sieht, es bei diesen eckigen Wegen bleibt,
dann sollte es eigentlich auch nicht so schwer sein, die Wände weiter zu modifzieren, Breite reduzieren usw.,

von Gitter aus mit Bausteinen arbeiten:
‘wenn Feld A eine Wand hat und drei freie Nachbarn sowie einen Wand-Nachbarn nach Norden,
dann zeichne dort ein Wandstück was bis nach Norden zum nächsten Feld grenzt,
aber in die anderen drei Richtungen dünner als volle Feldbreite’

oder missfallen dir speziell die sichtbaren Linien zwischen den Feldern?
da gibt es doch bestimmt auch eine geeignerere Textur für sauberen Übergang,

aber natürlich auch möglich dass es durchgehend eleganter wird,
wobei das die senkrechten Wandstrecken betrifft,
von oben aus dürfte es bei Kurven/ Ecken noch schwierig werden

Wege gleich zwei Felder breit wäre auch eine Variante,
zumindest bei Gitter alles mit der Zeit leicht aufzubauen, in Strecken auszudrücken…

Nein, also die textur ist nicht das problem. Darum gehts nicht.

[quote=SlaterB]von Gitter aus mit Bausteinen arbeiten:
‚wenn Feld A eine Wand hat und drei freie Nachbarn sowie einen Wand-Nachbarn nach Norden,
dann zeichne dort ein Wandstück was bis nach Norden zum nächsten Feld grenzt,
aber in die anderen drei Richtungen dünner als volle Feldbreite‘[/quote]

ich fühle mich gerade wie der dümmste mensch der welt. genau das brauche ich nämlich…
da es ein gitter ist brauch ich ja nicht die strecken… mensch… das ärgert mich gerade. aber danke :slight_smile:

Ich poste mal ein bild sobald ich’s hab ^^

aber… danke! :smiley:

*** Edit ***

Ich hab so ein leises gefühl… das ich die strecken irgendwann doch brachen werde… weiß aber nicht warum… naja.
ich werde das erst mal so machen. ich hätte trotzdem lust die algorithmen mal auszuprobieren, wer weiß ob ich das noch einmal irgendwann brauche…

Hab mitgelesen/quergelesen und mir wird jetzt langsam auch das Probl. klar.

  1. (Frage) Du darfst “Welt” nicht verändern (/entfernen), willst aber Wege/Wände hinzufügen (/entfernen)?

  2. Für jede Kante muss berechnet werden, ob eine der anderen “n” Wände sie kreuzt. n^2

Wann ist das nicht der Fall? … n log n fällt mir gerade nicht ein, wie würdet ihr Wände sortieren?

… allgemein … wieso “zeichnest” du nicht einfach die Wege, dann die “Wände”??

Also Welt, Wege, Wände, Kanten, Gitter, 2 -d, 3 -d, O -Notation, jetzt bin ich auch durcheinander. (btw) Brauchst du das später? yagni (anderer Kontext, egal) — mir einfach glauben.^^

Edit: Klar, nach Überschneidung(en) sortieren, ja auch logisch, … ich hätte bei Weite > Höhe von li. nach re. sortiert.

ich ignoriere mal (wie eigentlich immer, sorry…) Cyborgs schwer lesbaren text, und poste hier mal mein ergebnis ^^

so siehts momentan aus:

die texturen sind im mom nur da, um überhaupt etwas zu sehen, werde das alles noch schöner bzw weniger hässlich machen ^^

*** Edit ***

falls jemand lust zu meckern hat, hier ist der aktuelle code um die wände zu erzeugen :smiley:

		ArrayList<Float> data = new ArrayList<>();
		MapTile mapTiles[][] = map.getMapTiles();
		float wallWidth = map.getScale() * 0.5f, wallHeight = 5;
		for(MapTile tileRow[] : mapTiles){
			for(MapTile tile : tileRow){
				if(tile.getType() == TileType.WALL){
					Direction directions[] = Direction.values();
					for(Direction d : directions){
						MapTile neighbourTile = map.getNeighbourMapTile(tile, d);
						if(neighbourTile != null && neighbourTile.getType() == TileType.WALL){
							addWall(data, tile.getPosition(), wallWidth, wallHeight, d);
						}
					}
				}
			}
		}
		float dataArray[] = new float[data.size()];
		for(int i = 0; i < data.size(); i++){
			dataArray** = data.get(i);
		}
		return new AGLMeshData(dataArray, AGLDrawMode.TRIANGLES);
	}
	
	private void addWall(ArrayList<Float> data, Vector3f position, float wallWidth, float wallHeight, Direction direction){
		float xInDirection = position.x + wallWidth * direction.getVector().x;
		float zInDirection = position.z + wallWidth * direction.getVector().z;
		Vector3f p1 = new Vector3f(xInDirection, wallHeight, zInDirection);
		Vector3f p2 = new Vector3f(xInDirection, 0, zInDirection);
		Vector3f p3 = new Vector3f(position.x, wallHeight, position.z);
		Vector3f p4 = new Vector3f(position.x, 0, position.z);
		addDataRow(data, p1, new Vector2f(0, 0));
		addDataRow(data, p2, new Vector2f(0, 1));
		addDataRow(data, p3, new Vector2f(1, 0));
		addDataRow(data, p2, new Vector2f(0, 1));
		addDataRow(data, p3, new Vector2f(1, 0));
		addDataRow(data, p4, new Vector2f(1, 1));
	}
	
	private void addDataRow(ArrayList<Float> data, Vector3f point, Vector2f vt){
		data.add(point.x);
		data.add(point.y);
		data.add(point.z);
		data.add(vt.x);
		data.add(vt.y);
	}```

Kleinigkeiten zum Code:

float zInDirection = position.z + wallWidth * direction.getVector().z;

MapTile neighbourTile = map.getNeighbourMapTile(tile, d);

in den oberen beiden Zeilen wird nach dem Code aus anderen Thread 2x Vector erzeugt, lokale Variable würde helfen,
zur Bestimmung der NeighbourMapTile wird wohl auch nicht viel Vector gerechnet sondern einzelne Koordinaten für Array oder so?

sieht langsam so aus als wären reine int-Attribute in Direction besser

wieso braucht es eigentlich 6 Richtungen in 3 Dimensionen in Direction, hier in diesen beiden Anwendungen anscheinend nur die 4 Himmelsrichtungen in 2D interessant,
und die Koordinaten dafür sind x und z, nicht x und y? gefährlich für eine simulierte platte 2D-Welt

mag sein dass 3D-Direction für anderes noch nützlich ist, aber hier, etwa in der Suche for(Direction d : directions){ nach Nachbarn kaum,
falls du nicht auch schon mehrere Ebenen übereinander einplanst,
wenn nicht mehrere Ebenen dann nicht zu schade sein eine zweie Enum mit nur 4 Elementen einzuführen


        addDataRow(data, p2, new Vector2f(0, 1));

falls es nicht noch andere Aufrufe von addDataRow() gibt, dann ist der erzeugte Vector2f neben Schreibaufwand unnütz, in der Methode werden x und y wieder herausgeholt

        addDataRow(data, p2, 0, 1);

wäre lesbarer

sind eigentlich alle 6 Zeilen dort nötig, zwei in Wiederholung? aber kenne das 3D ja nicht,
falls das mehr als 1x für Zeichnen von Vierecken vorkommt, dann die 4 bis 6 magischen 0,0 bis 1,1 besser nicht wiederholen, in eine Methode mit den 4 Wandpunkten als Parameter


bei den Wänden wäre hier eine recht deutliche Vereinfachung möglich:
ziehe immer eine durchgehende Wand von Mittelpunkt zu Mittelpunkt, dann musst du dich mit wallWidth und Direction-x-z nicht abgeben,
und weniger Einzelobjekte in der 3D-Welt, weniger Übergänge

um keine Wände doppelt zu zeichnen hilft ein allgemeiner Trick: zu jedem Tile immer nur nach Nachfolger in zwei Richtungen schauen, etwa Süden und Osten
(+ noch nach oben falls 3 Dimensionen)

evtl. auch rekursiv/ per Schleife Wände immer weiterziehen solange in eine Richtung weitere Nachbar-Tiles folgen,
da hast du dann auch deine Wände in Komplettbeschreibung :wink:
nur einen Data-Eintrag vom eigenen Tile-Mittelpunkt bis zu dem weitesten auf der Wand-Linie

wenn diese zusätzlichen Tiles dann später in der Schleife noch durchlaufen werden, die Erzeugung weiterer Wände verhindern,
entweder durch Markierung oder durch Prüfung ob es einen Nachbar in der Gegenrichtung gibt,
wenn ja dann wird wohl von dort aus vorher eine Wand durchgezogen worden sein