Tilemaps & Fog of War => Performance?

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

  • Tilemaps & Fog of War => Performance?

    Hey,

    Also erstmal nen bisschen weiter ausgeholt damit ihr wisst worum es geht:
    Ich arbeite im Moment an einem Roguelike, wobei ich ein ähnliches Spielsystem geplant habe wie DoomRL.
    => Rundenbasiert, Tile-Based und Action orientiert... hey vielleicht sogar Zombies :D
    Mein Hauptproblem z.Z. stellt allerdings im Moment die Map auf der man spielt dar.
    Auf Grund von zufallsgenerierten Levels (wie für Roguelikes üblich), bin ich darauf angewiesen meine Grafiken alle irgendwie dynamisch zu erzeugen und darzustellen, d.b. insbesondere ich hab keine Map oder Ähnliches in nem Room schon zur Programmierzeit zusammen gebaut, das geschieht alles zur Laufzeit, inkl. Auswahl der Sprites die dargestellt werden sollen abhängig von der Umgebung jedes einzelnen Tiles der Map.

    Ich habe z.Z. 3 Arrays die das Level quasi "beinhalten".
    A1. Ein Array welches die Levelstruktur (den Tiletype könnte man sagen) enthält und nur aus "#" und "." besteht. Wobei "#" blockierte Tiles und "." begehbare Tiles sind. Über dieses Array finden dann auch Kollisionschecks bzw. der A* Algorithmus statt.
    A2. Ein Array welches eine Ziffer speichert die zusammen mit dem Tiletype (siehe A1) das darzustellenden Sprite angiebt
    A3. Ein Array welches speichert welche Tiles schon besucht worden sind, welche noch nicht besucht woren sind und welche gerade von einem Objekt aus eingesehen werden können -> Stichwort Fog of War bzw. Field of Vision

    A1,A2,A3 sind also quasi mehrere Layer eines Levels.

    Wenn wir uns jetzt vorstellen ich würde eine Levelgröße von 100*100 Tiles (oder auch mehr) generieren, dass sind dann insgesamt 10000 Tiles, da ich auch deren Beziehungen zueinander betrachten muss sind das ganz am Anfang bei Generierung des Levels 10000 Tiles * ihre 8 Nachbarn = 80000 Arrayabfragen, allerdings nur einmalig am Anfang wenn das Level generiert wird. Ungeachtet der Abfragen für Integritätsprüfungen ob z.B. keine Räume in einander überlappen oder Monster mitten in einem Fluss spawnen.
    Da ich jetzt natürlich nicht immer die komplette Map darstellen kann (also in jedem Step 10000 Arrayzellen iterieren müsste o.o), beschränke ich mich auf einen 21 * 21 Tiles großen Ausschnitt um den Player herum.

    -----------

    Mein Problem ist jetzt wie ich anfangen soll das konkret zu implementieren um von Anfang an die Performanz hoch zu halten.
    Im Moment lese ich wie gesagt nur einen kleinen Teil des Maparrays (A1) aus (21 x 21 Tiles) und stelle die Grafik mit Sprites dar.
    Dabei habe ich folgende 2 Ansätze prototypisch mal ausprobiert und keine Peformance-Probleme festgestellt.

    Ansatz 1: Sprites mit verschiedenen Alphawerten zeichnen ->also 21 * 21 = 441 Sprites mit verschiedenen Alphawerten, funktioniert ohne Probleme.
    Ansatz 2: Ebenfalls alle 441 Sprites darstellen allerdings normal ohne Alphawert und dann abhängig vom FOV-Array (A3) über die Sprites Rectangles mit ver. Alphawerten legen in der größe eines Tiles legen. Aufwand ist deutlich höher, FPS bleiben aber gleich.

    Soweit so toll.
    Aber... mein eigentliches Anliegen ist statt Sprites mit mehreren Subimages ein großes Tileset zu benutzen und einmal beim generieren des Levels die Tiles entsprechend von A2 zu setzen.
    Bei einem 100*100 Tiles großen Level sind das allerdings dann auch 10000 Tiles die ich in den Raum setzen würde, zwar wie gesagt nur einmalig aber sie wären da und dass obwohl lediglich 441 davon immer zusehen wären d.h. ich hätte ne Overhead von 9559 dargestellten Tiles die allerdings keine Sau sehen kann :(
    Zudem müsste ich dann immer noch wie in Ansatz 2 (dafür hab ich das ausprobiert), meinen Sichtradius mit halbtransparenten Rectangles regeln d.h. zusätzlich nochmal einen Darstellungsaufwand von 441 Rechtecken in unterschiedlicher Opacity.

    So wers bis hier hin durchgehalten hat wird sicher gemerkt haben, dass ich noch keine Frage gestellt habe, gell? :D
    Also was ich eigentlich wissen wollte ist:
    Was haltet ihr davon? Realisierbar oder Blödsinn?
    Hab ich das ganze völlig falsch angegangen?
    Und vorallem, hat jemand Erfahrung mit sowas?
    Gibts eventuell Techniken um sehr große Tilemaps möglichst effizient darzustellen ohne Zehntausende von Tiles rumliegen zu haben oder auf Sprites auszuweichen?

    Eine Überlegung die mir gekommen ist. wozu ich auch gern ne Meinung und/oder Ratschläge hätte:
    Was haltet ihr davon wenn ich die Tiles zwar ganz am Anfang bei der Generierung der Map erstelle, dann von der Zeichenfläche einen Snapshot als Background erzeugen und dann alle Tiles wieder lösche.
    Macht ein ~ 1600 * 1600 Pixel großer Background Probleme?
    Ich müsste dann immer noch, wie in Ansatz 2 beschrieben, meinen Fog of War mit halbtransparenten Rectangles zeichen, wobei ich aber denke dass 441 16*16 große Rechtecke verträglich sind oder?
    Auf diese Weise habe ich a) keine Sprites mehr und kann b) ein Tileset verwenden. Fragwürdig ist halt nur der gigantische Background...

    Sowas kann man sicher auch irgendwie mit Surfaces machen wobei ich da 0 Ahnung habe und mich damit auch noch nicht ausseinander gesetzt habe, Tipps?


    Ok ich denk ich hab genug gesabbelt, vergebt mir meine Ausschweifungen :D
    Wenigstens habt ihr so nen Eindruck davon bekommen mit was für nem Mindfsck ich meinen ersten freien Sommerferientag verbringe :]
    Anbei noch ein Screenshot meines Prototypes mit der Implementierung von Ansatz 2, wobei die Tiles die ihr seht keine wirklichen Tiles sind sondern lediglich Sprites die ich zeichne:
    Bilder
    • rogue_dev.png

      11,78 kB, 640×400, 424 mal angesehen

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

  • Hmmm..
    Ich weis zwar nicht, ob Tiles irgendwelche performance-mässige Vorteile gegenüber normalen Sprites haben, aber wieso machst du das nicht einfach über solche?
    Zb mit draw_sprite_part kannst du einen Teil eines Sprites zeichnen, und dieses könnte ja dein Tileset sein... oder missverstehe ich etwas?
    Ich meine damit müsstest du eben nur die Sprites im sichtbaren Bereich zeichnen.
    Oder laber ich Blödsinn?
    "das war meine letzte flamewar PM an dich ."
  • Mh ne laberst absolut kein Blödsinn, eher bins ich der Blödsinn labert :]
    Trotzdem ne gute Idee, muss ich mal ausprobieren, aber wie gesagt müsste ich dann zur Laufzeit 441 mal pro Step irgendwelche Teil-Sprites auslesen und offsets berechnen usw.
    Das würde halt komplett entfallen wenn ich Tiles einsetze, aber bevor ich da jetzt großartig was implementiere wollt ich halt so nen paar Meinungen ob das auch Sinn macht oder nurn Hirnfurz von meiner Seite aus is :x
  • Du könntest diese ganzen Dinge auch einfach schon beim Laden erledigen, mittels sprite_add einfach aus dem Background entsprechend den Teil auslesen und im step lediglich die Sprites zeichnen, die zu zeichnen sind... Ich denke, das wäre zumindest performanter als zehntausende von Tiles oder ein riesiger Background...
    "das war meine letzte flamewar PM an dich ."

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

  • ich finde die idee mit dem background sehr passend.
    Die Bedingung ist eine begrenzte größe, wobei ich dann keinen Background benutzen würde sondern ein sprite.

    Jetzt kommt es zudem auf deine Kamera an. Kann man während einer Runde sich mit dem view frei im level bewegen?

    Wenn nicht dann würde ich es mit kleinen sprite versuchen.

    Das Sprite wird dabei jede runde, sobald sich der view verändert, neu erstellt und als hintergrund gesetzt.
    Das ist natürlich nur einwandfrei möglich wenn sich der view nicht verändert.
    Wenn eine Bewegung sich ankündigt, wird vor dem bewegen ein neuer hintergrund erstellt, inklusive der kacheln die der spieler sehen wird. <- wird problematisch wenn es felderweise geht, da die funktion einfach zu langsam für eine kachelgröße fortbewegung ist (die alternative wäre einen einmaligen weg von 10 kacheln oder so) und gleichgesetzt mit dem freien view bewegen.
  • Habs jetzt mal mit nem gigantischen Background probiert und jo geht... allerdings wenn ich mehr als eine Map habe (ab 10 etwa) merkt man schon dass 1600*1600 Bitmaps am Speicher fressen, fps fallen von 60 auf 50, macht zwar nix is aber trotzdem ne schmuddelige Angelegenheit...
    Wenn ich nur Teilbackgrounds nehme und ständig was neu berechne dann wird das vermutlich aufwändiger als nötig.
    Das Beste was ich bis jetzt ausprobiert habe ist die Idee von blubberblub nen Sprite mit draw_sprite_part als Tileset zu missbrauchen, das geht einwandfrei und Ich spar mir auch das nervige rumhantieren mit Tile-Layern :)
  • Ich habe das jetzt nur überflogen, aber aus persönlicher Erfahrung lohnt es sich, solche Aktionen auf die View zu bechränken.

    Wenn mehr verdeckt wird als man sieht, solltest du vielleicht sogar eine Surface benutzen, die komplett dunkel gehalten ist und du die sichtbaren Felder "freizeichnest" und diese Surface dann am Ende auf alles draufzeichnest (hängt auch natürlich davon ab, wie du das mit den Abstufungen handhabst - gameplaytechnischer Fog of War braucht ja eigentlich nur eine Abstufung).

    Ich habe es mir zur Regel gemacht, so wenige Drawbefehle wie nur möglich zu verwenden. Die Komplexität der Drawbefehle scheint einen deutlich geringeren Einfluss auf die Performance zu haben als die Anzahl.
  • Benutzer online 1

    1 Besucher