Nebel des Krieges (Reg/Pro)

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

    • Nebel des Krieges (Reg/Pro)

      Aus gegebenem Anlass hat mich gerade mal wieder das Bastelfieber gepackt. Manch einer möchte sich gerne einen "Nebel des Krieges" oder auch "Fog of War" (kurz: FoW) in sein (Strategie)spiel einbaun. Natürlich kann man die ganze Karte mit kleinen Objekten zupflastern, die sich langsam auflösen, wenn sich jemand nähert, und wieder verschwinden, wenn wenn man den Ort verlässt, aber das kostet nur unnötig ressourcen, und kann, wenn die Sprites ungünstig gewählt sind, recht eckig aussehen.
      Da für mich ein FoW nichts anderes ist, als ein großer Schatten, wobei die eigenen Einheiten und Gebäude dann Lichtquellen sind, habe ich mir gedacht, man könnte dieses Tutorial ein wenig modifizieren, um einen entsprechenden Effekt zu erzielen.

      Da man das Wichtigste dort nachlesen kann, gehe ich hier nur noch auf das ein, was Xiebel damals ausgelassen hat, was ich hier aber eingeführt habe.
      (Getestet unter GM7 - Registrierte/Pro Version wird benötigt)

      Zunächst einmal benötigen wir für jedes Objekt, das eine Schneise in den FoW ziehen soll, ein Sprite, welches lediglich für Licht sorgt (und NIX im Draw Event verloren hat!). Dabei handelt es sich i.d.R. um unterschiedlich große, kreisförmige Farbverläufe: Weiß in der Mitte und nach außen hin Schwarz (bekommt man z.B. mit GIMP recht gut und schnell hin), Ursprung im Zentrum (auf "Center" klicken).

      So, nun nutzen wir die Ansätze des objektorientierten Programmierens, die uns der GM bietet, und erstellen ein Objekt namens "obj_FoWRem". Dieses Objekt sollten alle Objekte, die den FoW beseitigen, irgendwo in ihrem Stammbaum haben (d.h. entweder direkt als Parent, oder als Parent des Parents, oder als Parent des Parents des Parents, etc.); das Objekt selbst wird nicht im Raum Platziert.

      In diesem Objekt definieren wir nun ein Nutzerdefiniertes Event (ich nehme User0), welches bei allen Objekten, die dieses Objekt in ihrem Stammbaum haben (also die Child-Objekte, Kinder, Objekte, die von obj_FoWRem erben, Nachfahren, was auch immer) reserviert sein sollte, d.h. wenn man andere Nutzerdefinierten Events erstellt, sollte man darauf achten, dass man gerade dieses nicht belegt (zu Ausnahmen komme ich später).

      Dort schreibt man lediglich eine Zeile rein, die das Standardbeleuchtungssprite (also dasjenige unter den oben erwähnten Sprites, das verwendet werden soll, wenn man nichts anderes festlegt) zentriet an der Position des Objektes zeichnet. D.h. wenn alle Einheiten 32*32 Pixel groß sind und ihren Ursprung oben links haben (so wie die Standardquadrate beim erstellen eines neuen Sprites), lautet die Zeile:

      GML-Quellcode

      1. draw_sprite(spr_licht1,-1,x-view_xview[0]+16,y-view_yview[0]+16);


      Wie man sehen kann gehe ich davon aus, das View0 verwendet wird. Dieses "komische" Hin- und Hergeschiebe der Koordinaten von Objekt und View ergibt sich daraus, dass x und y die Koordinaten im Raum angeben, später aber auf eine Surface gezeichnet werden soll, und dabei deren obere linke Ecke der Ursprung ist. Da diese aber der oberen linken Ecke des Views entspricht, müssen die Koordinaten angepasst werden.

      Wenn wir nun also Objekte erstellen, die den FoW auflösen sollen, so tragen wir einfach dieses Objekt als Parent ein; falls wir einen größeren "Sichtradius" (ein größeres Lichtsprite) oder einen anderen Mittelpunkt (weil ein z.B. ein Haus größer ist, als ein Männchen) festlegen wollen, definieren wir zusätzlich(!) ein User0 Event (oder welches man vorhin genommen hat), und schreibt dort die Zeile von oben, nur mit entsprechenden Anpassungen, hinein.

      So, fast geschafft. Nun brauchen wir nur noch ein Objekt, das den Kriegsnebel zeichnet. Wir erstellen also ein "obj_FoW". Wie vorhin angekündigt besteht der FoW aus einem Surface. Im Create Event von obj_FoW erstellen wir diese mittels

      GML-Quellcode

      1. FoW := surface_create(view_wview[0],view_hview[0]);

      und im Destroy Event geben wir den reservierten Speicher wieder frei:

      GML-Quellcode

      1. surface_free(FoW);

      Das hat den Vorteil, dass wir durch Löschen oder Deaktivieren dieser Instanz den Nebel abschalten können (zu Entwicklungszwecken, als Cheat oder weil Satelliten entwickelt wurde, was auch immer...).

      Im Draw Event folgt nun die eigentliche Arbeit:

      GML-Quellcode

      1. surface_set_target(FoW); // FoW als Zielfläche zum Zeichnen bestimmen
      2. draw_clear(c_white); // Surface komplett Weiß streichen
      3. draw_set_blend_mode(bm_subtract); // das keht die Farben um, d.h. wenn wir was weißes Zeichnen, wird das Ergebnis schwarz und umgekehrt
      4. with(obj_FoWRem) // mit allen Instanten von obj_FoWRem und deren Nachfahren
      5. {
      6. event_user(0); //führe User0 aus
      7. }
      8. surface_reset_target(); //Setze den Bildschirm wieder als Zielfläche zum Zeichnen
      9. draw_surface(FoW,0,0); //Zeichne das Surface
      10. draw_set_blend_mode(bm_normal);//Die Farben werden nicht mehr umgekehrt


      Nun sehen wir auch, warum wir uns vorhin den Spaß mit den Parents gemacht haben: statt für jedes Objekt einen eigenen Abschnitt zum Zeichnen aufzurufen, machen wir es einmal für alle Objekte, die von obj_FoWRem erben, und der GM wählt automatisch die Funktion, die für jedes Objekt definiert wurde, d.h. entweder direkt die aus obj_FoWRem oder die, die im Objekt selbst (oder einem Vorfahren) definiert wurde. Und das Nutzerdefinierte Event wird verwendet, damit das Draw Event davon unangetastet bleibt, d.h. zugewiesene Sprites werden nicht entfernt, und wenn wir nur das Draw Event der Objekte aufrufen, erscheinen diese kreisförmigen Farbverläufe nicht.

      Allerdings ist mir beim Testen noch ein kleines Problem aufgefallen: obj_FoW sollte eine geringere Depth erhalten, als alle Objekte im Raum (außer dem HUD). Nicht, damit der Nebel über der Karte gezeichnet wird (das wird er trotzdem), sondern weil in meiner testumgebung auf einmal fest stehende Objekte angefangen haben, mit dem Spieler mitzulaufen, als ich obj_FoW eine höhere Depth gab, als den übrigen Objekten. Ich kann mir nicht erklären, woran das liegt, aber vllt. hat ja jemand anderes eine Idee.

      Soweit jedenfalls erstmal ein recht einfacher Kriegsnebel.
    • RE: Nebel des Krieges (Reg/Pro)

      CAS schrieb:

      Allerdings ist mir beim Testen noch ein kleines Problem aufgefallen: obj_FoW sollte eine geringere Depth erhalten, als alle Objekte im Raum (außer dem HUD). Nicht, damit der Nebel über der Karte gezeichnet wird (das wird er trotzdem), sondern weil in meiner testumgebung auf einmal fest stehende Objekte angefangen haben, mit dem Spieler mitzulaufen, als ich obj_FoW eine höhere Depth gab, als den übrigen Objekten. Ich kann mir nicht erklären, woran das liegt, aber vllt. hat ja jemand anderes eine Idee.
      Ich gehe davon aus, dass nicht die Objekte mitgelaufen sind, sondern einfach nur die Grafiken, die sich in die Zeichenebene gebrannt haben.

      Alles in allem ein sehr gutes Tutorial. Auch ich finde, dass FoW im GM am besten über diese Methode gelöst wird. Surfaces sind zwar im Grunde nicht besonders speicherschonend, aber mir fällt hierfür nichts ein, was angebrachter wäre. Alles andere würde auf den Einsatz vieler oder riesiger Grafiken mit Alphaverläufen oder Zeichnen in Blend Modes hinauslaufen.
      █████ ██ █ ████ everything ███ █████ is █████ ████ ████ fine ████ ███ █ ██████ love.
      █████ ███████ ███ your █████ ████ government.
    • Ja... ich frage mich aber immerzu, wie man das in kommerziellen Spielen eigentlich löst. Ich meine: Warcraft 2 lief sogar auf nem 486er perfekt mit seinem FoW. Starcraft hatte schon einen sehr ansehnlichen FoW und lief bei 200Mhz schon so gut wie optimal und Cossacks bietet einen der imposantesten FoWs, die ich je gesehen hab und ich habe keine Ahnung, wie man es dort geschafft hat das Spiel selbst bei 800Mhz perfekt laufen zu lassen! Es muss doch irgendeine bequemere, optimalere Lösung für FoWs, auch im GM, geben, wenn diese schon seit Ewigkeiten auf den beschränktesten Rechnern funzen.
    • Das wüsste ich auch gerne...

      Wahrscheinlioch liegt es einfach daran das GM eben nicht so gut mit sowas umgehen kann.

      Wenn man so ein spiel in einer richtigen Programmiersprache schreibt sieht die Sache vieleicht anders aus.



      Das Tutorial ist ziemlich gut. Hab vor nicht allzulanger Zeit versucht sowas selbst auf eine fast identische Art zu machen hab aber ein paar seltsame Probleme gehabt :/

      Werds nochmal auf genau diese Weise versuchen :)

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Hi

      ich wollte fragen, ob es möglich ist diesen script so umzuändern, dass die verdeckte Fläche (der Nebel) in einer anderen Farbe als schwarz dargestellt wird

      hoffe mir kann jemand helfen und danke schonmal im vorraus

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

    • hi ho ...
      1. Super tut ...
      2. habe ich den fehler gefunden warumm die ojecte "mit wandern"
      [...] never use it in drawing events. This will cause serious problems with the projection and viewport.
      steht in der hilfe ...

      ergo habe ich das zeichnen auf dem surface im step und das eigentliche zeichnen des surface im draw event gemacht und es geht ...

      3. habe ich mit hilfe deines tuts (und nen bisl hirn schmalz) eine (meiner meinung nach ^^) etwas verbesserte variante gebastelt ... kannst ja dein tut dem anpassen (musst aber nicht) ... siehe anhang XD ...
      Dateien
      • FoW_test.rar

        (11,33 kB, 379 mal heruntergeladen, zuletzt: )
      ---- wer fehler findet darf sie behalten ---

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