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:
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
und im Destroy Event geben wir den reservierten Speicher wieder frei:
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:
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.
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:
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
und im Destroy Event geben wir den reservierten Speicher wieder frei:
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
- surface_set_target(FoW); // FoW als Zielfläche zum Zeichnen bestimmen
- draw_clear(c_white); // Surface komplett Weiß streichen
- 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
- with(obj_FoWRem) // mit allen Instanten von obj_FoWRem und deren Nachfahren
- {
- event_user(0); //führe User0 aus
- }
- surface_reset_target(); //Setze den Bildschirm wieder als Zielfläche zum Zeichnen
- draw_surface(FoW,0,0); //Zeichne das Surface
- 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.