Open World Generator - J&R

    • GM 8

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Open World Generator - J&R

      Hallo Gemeinde,
      ich beschäftige mich momentan mit dem Konzept eines Open World Generators bei einem PLatformer(will heißen maps erstellen sich von alleine und per zufall).

      Nun zur Frage: Wie gehts man so etwas an?
      Woraus bestehen die Einzelnen segmente der Map? tileset? Objekte?

      Was ich gehört habe ist, das man etwa eine art Oberflächenlinie erstellt, und von dieser aus den rest per zufall macht. So oder so ähnlich.

      Danke schonmal im vorraus.
      lg Partik

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Partik ()

    • oh Natürlich :D.
      Grid, Platformer, Natürlich von der Seite. So als wollte man Minecraft in 2D Nachbauen(Das will man nicht)
      Obwohl das ja eigentlich auf andere 2d Spiele Übertragbar Sein Sollte.
      1# EDIT

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Partik ()

    • Grundsätzlich werden halt Objekte (und Tiles) per Code plaziert. Mir hat das großen Spaß gemacht, mit raffininertem Code (aus meiner Sicht, lol) einen leeren Raum mit Zeug zu füllen. Bei mir war "ds_grid" da eine wichtige Sache. Aber bevor es da konkret wird, braucht man schon einen Ansatz von Game Engine denke ich.
    • Na dann werde ich mich hier mal zu Wort melden. ^^
      Ich bin kein Experte was Map-Generation anbelangt, jedoch werde ich versuchen da so gut wie nur möglich auszuhelfen.

      Nun, zuerst müssen wir ein paar dinge über das Gameplay des Spiels wissen bevor man überhaupt an einen Levelgenerator denken kann.

      Wie genau stellst du dir das Spiel vor? Sind alle Gegänstende wie Bäume einfache Objekte?
      Oder basiert alles auf Tiles?

      Wies ollen die Maps aufgebaut sein? Blockartig (wie minecraft) oder eher in der richtung Super Mario?

      Da du ein Open World Spiel machst, wird die Sache ein wenig erschwert. Wenn du eine Map nach nur einem Durchlauf generieren möchtest, kann die generierung sehr lange in Anspruch nehmen (Je größer die Map, desto länger dauert die Prozedur.)
      Eine Möglichkeit hierbei wäre eine Procedurale Generierung (sprich: Teile der Map werden nach und nach dazugeneriert). Dies ist jedoch ein etwas schwereres Unterfangen. Man muss sich da in seinem Script sehr gut auskennen um den Überblick darüber nicht zu verlieren. (Mich hat die implementierung solch eines Systems mehre Tage gekostet... Natürlich mit debugging)

      Also wie gesagt, beantworte mir erstmal die Fragen, dann kann ich weitersehen was die beste Lösung wäre.
    • Wie genau stellst du dir das Spiel vor? Sind alle Gegänstende wie Bäume einfache Objekte?
      Oder basiert alles auf Tiles?

      Objekte.
      Es gibt zudem nicht sehr viele Objekte: Stein, Erde(andere folgen eventuell.).
      Es geht nur darum eine Zufällige "Arena" für einen zweikampf zu bilden. Alles was nicht Wand ist, soll nicht zufällig, sondern später vom Spieler erstellt werden.
      Wies ollen die Maps aufgebaut sein? Blockartig (wie minecraft) oder eher in der richtung Super Mario?


      Blockartig. Und da das ganze auf Spielereingaben basiert, müssen Platformen nicht unmittelbar erreichbar sein.

      Da du ein Open World Spiel machst, wird die Sache ein wenig erschwert. Wenn du eine Map nach nur einem Durchlauf generieren möchtest, kann die generierung sehr lange in Anspruch nehmen (Je größer die Map, desto länger dauert die Prozedur.)

      Das mit dem Openworld ist villeicht nicht so wichtig. Es kann auch begrenzt sein. Mich Interessiert erstmal der generelle Ansatz, das baut ja aufeinander auf, als ob man mehrere kleine Räume aneinander hängt.
    • Also ich nehme mal an du arbeitest mit Grids.

      So wie du anfangs sagtest würde ich auch eine "höhenlinie" quer durch die Map ziehen, die das Basisterrain darstellt.
      Die Frage ist nur: wie setzt man das um?

      Dabei gibt es 2 Möglichkeiten: Entweder benutzt du Heightmaps (SDX hat da mal einen Perlin script gemacht) und liest aus dieser Heightmap die einzelnen Pixelwerte raus. (je Heller, desto weiter ist die Ebene oben)
      oder (was ich gemacht habe) du benutzt ganz einfache zufallswerte.
      Du gehst mit einer For-Schleife in der x-Ebene von links nach rechts. Dabei hast du einen y-Pointer der die aktuelle Höhe auf er x koordinate ist. Du addierst zu der aktuellen y- Koordinate jedesmal einen Zufallswert, je weiter du nach rechts gehst.
      Dabei sollte der Wert im + und - Bereich gleich groß sein (z.B: Ein Zufallswert zwischen -3 und +3)

      Auf die Art udn weise bekommst du auch ein Terrain raus. Nachdem du nun die "Höhenlinie" gezogen hast, gehst du das Grid nochmals durch. Dabei gehst du mit einer weiteren For-Schleife von unten nach oben (solange bis die Höhenlinie auf der x-Koordinate erreicht wurde). Dabei befüllst du es mit Werten die z.B: Erde darstellen.

      Das ist im Prinzip ein Terraingenerator. (Zwar kein guter, aber immerhin einer der funktioniert.)

      Wie man des mit dne Plattformen richtig lösen kann weiss ich nciht. Du wirst da evtl mit einfachen Zufallswerten Arbeiten müssen.
    • Nach einer kleinen Schaffenskriese ist folgendes entstanden:
      code falls es wen interessiert
      Spoiler anzeigen
      grundlinie=xyz//Variable die die grundlinie angibt
      grunddif=xyz//wie weit ein block von der oberlinie entfernt sein darf
      set=xyz//differenz zum neuen y wert(-1, 1 block nach oben usw)

      GML-Quellcode

      1. while (xx!=room_width/32)
      2. {
      3. instance_create(xx*32,yy*32,block)
      4. if yy>grundlinie-grunddif && yy<grundlinie+grunddif
      5. {
      6. set=choose(1,0,-1)
      7. }
      8. else if yy=grundlinie-grunddif
      9. {
      10. set=choose(1,0)
      11. }
      12. else if yy=grundlinie+grunddif
      13. {
      14. set=choose(0,-1)
      15. }
      16. yy+=set
      17. xx+=1
      18. }
      Alles anzeigen


      dabei entsteht im besten fall noch soetwas abwechslungsreiches:
      nur würd eich diese kleinen außreisser gerne wegbekommen(wie beispielsweise der 3. block von rechts)

      hat da jemand eine idee?
    • Nach so ziemlich diesem Prinzip arbeitet auch mein Mapgenerator. :D
      Der ist aber bezüglich des Terrains ein wenig mehr "ausbalancierter". (Sprich: Je weiter der "pointer" von der Grundlinie entfernt ist, desto größer die Wahrscheinlichkeit dass dass Terrain wieder in Richtung Grundlinie geht.)
      Ich schau mal ob ich aus diesem Code wahnsinn die essentiellen Abschnitte dafür rausbekomme.

      Bezüglich der Außreiser:
      Diese tauchen auch bei mir auf. Aber grundsätzlich sollten sie leicht zu umgehen sein. Du prüfst einfach nur ab, ob der block gestiegen oder gesunken ist. Wenn dies der Fall ist, darf er das nächste mal z.B: 2 oder 3 Blöcke lang nicht mehr in die entsprechende richtung "zurückspringen".
      Sollte eigentlich leicht zu implementieren sein.
    • Perlin ist keineswegs in der Anzahl von Dimensionen begrenzt. Du kannst ohne Probleme auch einen 1D Perlin generieren, um so die Sideview Map zu generieren. Dafür habe ich allerdings gerade kein Script. Aber wenn du dich mit dem Prinzip von Perlin auseinander setzt, sollte es kein Problem sein, etwas zu Zaubern. Schwerer als 2D oder 3D Perlin wird es auf jeden Fall nicht ;)
      1D Perlins kannst du auch viel einfacher unendlich machen, um so eine Unendlich große Map zu generieren. Mit Chunks und so.


      Mein Wissen für meinen Script holte ich mir damals hier. Sehr interessant, sollte jeder einmal gelesen haben.

      EDIT: die im Artikel als Pseudecode vorhandene Funktion für 1D perlin ist eigentlich was du suchst. Übergebe der Funktion die x-position, und du bekommst die Höhe/Wert wieder. Für unendliche Maps perfekt!
      EDIT: die erste Funktion ist einfach eine Random-alternative. Du kannst genau so gut GMs Random mit Seed nutzten.

      MfG SDX

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von SDX ()

    • Das mit dem Perlin noise wäre da natürlich die bessere alternative.
      Die ergebnisse dürften hierbei qualitativ besser sein als die des "einfachen" Mapgenerators.
      Ich habe es jedoch nciht gebacken bekommen die Perlin noises miteinander "zu verschweißen". Sprich: Chunkübertragung funktionierte bei mir nicht. Ich habe die Logik dahinter zwar mehr oder weniger verstanden, dennoch war das anscheinend eine (noch) zu schwere aufgabe für mich.

      bzw @ Patrik:
      Willst du überhaupt auf chunks zurückgreifen oder belässt du es bei einer Welt die vollständig ins Spiel geladen bzw im Spiel generiert wird?

      Bei meinem generator ist es z.B: so dass ich einfach den letzten Block der "Höhenlinie" einfach an des entsprechende Nachbarchunk übergeben wird. Wird das nächste chunk generiert, wird einfach auf den Y-Wert des Blocks zurückgegriffen. an dieser stelle beginnt der generator an zu arbeiten. Ziemlich simpel.
    • Ich habe mich mal hingesetzt und was gebastelt. Ich weiß, dass hier ist die Expertenrunde, ein Link zum Pseudocode hätte reichen sollen.

      Ich habe es so weit implementiert bekommen, scheitere aber an einer merkartigen Sache. Im Beispiel, welches abgehangen ist, wird man sehen können, dass nur jeder 15te Wert etwas taugt. Egal wie sehr ich an den Parametern drehe, es ist und bleibt jeder 15te. Zufall ist ein schwerer Tanzpartner.

      Vllt kann sich das jmd anschauen. Ich würde nicht empfehlen nur jeden 15ten Wert zu nutzen, aufgrund der Performance ;)
      Ich vermute GMs seed für Random als Fehlerquelle

      Nachschlag:
      Es ist der Seed. Wenn ich den (in noise()) mit 1.5 multipliziere ist es nur noch jeder 10te. Bei multiplizieren mit 15 ist es allerdings kein Perlin mehr.


      MfG SDX
      Dateien
      • 1Dperlin.rar

        (10,04 kB, 263 mal heruntergeladen, zuletzt: )
    • Wow, das läuft hier ja auch ohne mich :D
      Ich bin leider mit dem verständnis noch nicht weit genug gekommen, um das jetzt nachvollziehen zu können.
      und einfach die vorgegebenen pseudocodes umschreiben wollte ich auch nicht.
      Das mit den Perlin Noise hört sich für mich nach einer vielversprechenden lösung an.

      @Lewa: JA das überlege ich mir auch gerade. wäre ja eigentlich relativ sinnvoll, dann könnte man auch einfach chunk per chunk speichern.
      Bis jetzt Stehe ich vor einer Idee, ich habe noch nichts davon in mein Spiel Implementiert, momentan arbeitet dieses mit einer vorgefertigten map: ich bin für alles offen.

      Ich werde mir das Toturial noch einmal in ruhe ansehen, und mich dann erneut melden. Fühlt euch aber bitte frei hier weiter zu diskutieren das hilft mir ungemein weiter!(ma im ernst):D
    • @SDX
      Habe mir jetzt den Algorithmus nicht im Detail angeschaut, aber ich denke das Problem liegt einfach darin, dass vor jedem Aufruf von random ein neuer Seed gesetzt wird. Die Absicht dahinter ist mir zwar klar, aber ich denke die meisten Zufallszahlengeneratoren sind nicht darauf ausgelegt, dass die Folge der ersten Zufallszahl für eine Folge von Seeds zufällig ist. Wenn man beispielsweise nacheinander den Seed von 0 bis 99 setzt und sich jeweils die erste Zufallszahl holt, kann man nicht erwarten, dass die so gewonnenen 100 Zahlen sehr zufällig aussehen. Es wird nur garantiert, dass die Folge der mit random gezogenen Zahlen für einen anfangs gesetzten Seed (mehr oder weniger) zufällig ist.

      Eine Idee wäre also einmal am Anfang einen Seed zu setzen, noch nicht generierte Teile nach Bedarf zu erzeugen und alle bereits besuchten Gebiete irgendwo zwischenzuspeichern.
    • So dann poste ich mal meinen Generator, den ich selbst für BbW benutzte. Aber das ist auch wirklich nur das Grundkonzept, zum veranschaulichen. Das Ergebnis sind weiche Berge/Täler.
      Man muss etwas mit den Werten rumspielen.
      Dateien
    • WOW

      Wüsste ich nicht, dass es kein Perlin ist, würde ich glauben, dass es das ist. Das mit der Cosinus Interpolation hilft wirklich.
      Außerdem ist deine Methode vieeeel schneller als echtes Perlin.

      EDIT:
      Zwei Probleme sehe ich allerdings schon bei Chris987 Lösung.
      Mir fällt auf, dass die Kurve am ende immer höher ist als am Anfang - immer.
      Es gibt keine Extreme. Das wird man aber brauchen. Sonst wachsen deine Berge theoretisch unendlich nach oben oder nach unten. Nicht so smart.


      @Blackspark
      Perlin braucht in der Berechnung auch die Werte der Benachbarten "Noises" (einfach "nur" die stochastische Größe). Bei mehreren "nachfragen" für die selbe stelle, muss es ja immer der selbe Wert sein.

      Die einzige Lösung scheint mir wirklich das Zwischenspeichern, also eine Liste generieren, die die Noise enthält, also mit random() gefüllt. Diese kann man dann als Grundlage nutzen. Also statt die noise() Funktion in meinem Beispiel zu nutzen, in der List "nachgucken". Performance lassen wir mal außer betracht. Außerdem ist, trotz der Möglichkeit die Liste für bisher ungenutzte Bereiche aufzufüllen, dann die Unendlichkeit auch deutlich kleiner (welche nie Unendlich ist).

      MfG SDX

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von SDX ()

    • SDX schrieb:

      EDIT:
      Zwei Probleme sehe ich allerdings schon bei Chris987 Lösung.
      Mir fällt auf, dass die Kurve am ende immer höher ist als am Anfang - immer.

      Hm? Hast du denn auch mit den Werten etwas rumgespielt? Mir ist nur aufgefallen, dass wenn man die gleichen Werte benutzt, die gleiche Kurve ensteht - immer.
      Aber wenn man die Werte verändert, andere Kurven entstehen, wo durchaus auch das Ende unter dem Anfang sein kann höhentechnisch (gib Bspl. mal für die Frequenz 99, für die Amplitude 62 und für Seed 11 ein).

      MfG.,
      Mokuyobi
      木曜日 (Mokuyōbi)
    • Nach eindringlicher Beschäftigung des genannten Links und weiterer Internet recherche kann ich sagen: ICH BLICKS NICHT.
      Könnte, falls ihr es hier für angebracht haltet, mir jemand(SDX du scheinst es verstanden zu haben :D) nochmal erklären wie Perlin Funktioniert, beziehungsweise wie es aufgebaut ist?
      Falls es nicht in die Expertenrunde passen sollte, bitte entsprechend verschieben.
      Danke schonmal im vorraus!
      lg Partik

      EDIT: Push! Hab nach weiteren Tutorials gesucht: Fehlanzeige. würde sich wirklich keiner dazu bereit erklären mir zu helfen?

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Partik ()

    • Für die Nachwelt, so habe ich'S gelöst(!):
      In einen Array werden zufällige werte(0-1) geschrieben, zischenpunkte werden per Cosiner Interpolation berechnet:

      //scrCosineInterpolation(Point a,Point b,x)
      var a , b , xx , ft , f;
      a = argument0;
      b = argument1;
      xx = argument2;
      ft = xx * 3.1415927
      f = (1 - cos(ft)) * 0.5

      return a*(1-f) + b*f

      Danke, an alle die geholfen haben, besonders an SDX, der mich auf DIESE Idee gebracht hat!