somethinglikegames.de

Mein Blog über Spieleentwicklung und das Drumherum


Kategorien


Tags

Nachdem wir im Artikel zum Thema Scene Replication bereits erste Erfahrungen mit dem MultiplayerSynchronizer sammeln konnten, wollen wir unsere Erfahrungen damit in diesem Artikel weiter vertiefen. Denn der MultiplayerSynchronizer hat neben dem Synchronisierungsintervall noch andere Konfigurationsoptionen, mit dem sich interessante Dinge anstellen lassen.

Wir wollen uns in diesem Artikel mit dem Thema Interest Management beschäftigen. Darunter versteht man bei Netzwerkspielen, dass man den jeweiligen GameClients nur die Informationen über die anderen Spieler zukommen lässt, die der Spieler wirklich benötigt, um alles in seiner Umgebung wahrnehmen zu können. Dadurch wird versucht, die Netzwerkkommunikation pro verbundenem GameClient / Spieler möglichst klein zu halten. Als Nebeneffekt reduziert man bei wettbewerbsorientierten Spielen dadurch teilweise das Risiko von Wallhacks etc., da der GameClient im Idealfall nur noch das an Informationen bekommt und umsetzt, was der Spieler auch wahrnehmen (sehen bzw. hören) kann. Im Grunde genommen basiert es darauf, dass jede Spielfigur (mindestens) eine Area of Interest (AoI) hat, also einen Bereich um die Spielfigur herum. Wenn etwas innerhalb dieses Bereichs passiert, sich beispielsweise eine andere Spielfigur innerhalb des Bereichs bewegt, wird der GameClient darüber informiert, sodass er diese Bewegung auch anzeigen kann. Man könnte auch mit mehreren AoI arbeiten, um unterschiedliche Aspekte dadurch abzubilden, wenn z.B. der Spieler weiter sehen kann als hören, könnte man für jeden Sinn eine eigene AoI nutzen.

Zum Thema Interest Management wurde im Februar 2022 ein lesenswerter Godot Proposal veröffentlicht, den Fabio Alessandrelli dann im Rahmen von Godot 4 auch umgesetzt hat, indem er ihn in den MultiplayerSynchronizer integriert hat. Der zugehörige Pull-Request mit konkreter Implementierung ist hier zu finden. Aber schauen wir uns für ein besseres Verständnis die ganze Thematik doch einfach mal an einem konkreten Beispiel an.

Wir starten mit dem Beispielprojekt aus dem Artikel zum Thema Scene Replication. Wenn ihr es nicht mehr haben solltet, findet ihr es im zugehörigen Github-Repository. Ich habe mir gedacht, wir erweitern das Projekt so, dass die Spielfigur innerhalb der Player-Szene eine AoI in Form einer Area3D mit zugehörigem CollisionShape3D bekommt. Als Shape nehmen wir ein CylinderShape3D mit einem Radius von 5m, sodass unsere Spielfigur eine kreisrunde AoI mit 5m Radius hat. Dadurch sollten wir in unserem Beispiel den Effekt sehr gut bemerken können.

Die Player-Szene inkl. 3D Ansicht

Die Player-Szene inkl. 3D Ansicht

Konfiguration des ServerSynchronizers

Konfiguration des ServerSynchronizers

Bevor wir uns den zugehörigen Quellcode ansehen, müssen wir erst noch weitere Vorarbeit leisten. Die Idee ist ja, dass die Area3D unsere AoI ist. Damit sind alle Spielfiguren, die mit unserer AoI “kollidieren” von Interesse, alle anderen interessieren uns nicht. Für die Umsetzung müssen wir also die Signale body_entered und body_exited unserer Area3D mit unserem Player-Skript verknüpfen.

Zusätzlich müssen wir auch noch Interest Management im MultiplayerSynchronizer aktivieren. Dafür setzen wir das Property public_visibility des Synchronizers auf false. Das geht entweder skriptbasiert oder durch Entfernen des passenden Hakens über den Inspector, wie ich es hier im nebenstehenden Screenshot getan habe. Nun werden Sichtbarkeitseinstellungen, die man durch die Funktion set_visibility_for() machen kann, auch vom Synchronizer berücksichtigt.

Wie im untenstehenden Quellcode-Snippet zu erkennen ist, nutzen wir unsere verknüpften Signale der Area3D, um die Sichtbarkeit der jeweiligen Spielfiguren für den eigenen GameClient an- bzw. abzuschalten. Hier kommt uns zugute, dass wir die jeweiligen Spielfiguren mit der NetzwerkID des GameClients benannt haben. Hier in diesem Beispielprojekt verzichten wir der Einfachheit halber auf die Überprüfung ob es sich bei den kollidierenden Node3D-Objekten wirklich um andere Spielfiguren handelt. Normalerweise müsste man dies noch evaluieren oder besser CollisionLayer und CollisionMask so konfigurieren, dass Kollisionen nur durch andere Spielfiguren bzw. deren Handlungen ausgelöst werden können.

Die Player-Szene muss natürlich sowohl im WorldServer als auch im GameClient erweitert werden. Streng genommen reicht es aus, im GameClient ausschließlich das Property public_visibility vom ServerSynchronizer auf false zu stellen, da wir die Kollisionserkennung mit der Area of Interest ausschließlich auf dem Server machen. Daher ist die nachfolgende Skript-Erweiterung auch nur im WorldServer notwendig.
47func _on_area_3d_body_entered(body: Node3D) -> void:
48	synchronizer.set_visibility_for(str(body.name).to_int(), true)
49
50
51func _on_area_3d_body_exited(body: Node3D) -> void:
52	synchronizer.set_visibility_for(str(body.name).to_int(), false)

Sind diese Änderungen gemacht, sollte dem Testlauf eigentlich nichts mehr im Wege stehen. Ich hoffe, dass ich nichts vergessen habe und es auch soweit verständlich war. Ich finde die Godot-Umsetzung von Interest Management ziemlich elegant, da sie nicht nur funktional ist, sondern den Entwicklern die Freiheit lässt, selbst zu bestimmen, was ihre Sichtbarkeitskriterien für die jeweilige Area of Interest sind. Man muss nicht mit Kollisionen arbeiten, wie in diesem Beispiel, man ist komplett frei oder, um deutsche Politiker zu zitieren, “technologieoffen” 😉.

Mit dieser Technologie sollte es sogar möglich sein, ein System zu entwickeln, was ähnlich funktioniert wie das Layering bei World of Warcraft Classic. Da dort zum Start eines Addons oft viel mehr Spieler in bestimmten Gebieten sind als wenige Wochen nach dem Start, sind Spieler bestimmten Layern zugeordnet und sehen dann auch nur Spieler und NPC / Monster des selben Layers. Gruppen werden natürlich auf einem Layer zusammengelegt, sodass man die eigenen Gruppenmitglieder auch sehen und mit ihnen spielen kann.

Natürlich gibt es das fertige Projekt im üblichen Github-Repository zur eigenen Verwendung.