Dies ist eine alte Version des Dokuments!
Mitglieder: Alex, Magdalena L., Sebastian
Modellierungen einer 2-dimensionalen Landkarten, mögliche Ziele wären dann noch die Modelierung von Strukturen auf der Karte wie zum Beispiel: Wälder, Berge, Häuser und weiteres.
Informationen zu Höhenunterschieden, Flussläufen… sollen dabei generiert und zu einer möglichst realistischen Karte verarbeitet werden, Wälder… sollen danach in die Karte integreirt werden und dabei von den Höhen- und Flussstrukturen abhängen.
Unser Projekt soll möglichst realitätsnahe Landschaften generieren, dazu können Erosionssimulationen gehören, aber auch die Auseinendersetzung damit, wie ein klassischer Flusslauf aussieht und wie dieser im Code umgesetzt werden kann. All das können wir aber erst umsetzen, wenn wir eine sonst weitest gehend Funktionierende Grundlage haben, die mehr Zeit in Anspruch nimmt, als wir es erwartet hatten.
Den Code haben wir auf mehrere Dokumente verteilt, die je eine der unten genauer beschriebenen Klassen enthalten. So ist der Code gut lesbar und leichter zu verstehen.
Um eine Höhen zu generieren haben wir Perlin-Noise genutzt. Dabei wird für Stellen im regelmäßigem Abstand eine Steigung generiert, diese Steigungen bzw. Vektoren werden dann mit einer Funktion so verbunden, dass jese Stelle der Karte eine Höhe zugewiesen bekommt. Diese Höhen haben wir dann auf Höhen von einem Minimum von 0.0 bis zu einem Maximum von 1.0 normalisiert.
Einen Code für ein Eindimensionales Perlin-Noise haben wir selbst geschrieben, danach haben wir gemerkt, dass es dafür ein Pythonpaket gibt, das wir von da an für unsere Karte verwendet haben.
Um die Höhen darzu stellen haben wir mit
measure.find_contours()
Höhenlinien berechnet. So werden Contouren zurückgegeben, die so verteilt sind, das sie an den Stellen liegen, an denen sie ungefähr liegen müssten, wenn eine tatsächlich abgerundete Karte vorläge. Die berechneten Conturen visualisieren wir als pyglet Line.
Die Bergspitzen werden gefunden, indem die Höhe von jedem Pixel mit der, der umligenden verglichen wird. Liegt der geprüfte Pixel höher als die umligenden, wird er in einer Liste gespeichert. Anschließend wird geprüft, wie nah die Punkte bei einander liegen. Ist der abstand kleiner als 5 wird der Punkt aus der Liste gelöscht. Dargestellt werden die Bergspitzen als pyglet Circle.
Als Wasserelemente wollten wir einerseits einen Meeresspiegel, andererseits Flüsse und Seen kreiren.
Als Meeresspiegel haben wir die Höhe 0.3 gewählt. Für die Konturlinien wird wieder measure.find_contours() verwendet.
In der Visualisierungs-Funktion kann nun die Anzahl der Wasserquellen festgelegt werden. Nun werden für diese Anzahl an Punkten ein zufälliger Punkt auf dem Grid als Flussquelle festgelegt. Da Flüsse meist in Gebirgen entstehen, haben wir hier festgelegt, dass die Quellen je eine Höhe von über 0.5 besitzen muss.
Für jeden dieser Ursprungspunkte wird nun ein Fluss erstellt. In der Funktion
Water.flussverlauf_erstellen()
wird immer der niedrigste Nachbar eines Punktes gewählt und zum nächsten Teil des Flußverlaufs gemacht. Dies wird so lange gemacht, bis kein Nachbar des momentanen Punktes höher als dieser ist. Dieser Punkt ist dann das Ende des Flusses und an diesem Punkt entsteht dann ein potenzieller See.
Zur Visualisierung des Flusses wird dann das in Pyglet enthaltene BezierCurve shape verwendet, um der natürlichen Form eines Flusses näher zu kommen.
Um die Höhe des Sees zu bestimmen wird die Funktion
Water.level_bestimmen()
verwendet. Die Funktion sucht immer den Punkt mit der niedrigsten Steigung, welcher noch nicht 'gechecked' wurde und sich somit die niedrigste Stelle wo der See übertreten und wieder in einen Fluss münden würde.
Auf dieser Höhe wird dann die Konturlinie gezeichnet. Für jede Kontur auf diesem Level wird der durchschnittliche und der minimale Abstand zu der Mitte des Sees berechnet. Wenn die Kontur mit dem niedrigsten Abstand zu der Mitte des Sees (Endpunkt des Flussverlaufs) nicht mit der Kontur des niedrigsten durchschnittlichen Abstandes übereinstimmt, wird geguckt ob die Kontur sich am Rande des Grids befindet, weil das die Werte der Abstände 'verfälschen' kann. Diese Funktion entscheidet sich leider nicht immer für die richtige Kontur, aber liegt schätzungsweise zu in 80% der Fälle richtig.
Wenn man nicht auf die Größe der Seen achtet, bekommt man hin und wieder leider sehr große Seen, die nicht so gut auf der Karte aussehen. Deshalb wollten wir diese Seen vermeiden und haben Seen, dessen Umriss (Liste aus Punkten) größer als 64 ist, nicht zugelassen. Wir haben hierbei die Länge 64 gewählt, weil es auch die Länge ist, die das Polygon Shape in Pyglet maximal haben kann, welches wir zu der Visualisierung der Seen verwenden.
Falls ein See Umriss jetzt länger als 64 ist, wird solange von der Höhe des Sees 0.01 abgezogen, bis die Länge des Sees unter 64 ist.
Was wir leider nicht mehr in der Zeit fertigstellen konnten war, dass aus den Seen dann wieder Flüsse entstehen. Das Problem, welches wir am Ende hatten war, dass der neu entstehende Fluss in vielen Fällen einfach wieder zurpck in die Mitte des Sees floss, anstatt weiter zu fließen.
Die Visualisierung Klasse hat nur eine Funktion, doch diese Funktion steuert die gesamte Generation. Diese Funktion ruft die heightmap-Funktion, sowie die water-Funktion und die Funktion zur Erstellung der Biome.
Mithilfe dieser Funktion kann man auch noch einige Variablen verändern. CELL_SIZE ändert die Größe einer einzigen Zelle auf der Karte, xpix und ypix verändern die Anzahl an 'Zellen' im Grid. Die anzahl_wasserquellen-Variable bestimmt wie viele Wasserquellen auf der Karte generiert werden. Die abstand_linien-Variable gibt an in welchem Abstand die Höhenlinien gezeichnet werden soll.
Außerdem übernimmt die Funktion auch das Einfärben der Karte und das Zeichnen der Batches mithilfe der
on_draw()
Funktion von Pyglet. Zuletzt hat diese Funktion noch eine
on_mouse_press()
Funktion. Wenn man auf die Karte clickt, werden die Koordinaten des Punktes, sowie die Höhe des Punktes gedruckt.
Erste Inspiration
https://de.wikipedia.org/wiki/Perlin-Noise
Perlin-Noise-Paket hier
https://de.wikipedia.org/wiki/B%C3%A9zierkurve