Hi Community,
heute will ich ein schnelles Field of View - System für TopDown-Spiele vorstellen. Ich will schon mal vorwegnehmen, dass dieses Tutorial/Example nicht für Anfänger geeignet ist!
1) Allgemein
Was ist eigentlich ein FoV-System? Das ist leicht erklärt. Einige von euch haben sich sicher schon gewundert, wie man eine Art Fog of War in TopDown-Spielen implementieren kann, damit der Spieler Teile der Welt oder Gegner, die außerhalb des Sichtbereichs sind, nicht sehen kann. Natürlich könnte man einfach mittels collision_line() checken, ob ein Gegenstand hinter einer Wand ist und diesen dann unsichtbar machen. Jedoch ist dies langsam und auch unschön, da man so keinen Nebel implementieren kann, der das Sichtfeld anzeigt. Ein gutes Beispiel für ein FoV-System ist CS2D.
2) Theorie
Dieses System setzt ein Zellensystem vorraus. D.h. der Raum ist in Boolean-Zellen eingeteilt, die angeben, ob eine bestimmte Zelle blockiert oder passierbar ist. Nun brauchen wir ein zweites Boolean-Feld, das angibt welche Zellen im View sichtbar sind. Für dieses verwende ich ein Grid, weil ich in jedem Step alle Zellen auf einen Standardwert zurücksetzen muss (Grids sind in diesem Bereich schneller als Arrays).
Das System muss man sich jetzt so vorstellen: Das FoV-Grid liegt über dem View und der Spieler befindet sich genau in der Mitte des Views. Nun werden alle Zellen des Grids auf false (= nicht sichtbar) gestellt. Jetzt wird es interessant: Man schickt einen Strahl zu jeder Randzelle und setzt jede Zelle, die man passiert, auf true (= sichtbar) bis man am Ende ist oder eine Wand trifft (= wenn ein False-Wert im Raumfeld auftritt). Die Strahlen werden mit Hilfe des Bresenham-Algorithmus berechnet. Nun hat man ein Grid, das angibt welche Zellen im View sichtbar sind. Mit Hilfe dessen kann man auch das Ganze recht einfach zeichnen und Sichtbarkeitschecks durchführen.
3) Umsetzung
Bei dieser reinen GM-Umsetzung habe ich etwas getrickst, damit die Performance akzeptabel bleibt. Bei dieser werden die Strahlen nur einmal berechnet und gespeichert. Daraus folgt leider, dass der Spieler immer in der Mitte des Views sein muss, dafür ist das ganze schneller.
Bitte ladet euch die *.gmk runter und seht euch den Code an, damit ihr wisst wovon ich spreche:
Im Room-Creation Code wird das FoV-Grid erstellt und das Surface, welches wir für den Fog verwenden. Das Grid ist größer als der View, da es sonst zu Problemen kommt, wenn sich der View bewegt.
Im Creation-Event von obj_fov werden die Strahlen berechnet. Zur Erinnerung: Sie werden aus der Mitte des Views zu den Randzellen des Views geschickt. cast_ray() ist nur eine Bresenham-Implementierung, die auch die Strahlen in jeweils ein Array speichert. Zusätzlich wird die Richtung des Strahls in Grad gespeichert. Dies ist wichtig, wenn das Sichtfeld nicht 360° beträgt, sonder eingeschränkt ist.
Der nächste Schritt ist der wichtigste und wird jeden Step im obj_fov ausgeführt. Er berechnet die sichtbaren Felder und zeichnet diese gleichzeitig auf ein Surface.
Im Grunde werden alle Strahlen durchlaufen und, wie oben beschrieben, alle Zellen auf sichtbar gesetzt, die passiert werden. Die Richtungschecks sind dafür da, dass nur die Strahlen durchlaufen werden, die für das Sichtfeld relevant sind (Hier beträgt das Sichtfeld 75°).
Schließlich wird das Surface im Draw-Event von obj_fov, das im Step-Event gezeichnet wurde, über den View gelegt um das Ganze zu visualisieren.
4) Bessere Variante
Alle die, die imstande sind eine DLL zu erstellen, können sich jetzt freuen. Anstatt, die Strahlen am Anfang zu berechnen, kann man diese auch jeden Step berechnen, um das System flexibler zu machen. Ich hab das ganze in Delphi realisiert, um eine gute Performance zu erzielen. Im GM könnte diese Methode kritisch sein und die Performance killen. Einen gewaltigen Nachteil hat eine DLL-Implementierung jedoch: Man kann nicht gleichzeitig die sichtbaren Zellen berechnen und auf das Surface zeichnen. Dieses Problem habe ich durch die Verwendung von Quadtrees gedämpft. Näher möchte ich jedoch nicht darauf eingehen.
5) Quellen
Grundlage für dieses System bat diese Seite. Den Bresenham-Algorithmus habe ich mit Hilfe von Wikipedia implementiert. dirdiff() ist von GMLScripts.com und das einzige Sprite ist von MasterXY.

Ich hoffe dieses Tutorial hat einigen geholfen.
heute will ich ein schnelles Field of View - System für TopDown-Spiele vorstellen. Ich will schon mal vorwegnehmen, dass dieses Tutorial/Example nicht für Anfänger geeignet ist!
1) Allgemein
Was ist eigentlich ein FoV-System? Das ist leicht erklärt. Einige von euch haben sich sicher schon gewundert, wie man eine Art Fog of War in TopDown-Spielen implementieren kann, damit der Spieler Teile der Welt oder Gegner, die außerhalb des Sichtbereichs sind, nicht sehen kann. Natürlich könnte man einfach mittels collision_line() checken, ob ein Gegenstand hinter einer Wand ist und diesen dann unsichtbar machen. Jedoch ist dies langsam und auch unschön, da man so keinen Nebel implementieren kann, der das Sichtfeld anzeigt. Ein gutes Beispiel für ein FoV-System ist CS2D.
2) Theorie
Dieses System setzt ein Zellensystem vorraus. D.h. der Raum ist in Boolean-Zellen eingeteilt, die angeben, ob eine bestimmte Zelle blockiert oder passierbar ist. Nun brauchen wir ein zweites Boolean-Feld, das angibt welche Zellen im View sichtbar sind. Für dieses verwende ich ein Grid, weil ich in jedem Step alle Zellen auf einen Standardwert zurücksetzen muss (Grids sind in diesem Bereich schneller als Arrays).
Das System muss man sich jetzt so vorstellen: Das FoV-Grid liegt über dem View und der Spieler befindet sich genau in der Mitte des Views. Nun werden alle Zellen des Grids auf false (= nicht sichtbar) gestellt. Jetzt wird es interessant: Man schickt einen Strahl zu jeder Randzelle und setzt jede Zelle, die man passiert, auf true (= sichtbar) bis man am Ende ist oder eine Wand trifft (= wenn ein False-Wert im Raumfeld auftritt). Die Strahlen werden mit Hilfe des Bresenham-Algorithmus berechnet. Nun hat man ein Grid, das angibt welche Zellen im View sichtbar sind. Mit Hilfe dessen kann man auch das Ganze recht einfach zeichnen und Sichtbarkeitschecks durchführen.
3) Umsetzung
Bei dieser reinen GM-Umsetzung habe ich etwas getrickst, damit die Performance akzeptabel bleibt. Bei dieser werden die Strahlen nur einmal berechnet und gespeichert. Daraus folgt leider, dass der Spieler immer in der Mitte des Views sein muss, dafür ist das ganze schneller.
Bitte ladet euch die *.gmk runter und seht euch den Code an, damit ihr wisst wovon ich spreche:
Im Room-Creation Code wird das FoV-Grid erstellt und das Surface, welches wir für den Fog verwenden. Das Grid ist größer als der View, da es sonst zu Problemen kommt, wenn sich der View bewegt.
Im Creation-Event von obj_fov werden die Strahlen berechnet. Zur Erinnerung: Sie werden aus der Mitte des Views zu den Randzellen des Views geschickt. cast_ray() ist nur eine Bresenham-Implementierung, die auch die Strahlen in jeweils ein Array speichert. Zusätzlich wird die Richtung des Strahls in Grad gespeichert. Dies ist wichtig, wenn das Sichtfeld nicht 360° beträgt, sonder eingeschränkt ist.
Der nächste Schritt ist der wichtigste und wird jeden Step im obj_fov ausgeführt. Er berechnet die sichtbaren Felder und zeichnet diese gleichzeitig auf ein Surface.
Im Grunde werden alle Strahlen durchlaufen und, wie oben beschrieben, alle Zellen auf sichtbar gesetzt, die passiert werden. Die Richtungschecks sind dafür da, dass nur die Strahlen durchlaufen werden, die für das Sichtfeld relevant sind (Hier beträgt das Sichtfeld 75°).
Schließlich wird das Surface im Draw-Event von obj_fov, das im Step-Event gezeichnet wurde, über den View gelegt um das Ganze zu visualisieren.
4) Bessere Variante
Alle die, die imstande sind eine DLL zu erstellen, können sich jetzt freuen. Anstatt, die Strahlen am Anfang zu berechnen, kann man diese auch jeden Step berechnen, um das System flexibler zu machen. Ich hab das ganze in Delphi realisiert, um eine gute Performance zu erzielen. Im GM könnte diese Methode kritisch sein und die Performance killen. Einen gewaltigen Nachteil hat eine DLL-Implementierung jedoch: Man kann nicht gleichzeitig die sichtbaren Zellen berechnen und auf das Surface zeichnen. Dieses Problem habe ich durch die Verwendung von Quadtrees gedämpft. Näher möchte ich jedoch nicht darauf eingehen.
5) Quellen
Grundlage für dieses System bat diese Seite. Den Bresenham-Algorithmus habe ich mit Hilfe von Wikipedia implementiert. dirdiff() ist von GMLScripts.com und das einzige Sprite ist von MasterXY.

Ich hoffe dieses Tutorial hat einigen geholfen.

© 2008 by Teamgrill Productions
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Soul Reaver ()