Godot: Niemand weiß, wie Godot funktioniert. (Re-MultiScript, Re-Class-basierter Knoten)

Erstellt am 16. Okt. 2018  ·  63Kommentare  ·  Quelle: godotengine/godot

Dies ist eher ein informelles Thema, aber es ist ein drastisches Problem, wenn nicht das Hauptproblem von Godot.
Niemand weiß, wie die Entwickler der Godot-Engine die Benutzer, die sie verwenden, geplant haben.

Einige verwandte Probleme: #19486 #7402 #15996 #8502
Dies sind die Top 4, aber es gibt viele ähnliche, die alle das gleiche Problem lösen wollen: Alle suchen nach einem brauchbaren Workflow.

Erstaunlicherweise haben Godot-Benutzer es geschafft, ineffiziente Workflows zu erstellen, die andere bekannte Engines kopieren. Um dies zu demonstrieren, werde ich eine Mock-Klasse verwenden, die zeigt, wie eine MeshInstance aussehen würde, wenn sie in Godot erstellt würde.


Es gibt Pseudo-Unity, auch bekannt als untergeordnete Knoten:


Godot-Benutzer verwenden untergeordnete Knoten, um ein Äquivalent zu MultiScripts zu erstellen.

MeshInstance(Spatail +Skript)
--- Mesh (Mesh + Skript)
--- Material (Knoten + Skript) - Shader (Knoten + Skript) - Textur (Knoten + Skript)
--- Transformieren (Position3D +Skript)

Grundsätzlich verwenden sie den am besten geeigneten Knoten und codieren, was sie benötigen, um mit einem Skript die gewünschte Klasse zu erstellen.

Probleme:
1.) Es ist das digitale Äquivalent zum Hinzufügen von kaltem Wasser zu einem kochenden Topf; es hilft kurzfristig, sorgt aber bei größeren Projekten für mehr Verwirrung.
2.) Die meisten Benutzer verwenden am Ende Signale wie Ereignisse, verbinden sie nur mit dem Knoten, der sie sendet, und verwenden Export , um das Ziel zu finden.
3.) Ereignisse können abgefangen werden, bevor sie die unteren Knoten erreichen.
4.) Die Leistung ist langsam und bei etwa 50.000 Objekten kann es zum Stillstand kommen, wenn das Spiel versucht, Szenen zu laden.


Pseudo Unreal, auch bekannt als Controller und Intermediate:

Godot-Benutzer erstellen Controller und Besitzerknoten, die alle Kinder manipulieren. Das Markenzeichen dieses Workflows sind die mit Extends abgeleiteten Klassen.

MeshWithTexturedMaterial.instanced() *nur Knoten im Baum
-> erstreckt sich von -> MaterialTextured -> erstreckt sich von -> Material -> erstreckt sich von -> Shader

Dieses System erfordert viel Planung, oder Sie landen in vielen Klassen mit ähnlichem Code. Wie eine Kamera, Charakter- und Fahrzeugklassen, die alle ihre eigene Kopie von „Ziel verfolgen“ enthalten.
Probleme:
1.) Unordentliche große Skripte, die mühsam zu debuggen sind.
2.) Doppelter Code in verschiedenen Klassen.
3.) Godot behandelt Knoten nicht als Klassen; Dies zwingt diese Entwickler, sich stark auf selbst codierte Klassen zu verlassen.
4.) Erweiterungen machen keinen Sinn, wie ein _Kampfsystem_ das ein _Waffensystem_ erweitert und schließlich den Spieler erweitert.


Pseudo Panda3D, auch bekannt als Preload(Script):

Dieser repliziert den Arbeitsablauf, wie die meisten codebasierten Engines funktionieren. Die Entwickler haben oft mehr Skripte als Knoten.

MeshInstance (Knoten)
Vorladen (Mesh-Skript)
Vorladen (Materialskript)
Vorab laden (Transformationsskript)

Seltsamerweise weigern sich diese Entwickler, GDscript aufzugeben, auch wenn C# für diesen Ansatz eindeutig besser ist. Deshalb gehe ich davon aus, dass sie mit Python vertraut sind.
Probleme:
1.) Verwirrung darüber, wie Importe aufgerufen werden sollten, da Konstanten möglicherweise Variablen mit Onready sind; Wer weiß.
2.) Verwendet selten Godot-Knoten, ich habe sogar gesehen, wie Entwickler die UI-Tools vollständig ignorierten.
3.) Mühe beim Debuggen, da es keinen Hinweis darauf gibt, wo ein Skript verlinkt ist.


WTF-Skript:

Das Beste kommt zum Schluss. Einige Godot-Spieleentwickler haben es geschafft, gute Spiele mit Signalen und Gruppen zu entwickeln.

MeshInstance (Knoten) mit einem leeren Knoten oben ermöglicht ein einfaches Verschieben und Neugestalten der Kinder.
--- Mesh (Mesh +Skript || Signal)
--- Material (Sprite +Script || Signal)
--- Transform (Position3D +Script || Signal)

Wenn der Baum Objekte mit einer Tiefe von 2 oder mehr Szenen verbinden muss, wird stattdessen eine Gruppe verwendet. Bemerkenswert an diesem Workflow ist, wie er flache Bäume hat.
Probleme:
1.) Signale und Gruppen lassen ganze Teile des Spiels einfach fehlschlagen, ohne auch nur eine Warnung.
2.) Kleine sinnlose Skripte, die nur herumlungern. Sie senden lediglich ein Signal und verfolgen einen einzelnen Wert.
3.) Das Bewegen eines Objekts mit so vielen angeschlossenen Signalen ist im geringsten frustrierend.
4.) Konflikte mit Instanzsystem. Weil Instanzen nach unten fließen, während Signalverbindungen am besten nach oben gerichtet sind.

Ja, ich weiß, dass Godot eine MeshInstance -Klasse hat.
Dies zeigt, dass die meisten Workflows, die derzeit von Entwicklern verwendet werden , eine so komplexe Klasse wie MeshInstance mit mehreren Komponenten erstellen können. außer dass jeder Workflow ernsthaft fehlerhaft ist.

Alle diese Arbeitsabläufe teilen das gleiche Kernproblem. Sie sind kurzfristige Lösungen für die Entwicklung eines Spiels.
Keiner von ihnen lässt sich gut skalieren und das Debuggen ist in allen fehlerhaft.

Was Godot-Spieleentwickler von den Engine-Entwicklern brauchen, ist eine deutliche Entschleunigung des offiziellen Arbeitsablaufs zur Erstellung komplexer Objekte und Systeme.
Auf diese Weise weichen sie ab, wissen aber immer, wie es verwendet werden sollte.

archived discussion core

Hilfreichster Kommentar

Wenn die Frage einfach lautet: "Gibt es mehrere Möglichkeiten, dasselbe Ergebnis in Godot zu erzielen?", lautet die Antwort ja. Und der Versuch, einen einzigen Workflow zu erzwingen, ist absurd, da jedes System in einem Spiel unterschiedliche Anforderungen haben kann. Sie programmieren nicht auf die gleiche Weise ein System, das viel Leistung erfordert, und eines, das häufig von einem Spieledesigner aktualisiert werden muss. Alle Lösungen haben Kompromisse, daher macht es keinen Sinn, einen "offiziellen" Workflow zu erstellen.

Alle 63 Kommentare

Wenn die Frage einfach lautet: "Gibt es mehrere Möglichkeiten, dasselbe Ergebnis in Godot zu erzielen?", lautet die Antwort ja. Und der Versuch, einen einzigen Workflow zu erzwingen, ist absurd, da jedes System in einem Spiel unterschiedliche Anforderungen haben kann. Sie programmieren nicht auf die gleiche Weise ein System, das viel Leistung erfordert, und eines, das häufig von einem Spieledesigner aktualisiert werden muss. Alle Lösungen haben Kompromisse, daher macht es keinen Sinn, einen "offiziellen" Workflow zu erstellen.

kann eine Klasse so komplex wie MeshInstance mit mehreren Komponenten machen

Mit welchen Komponenten genau?

BEARBEITEN: Und nur damit Sie es wissen, eines der von Ihnen zitierten Probleme wurde mit der Aussage des Autors geschlossen: "Diese Idee ist wirklich und absolut beschissen und völlig unsinnig."

Um dies zu demonstrieren, werde ich eine Mock-Klasse verwenden, die zeigt, wie eine MeshInstance aussehen würde, wenn sie in Godot erstellt wird.
Es gibt Pseudo-Unity, auch bekannt als untergeordnete Knoten:
Godot-Benutzer verwenden untergeordnete Knoten, um ein Äquivalent zu MultiScripts zu erstellen.
Pseudo Unreal, auch bekannt als Controller und Intermediate:
Pseudo Panda3D, auch bekannt als Preload(Script):
WTF-Skript:
Ja, ich weiß, dass Godot eine MeshInstance-Klasse hat.
Dies zeigt, dass die meisten Workflows, die derzeit von Entwicklern verwendet werden, eine so komplexe Klasse wie MeshInstance mit mehreren Komponenten erstellen können. außer dass jeder Workflow ernsthaft fehlerhaft ist.

Ich verstehe nicht ganz, was Sie hier sagen wollen. Warum sollte jemand eine MeshInstance-Klasse erstellen, wenn es bereits eine gibt? Und warum ist es ein Problem, dass Godot ähnliche Funktionen wie andere Engines hat? Wenn Sie versuchen, mehrere Skripte an einen Knoten anzuhängen, verwenden Sie entweder kein OOP oder Sie packen zwei separate Funktionalitäten in einen Knoten, was durch die Verwendung von Godots Knotensystem leicht behoben werden kann.

Wenn die Frage einfach lautet: "Gibt es mehrere Möglichkeiten, dasselbe Ergebnis in Godot zu erzielen?", lautet die Antwort ja ...

Wenn ich einen Hammer mache, weiß ich, wofür er bestimmt ist, ich weiß, wofür er nicht verwendet werden sollte, auch wenn ich nicht alles weiß, wofür er verwendet werden könnte.
Wenn Sie jemandem einen Hammer geben, der keine Ahnung hat, was er ist, und Sie nie erklärt haben, wie man ihn benutzt; Sie können nicht überrascht sein, wenn sie anfangen, wild zu schwingen.

Hier ist Godot, die Entwickler tappen im Dunkeln und hoffen, dass sie dadurch irgendwie etwas schaffen können.

Mit welchen Komponenten genau?

Werden Dinge wie Materialien und Transformationen als Teil der ursprünglichen Instanz betrachtet oder nicht?
Wenn wir ähnliche Komponenten erstellen, wie hängen wir sie an den Knoten an?

Was ist mit anderen Aufgaben, wie "Ziel verfolgen" oder "auf Ziel schießen", sollten diese der Klasse hinzugefügt oder irgendwie angehängt werden?
Da Godot nie eine richtige Include- oder Import -Funktion für Godot erstellt hat, bedeutet das, dass es nie dazu gedacht war, auf diese Weise verwendet zu werden?

Wir wissen, dass wir nicht alles haben können, also stellt sich die Frage, was haben wir? Wie war das Design-to-Work?

@MysteryGM Lose und getrennte Analogien sind nicht hilfreich.

Dinge wie Materialien und Transformationen

Transform ist eine Spatial-Eigenschaft und Materials ist eine Mesh-Eigenschaft. MeshInstance baut auf Spatial auf, erbt also alle Spatial-Eigenschaften. Es ist eine einfache Hierarchie, die für mich Sinn macht.

Wenn wir ähnliche Komponenten erstellen, wie hängen wir sie an den Knoten an?

Warum sollten Sie Ihr eigenes Mesh-System erstellen, wenn Godot sie bereits hat?

Was ist mit anderen Aufgaben, wie „Ziel verfolgen“ oder „auf Ziel schießen“?

Code geht in Skripte. Sie können es in das Hauptskript des Knotens einfügen oder ihm ein untergeordnetes Skript zuweisen, wenn Sie glauben, dass dies auf diese Weise sinnvoller wäre.

Warum sollten Sie Ihr eigenes Mesh-System erstellen, wenn Godot sie bereits hat?

Weil Spielobjekte genauso komplex sind wie ein Netz, wenn nicht sogar noch mehr. Denken Sie daran, dass Engines ursprünglich Teil der Spiele waren, es war nur der Teil, der wiederverwendet wurde.

Wenn Godot keine Mesh-Klasse innerhalb der Engine effektiv erstellen kann, kann sie nicht zum Erstellen komplexer Spiele verwendet werden. Alle Spiele müssen weniger komplex sein als die Engine.
Dies wiederum bedeutet, dass es für ein professionelles Entwicklerteam nutzlos ist. Es sei denn, ein solches Team verwendet nur C++ mit dem Quellcode.

Code geht in Skripte.

Aber auf welche Weise?
Ich weiß bereits, dass ich nicht für jedes Skript ein Kind erstellen kann, da ich mehr als eine Million Funktionen brauche und selbst eine Million leere Knoten zu viel für Godot sind.
Was bedeutet das, wie viele Funktionen sollten zusammengefasst werden oder sollte ich 2-4 Monate damit verbringen, meine Objektvererbung auf Papier zu planen?

Was ich wissen möchte, ist, wie Godot mit großen Spielen mit komplexen Systemen wie Wettereffekten, volumetrischem Nebel und großen Terrains umgeht?

Das Folgende bezieht sich auf mich, meine Meinungen und Erfahrungen, _YMMV_

Jeder Motor hat seine Macken, und Godot ist da nicht anders. Wenn ich ehrlich bin, wenn man bedenkt, wie lange es seit seiner ersten stabilen Veröffentlichung her ist, bin ich definitiv verblüfft darüber, wie gut es ist und wie schnell es sich entwickelt hat. Das mag ein Grund für einige unserer Probleme sein. Das Szenen-/Knotensystem ist mein Lieblingsteil, die Einfachheit von geskripteten Knoten ist wirklich das, was für mich glänzt. Auch wenn es für mich seine Nachteile hat, mag ich Python-ähnliche Syntaxen nicht ... und das Preload-System ... konnte nicht herausfinden, wie man C # zum Laufen bringt.

Nimmt man Unity 4/5 als Beispiel (an das ich jahrelang gekettet war), hat es _Komponenten_, die so aufgebläht sind, dass es nicht mit irgendeinem anderen ECS verglichen werden kann, das ich je verwendet habe. Und oh, Sie möchten eine HTTP-Anfrage stellen? Sicher, fügen Sie Ihrer Szenenstruktur eine neue Komponente zu einem neuen Objekt hinzu, da es sehr sinnvoll ist, HTTP-Anforderungen mit In-Scene-Objekten und ihren Komponenten zu koppeln. Die Funktion „Speichern einer Szene ohne Änderungen unterbricht alle UUIDs“ schien nur erfunden worden zu sein, um es unseren nicht technisch versierten Designern zu erschweren, die Versionskontrolle zu verwenden. Mit "Don't Destroy On Load" und Prefabs will ich gar nicht erst anfangen.

Was war überhaupt die Begründung zwischen den meisten dieser Sachen? Ich würde sagen, es ist wahrscheinlich eine organische, iterative Entwicklung und hier und da ein paar hackige Problemumgehungen (auch in Godot und wahrscheinlich allen anderen Spiel-Engines zu finden). Ich meine, es stürzte so oft ab, dass meine Swift-Tastatur anfing, jedes Mal, wenn ich „_With_“ eintippte, die Worte „_Unity crashing_“ vorherzusagen. Das war ein großer Teil meines Arbeitsablaufs, Absturz -> alle Assets für eine Minute neu importieren, 30 Minuten lang arbeiten, wiederholen.

Ich habe so viel blasphemischen Gebrauch von Monobehavior gesehen, aber wem kann ich die Schuld geben? Die Engine erlaubt es Leuten, einen _GameState_ "_component_" in ein Pointlight-Objekt zu stecken. Sollen wir es verbieten? Wie argumentiere ich, dass die Spielzustandsdaten nicht einmal in der Komponente eines Szenenobjekts enthalten sein sollten, wenn die HTTP-Kommunikation (oder praktisch jede asynchrone Arbeit) eine benötigt?

Das bringt mich zu meinem Punkt, der Vergleich von Engines in ihren verschiedenen Entwicklungsstadien ist schwierig, und Godot entwickelt sich tatsächlich schnell und fügt Funktionen hinzu oder entfernt sie. Das bedeutet jedoch, dass sich unser Workflow entsprechend ändern und anpassen muss. Ich habe einen anständigen 2D-Workflow mit Godot, er ist definitiv besser als der, den ich mit Unity hatte. Ja, Best Practices sind wolkig. Ja, wenn Sie drei Entwickler fragen, haben Sie drei verschiedene Workflows. Aber ich kann nicht sagen, dass das ein neues Problem für mich ist, oder zumindest ist es eines, das bei beiden verglichenen Motoren vorhanden ist.

Ich habe Unreal (oder eine andere relevante Spiel-Engine) nicht wirklich für mehr als Prototypen und Testprojekte verwendet, kann es nicht mit angemessener Tiefe vergleichen.

Aber auf welche Weise?
Ich weiß bereits, dass ich nicht für jedes Skript ein Kind erstellen kann, da ich mehr als eine Million Funktionen brauche und selbst eine Million leere Knoten zu viel für Godot sind.
Was bedeutet das, wie viele Funktionen sollten zusammengefasst werden oder sollte ich 2-4 Monate damit verbringen, meine Objektvererbung auf Papier zu planen?

Vielleicht alle Funktionen in einem Skript? Godot kann ziemlich gut objektorientiert verwendet werden. Wenn Sie also jemals OOP verwendet haben, können Sie Skript- oder Szenenvererbung verwenden, Klassen erstellen und so weiter.

Was ich wissen möchte, ist, wie Godot mit großen Spielen mit komplexen Systemen wie Wettereffekten, volumetrischem Nebel und großen Terrains umgeht?

Wettereffekte? Erstellen Sie eine Szene, die einen Partikelknoten, eine Sonne und eine Weltumgebung enthält, und hängen Sie ein Skript an die Wurzel an. Dieses Skript kann das Wetter steuern. Sie können auch einen leeren Knoten erstellen und ihn als Zustandsmaschine verwenden, indem Sie für jeden Zustand, den Sie haben (wie Regen, Sonnenschein usw.), leere Knoten anhängen. Fügen Sie jetzt einfach den Code für jeden Zustand in ihre Knoten ein. Diese Zustandsmaschine kann vom Root-Skript gesteuert werden. Dies ist eine sehr einfach zu lesende Art, Dinge zu tun.

Volumennebel? Ich glaube, ich habe das in der neuen FPS-Demo gesehen.

Große Gelände? Ich hatte einmal ein Projekt mit prozeduralen Terrain-Meshes und es lief ziemlich reibungslos auf meinem ein paar Jahre alten Laptop.

Dies sind nur einige Funktionen und kein „großes Problem“, über das Sie im OP gesprochen haben.

Wettereffekte? Erstellen Sie eine Szene, die einen Partikelknoten enthält...

Nun, wir planen, etwas ehrgeiziger zu sein :) mit einer Regionskarte, um sowohl der KI zu sagen, wohin sie gehen soll, als auch mit einem anderen Kanal für Regenausschlusszonen, während der letzte Kanal für die Tiefe beibehalten wird, damit sich im Laufe der Zeit Schnee bilden kann.

Große Gelände?

Platz groß. Wir brauchen eine Möglichkeit, Szenen auf Vector3(0,0,0) zurückzusetzen, ohne dass es einfriert, weil zu viele Knoten entfernt werden müssen. Physik und alles wackelt mit großen Schwimmern.

Es hat so aufgeblähte Komponenten, dass es mit keinem anderen ECS verglichen werden kann, das ich je verwendet habe.

Zugegeben, Komponenten können schrecklich sein, deshalb würde es uns nicht überraschen, wenn Godot eine andere Strategie im Sinn hat. Wir haben jedoch keine Ahnung, welche Strategie Godot geplant hat oder ob dies überhaupt der Fall war.

2 Monate Lernen Godot hat uns nur überlegt, wie man kleine Spiele macht.
Da noch 14 Tage verbleiben, um sich für die Verwendung von Godot zu entscheiden, hoffe ich, dass die Entwickler der Engine erklären können, wie sie bei großen Projekten funktionieren soll.

Das Letzte, was wir tun wollen, ist, gegen das Engine-Design zu kämpfen, während wir versuchen, das Spiel zu entwickeln.

@MysteryGM Ich verstehe wirklich nicht, warum Sie denken, dass Godot für große Projekte nicht geeignet ist. Sein Design eignet sich wirklich für große Projekte, da Sie alles in separate Szenen aufteilen und OOP verwenden können, um die Arbeit wiederzuverwenden. Wenn Ihr Problem bei der Verwendung von Godot für ein großes Projekt darin besteht, dass Sie nicht wissen, wie Sie ein Ziel erreichen können, fragen Sie einfach auf den Hilfekanälen von Godot Discords, Sie erhalten eine sehr sofortige Antwort.

Physik und alles wackelt mit großen Schwimmern.

Siehe Nr. 288

Wir haben jedoch keine Ahnung, welche Strategie Godot geplant hat oder ob dies überhaupt der Fall war.

Ich verstehe, dass es zunächst etwas fremd ist, aber für mich ist die Verwendung von Knoten und Skripten ziemlich einfach. Ich würde auf jeden Fall empfehlen, sich (mindestens) die Hobbyversion dieses Kurses hier anzusehen: https://gumroad.com/gdquest
Es verwendet eine Knotenskriptstruktur, die meiner sehr ähnlich ist, und kann Ihnen definitiv einen besseren Einblick darüber geben, wie diejenigen, die wirklich mit der Engine zu tun haben, es verwenden. Der Autor leistet einen wichtigen Beitrag zu Godot Docs.

edit: Eigentlich kannst du dir die Quelle im Repository ansehen, wenn du den Kurs nicht willst https://github.com/GDquest/make-pro-2d-games-with-godot

Da noch 14 Tage verbleiben, um sich für die Verwendung von Godot zu entscheiden, hoffe ich, dass die Entwickler der Engine erklären können, wie sie bei großen Projekten funktionieren soll.

Ich glaube, ich bin nur etwas verwirrt darüber, was genau du damit meinst. Sie haben zuvor die Hammer-Analogie als Beispiel verwendet, aber es ist eine fehlerhafte Analogie, da ein Hammer im Allgemeinen ein einfaches Gebrauchswerkzeug für den einmaligen Gebrauch ist und es aufgrund seiner Erschwinglichkeit ein intrinsisches Verständnis dafür gibt, wofür das Werkzeug verwendet wird.

Obwohl Sie alle Probleme mit all diesen oben genannten Systemen aufgelistet haben, denke ich, dass die Realität eines jeden großen Softwareprojekts darin besteht, dass jede Architekturentscheidung, die Sie treffen, später zu einigen Nachteilen führen wird, die Sie einfach haben müssen arbeiten Sie mehr mit auf dem Weg. Suchen Sie also nach einem Wunderwaffe Vorschlag? Denn ehrlich gesagt glaube ich nicht einmal, dass die meisten Unity- oder Unreal-Projekte genau der „empfohlenen“ Struktur folgen und oft die Engine forken, um dem für sie am besten geeigneten Workflow zu entsprechen. Ich würde sogar so weit gehen zu argumentieren, dass jedes Spiel seine eigene einzigartige Idee zur Node-Architektur haben muss. (Ein Simulationsspiel hätte beispielsweise eine ganz andere Struktur als ein Third-Person-Shooter.)

Ich denke, man könnte für mehr Dokumentation zu Beispielen der Projektstruktur argumentieren, aber ich denke, das ist nur eine Frage von mehr Beiträgen zur Dokumentation.

trennen Sie Szenen und verwenden Sie OOP, um Arbeit wiederzuverwenden.

Wie ich bereits erwähnt habe, ist das Bewegen von Objekten nach dem Anbringen von Signalen ein Schmerz. Vor allem, wenn sie aufhören zu arbeiten, ohne jemals eine Ausnahme oder Warnung zu geben.
Wir haben uns für ein Refactoring-Tool eines Drittanbieters entschieden, nachdem ein anderer Entwickler es erwähnt hatte. aber selbst damit kann es Godots einzigartige Probleme nicht lösen.
Wenn sich die Dinge nicht bewegen, führt dies zu diesem Problem (Bilder von unserem "Problemboard"):
pawndefend
Um dies zu beheben, haben wir untergeordnete Knoten erstellt. Außer bei etwa 50 000 fängt es an, Probleme zu verursachen, selbst wenn es sich nur um Knoten handelt.
pawnfollow

Was wir wissen wollen, ist, wie wir mit diesen Problemen umgehen, wie Godot vorhatte, damit umzugehen; Wir haben jeden Workflow getestet, den ich oben erwähnt habe.

Siehe Nr. 288

Danke dafür, wir sind so an Ruheweltkoordinaten gewöhnt, dass wir das nie überprüft haben.

Ich verstehe, dass es zunächst etwas fremd ist, aber für mich ist die Verwendung von Knoten und Skripten ziemlich einfach.

Das Problem ist nicht, dass es fremd ist, das Problem ist, dass es ein anderes Problem verursacht. Hauptsächlich, dass das Hinzufügen weiterer Kinder das Spiel schließlich verzögert oder einfriert, wenn wir versuchen, sie zu entladen.
Auch wenn es nur Knoten sind.

Warum brauchen Sie 50.000 Objekte in Ihrem Spiel? Dies würde sicherlich JEDEN Motor verzögern.

Warum brauchen Sie 50.000 Objekte in Ihrem Spiel?

Weil wir Knoten verwenden, um den Objekten zusätzliche Skripte hinzuzufügen. Weil die UI-Tools von Godot Container in Containern in Containern verwenden, um Dinge in Echtzeit zu skalieren.
Unsere kleinste Benutzeroberfläche umfasst über 800 Objekte. Die meisten dieser Behälter.

Wir haben 50.000 Objekte, weil eine einzelne feindliche KI +/-8 Knoten mit einem Zweck und +/-64 Knoten hat, die nur da sind, damit wir ihnen Skripte hinzufügen können.
Denn indem wir jede Aufgabe in ihren eigenen Code aufteilen, können wir sehen, wo unsere Probleme liegen. Weil es keine andere Möglichkeit gibt, schnell einen bestimmten Teil des Spiels zu finden.

In diesem Fall scheinen Sie in die Zone eingedrungen zu sein, in der benutzerdefinierte Module eine gute Option sind.
http://docs.godotengine.org/en/3.0/development/cpp/custom_modules_in_cpp.html
Sie können dort benutzerdefinierte Knoten erstellen und viele Verschachtelungen vermeiden.

Bearbeiten: Obwohl ich argumentieren würde, dass 800 Objekte für eine (kleinste?) Benutzeroberfläche auf schlechtes Design / schlechte Architektur hindeuten.

Ich verstehe ernsthaft nicht, wie Sie fast 64 Skripte für ein einzelnes Objekt haben können. Dies klingt eher nach einem Designproblem Ihres Projekts als nach einem Godot-Problem (wiederum wird wahrscheinlich jede Engine verzögert). Konsolidieren Sie Ihren Code in weniger Skripts. Erstellen Sie kein Skript für jede Funktionalität, sondern für jeden Objekttyp (Wenn ein "Feind"-Knoten XYZ ausführen kann, fügen Sie diesen Teil dem Feind-Skript hinzu, anstatt untergeordnete Knoten für die X-, Y- und Z-Funktionalität hinzuzufügen). . Wenn Sie dazu erweiterte Funktionen benötigen, können Sie vielleicht benutzerdefinierte Vererbung und/oder C#-Schnittstellen verwenden.

In diesem Fall scheinen Sie in die Zone eingedrungen zu sein, in der benutzerdefinierte Module eine gute Option sind.

Sehen Sie, das war eines der Dinge, über die wir uns wundern, weil wir alle C++ kennen, wenn benutzerdefinierte Module benötigt werden, würden wir stattdessen einfach die Godot-Engine bearbeiten.
Wir wissen, dass wir #include sicher verwenden können, wenn Godot preload() fragwürdig ist; Niemand kann uns sagen, wie stabil es ist oder ob es irgendwelche Nachteile gibt.

Ich verstehe ernsthaft nicht, wie Sie fast 64 Skripte für ein einzelnes Objekt haben können.

Einfach, jede KI kann mehr oder weniger 64 Aufgaben erledigen, auch keine kleineren Aufgaben.
Ein Skript ist zum Beispiel SquadFlightPatters und darin sind alle Flugformationen, alle 20 davon, dann gibt es SquadFlightPattersCosmetic, das nur Animationen, Sound und Partikel auflöst, die sich auf Flugmuster beziehen.

Unsere Regel ist im Moment, das Feedback der Benutzer vom Mechaniker zu trennen.

Wenn ein "Feind"-Knoten XYZ ausführen kann, fügen Sie diesen Teil in das Feind-Skript ein, anstatt untergeordnete Knoten für die X-, Y- und Z-Funktionalität hinzuzufügen

Schaut man sich die Bilder an und Pseudo Unreal, auch bekannt als Controller und Intermediate.

Da wir alle C++ kennen, würden wir, wenn benutzerdefinierte Module benötigt werden, stattdessen einfach die Godot-Engine bearbeiten.

Ich finde das Erstellen von Modulen viel einfacher als das Ändern der Engine selbst, da sie darauf aufbaut, anstatt in sie hinein.

Ich kann mir diese Skalierung jedoch immer noch nicht auf so hohe Zahlen vorstellen, insbesondere bei einer Benutzeroberfläche mit Hunderten oder Tausenden von Knoten pro Widget.

Als Antwort auf die referenzierten Probleme in OP:

  • 19486 :

    • Fügen Sie eine ordnungsgemäße Abhängigkeitsverwaltung mit systemweiten Installationen von Assets hinzu. Verschieben Sie Addons aus dem Projekt selbst mit einer Möglichkeit, sie zur Änderung zurückzubringen
    • Erleichtern Sie das Erweitern benutzerdefinierter Knoten, ermöglichen Sie die sprachübergreifende Skriptvererbung
    • Ermöglichen Sie die Referenzierung von Skripten nach Klassennamen und Namespace, um im Fall von Assets superlange Pfade zu vermeiden.

    Skriptklassen lösen das letzte Problem. Namespaces können erstellt werden, indem eine Toplevel-Skriptklasse mit Konstanten erstellt wird, die als Aliase für andere Skripts dienen. Die Änderungen, die ich in 3.1 am Szenen-Dock des Editors vorgenommen habe, machen es jetzt auch VIEL einfacher, benutzerdefinierte Skripte zu erweitern. Was die sprachübergreifende Vererbung betrifft, so wird diese nie offiziell implementiert, aber wenn MultiScripts jemals wieder eingeführt werden, könnten diese es ziemlich gut vortäuschen.

  • 7402 : Auch hier sind Skriptklassen die Lösung für dieses Problem (die "einfachere Lösung", an die reduz gedacht hatte, wenn Sie einige der abschließenden Kommentare aus dieser Ausgabe sehen).

  • 15996 : Das war meine Erkenntnis, dass das, was ich wollte, ein Eigenschaftssystem war (bevor ich verstand, was Eigenschaften sind) und folglich wurde mir klar, wie schrecklich mein ursprünglicher Vorschlag war, da er das geplante Design von Szenen und Knoten vollständig verzerrte und das Ganze umwandelte Ding in ein kompositionsbasiertes Vererbungssystem - etwas, das eher dem entspricht, was Unity tatsächlich tut, was ekelhaft ist (in Unity können Sie getComponent von jeder KOMPONENTE verwenden und es ruft die Geschwisterkomponente auf dem besitzenden GameObject ab. Die Komponenten sind in der Praxis ein Erweiterung des GameObjects, die ihre Abhängigkeiten aufeinander schiebt).

  • 8502 : MultiScript sind einfach Werkzeuge, die es verschiedenen Skriptsprachen ermöglichen, voneinander zu erben, ähnlich wie die Blueprints von UE4 direkt von C++-Skripten erben können (was in Godot nicht möglich wäre, da der Vergleich ein GDScript hat, das ein NativeScript erweitert. VisualScript unterstützt Vererbung überhaupt nicht, daher ist GDScript hier der passendere Vergleich).

    Da MultiScript im Wesentlichen JEDES Skript unterstützt, das den Basis-Engine-Typ erweitert (Sie könnten also mehrere Node-erweiternde Skripts aus verschiedenen Sprachen haben, die alle unterschiedliche Dinge tun, aber nicht miteinander verwandt sind), funktioniert es tatsächlich fast mehr wie ein sprachübergreifendes Merkmalssystem ... sozusagen. Ich denke jedoch, dass das erneute Hinzufügen von MultiScript ziemlich cool wäre

Viele der im OP angesprochenen Probleme drehen sich darum, dass es mehrere mögliche Möglichkeiten gibt, ein Problem anzugehen, von denen jede verschiedene Ineffizienzen aufweisen kann. Wenn es eine bestimmte Vorgehensweise gibt, die am besten wäre, stellt die Engine normalerweise ihre eigene Implementierung in der Haupt-C++-Engine bereit (keine Notwendigkeit für Skripte oder Plugins) und das ist die empfohlene Verwendung.

Wenn eine solche Klasse existiert und die Leute sie nicht verwenden, dann ist das ein Zeichen dafür, dass 1) sie die Dokumentation nicht richtig überprüfen, um zu sehen, ob ihre Bedürfnisse bereits von der Engine erfüllt werden / wie die Engine ihre Verwendung vorschlägt, oder 2) Die Engine / Organisation macht die Dokumentation nicht gut genug, um die Dokumentation für Benutzer gut sichtbar oder zugänglich zu machen (da sie die vorhandenen Ressourcen nicht finden).

Das einzige, was getan werden muss, um Problem 1 zu beheben, ist, dass diese Personen ihr Problem äußern und jemand anderes sie auf die Dokumentations- oder Q&A-Website weiterleitet, um ihnen zu helfen, ihre Lösung zu finden. Ich habe ein Problem (#23043) erstellt, in dem vorgeschlagen wird, dass Benutzer die Q&A-Site direkt vom Editor aus durchsuchen und verwenden können, was bei Problem 2 sehr hilfreich sein sollte. Die Gründe sind im Link beschrieben.

(Bearbeiten: Wenn es viele Möglichkeiten gibt, ein Problem zu lösen, und eine dieser Möglichkeiten weitaus besser ist als jede andere, und Godot noch keine eigene native Lösung dafür implementiert, dann wäre dies etwas, das als neues Feature vorgeschlagen werden könnte für die Engine. Auf diese Weise haben wir das SimplexNoise-Zeug hinzugefügt, da die Leute ihre eigenen SimplexNoise-Algorithmen in GDScript / Shader-Code usw. geschrieben haben).


Basierend auf dem von Ihnen dargestellten "Problemboard" besteht das Problem darin, dass Mehrfachvererbung nicht unterstützt wird (und auch keine gute Idee ist), also haben Sie sich für Komponentenknoten entschieden, die ihrem übergeordneten Element Funktionalität gewähren (was für mich vernünftig klingt). Wenn Sie auf Probleme mit Ihrem Spiel stoßen, weil es einfach zu viele Knoten erstellt, dann scheint es mir höchstwahrscheinlich ein Problem mit Ihrem allgemeinen Ansatz zu geben (was Sie anscheinend erkennen und Hilfe suchen um hier zu identifizieren).


Was Ihre Beispiele für Workflows in OP betrifft ...

  • Unity-Ansatz, untergeordnete Knoten:

    Es ist sinnvoll, untergeordnete Knoten zu verwenden, vorausgesetzt, man schreibt Paarungslogik. Hier wäre idealerweise ein Trait-System nützlich (damit man die Paarungslogik einmal schreiben und sie bei Bedarf einfach überall replizieren kann). Ich schreibe Komponenten oft so, dass sie sich automatisch als "Ziele" für ihre Eltern festlegen, wenn sie übergeordnet/nicht übergeordnet sind, und relevante Signale automatisch verbinden/trennen. Sie können dafür die NOTIFICATION_(UN)PARENTED-Benachrichtigungen in _notification(what) verwenden.

  • UE4-Ansatz mit Controllern:

    Mit Godot 3.1 können Sie Skriptklassen für Skripte zuweisen, sodass Sie sie nicht mehr vorab laden müssen. In diesem Fall erlaubt Ihnen Godot, Knoten Typnamen zuzuweisen, aber es ist spezifisch für das Skript, also müssen Sie vorsichtig sein. Szenen erhalten nicht die gleiche Behandlung und werden es wahrscheinlich auch nicht, da es bedeuten würde, dem Engine-Kern eine Menge Dinge hinzuzufügen (worüber Kern-Entwickler ziemlich empfindlich werden können).

    Ich bin mir auch nicht sicher, wie Sie so viel doppelten Code bekommen? Wenn mehrere Klassen dieselbe Logik erfordern, bündeln Sie diese Logik in einem einzigen Knoten und reproduzieren diesen Knoten dann unter den Klassen, die ihn benötigen, genauso wie Sie es mit Unreal (Komponenten, untergeordnete Akteure), Unity (MonoBehaviours oder untergeordnete GameObjects) tun würden. , oder so ziemlich jede andere Engine, die Abhängigkeiten auf ein eigenes Objekt verschiebt, um die Wiederverwendung von Code zu reduzieren.

  • Panda3D-Ansatz mit Preloads:

    Ich könnte verstehen, dass es bei diesem Ansatz viele Probleme gibt, da NodeRefs noch keine Sache sind, und es gibt im Moment Probleme beim Exportieren von Ressourcenskripten, die ich für 3.2 beheben möchte (obwohl Sie die Lösung wahrscheinlich selbst vornehmen könnten). leicht genug, es ist ziemlich klein).

  • WTF-Skript-Ansatz:

    Ich verstehe nicht wirklich all die Probleme, die Sie hier haben, wahrscheinlich weil wir nicht viel Kontext haben.

    Konflikte mit dem Instanzsystem. Weil Instanzen nach unten fließen, während Signalverbindungen am besten nach oben gerichtet sind.

    Wann möchten Sie das Signalauslöseverhalten eines Elternteils bei einem Nachkommen haben? Warum lassen Sie nicht einfach den Elternteil direkt den Nachkommen und seine Methode abrufen und aufrufen? Es besteht keine Gefahr, dass der Elternteil sein Kind sieht. Es ist, als würde man sagen, dass ein C++-Objekt nicht in der Lage sein sollte, auf seine Struktur- oder Klassenmitgliedsvariablen (?) zuzugreifen.

    Kleine sinnlose Skripte, die nur herumlungern. Sie senden lediglich ein Signal und verfolgen einen einzelnen Wert.

    Dies ist bereits ein Zeichen dafür, dass das Design des Projekts nicht gut ist. Es ist das Problem, dass jede einzelne Interaktion im Spiel von einem eigenen persönlichen Objekt verfolgt wird. Das ist nicht wirklich ideal, aus jeder Perspektive.

    Das Bewegen eines Objekts mit so vielen angeschlossenen Signalen ist zumindest frustrierend.

    Inwiefern? Ich habe im Allgemeinen festgestellt, dass ich entweder die Verbindungen in der Szenendatei fest kodiere oder Signale für Knoten algorithmisch verbinde und trenne, wenn sie verschoben werden sollen. Das hat meinen Zwecken genug gedient, aber wenn Sie bestimmte Probleme haben, kann das Teilen dieser Probleme anderen helfen, Ihnen zu helfen.

    Signale und Gruppen lassen ganze Teile des Spiels einfach fehlschlagen, ohne auch nur eine Warnung.

    Das ist das Problem bei jedem booleschen Via-Existenz-Design. Die Alternative besteht darin, ALLE Objekte zu durchlaufen, zu prüfen, ob sie den Kriterien entsprechen, und dann die Logik auszuführen, wenn sie übereinstimmen, und wenn sie übereinstimmen, aber nicht richtig, einen Fehler auszugeben. Im Falle von Signalen und Gruppen werden Verhalten automatisch auf alles innerhalb des Sets ausgelöst, sodass es keine Möglichkeit gibt, zu erkennen, dass während der Ausführung ein Problem aufgetreten ist, wenn Dinge aus dem Set herausfallen. Der einzige Weg, solche Probleme zu finden, ist während der Setup-Prozesse, wo die Gruppen/Signale überhaupt angeordnet werden.


Jedenfalls war das alles meine Erfahrung mit dem Zeug. Es würde uns viel mehr helfen, mehr über Ihr Projekt zu erfahren und darüber, was es eigentlich alles tut , damit wir Vorschläge für Ihren speziellen Anwendungsfall machen können.

In jedem Fall scheinen die Probleme, die Sie hier angesprochen haben, keine "neuen" Probleme mit dem Design oder der Implementierung von Godot Engine an sich zu sein. Godot gibt den Menschen eine API und wie die Menschen diese API verwenden, ist ihnen überlassen. Wenn Sie eine Vorstellung davon haben, wie ein bestimmtes Feature besser in Godot integriert / verfügbar gemacht werden sollte (z. B. die Wiederbelebung von MultiScript), dann wäre das ein guter Vorschlag.

So wie es aussieht, scheint die Frage hier eher zu sein, "was ist der beste Weg, ein System wie X zu entwerfen", was ... nicht wirklich ein GitHub-Problem ist. Scheint auf der Q&A-Site für eine Art "Best Practices"-Frage besser geeignet zu sein. Das, oder es ist ein Vorschlag, dass wir eine Möglichkeit bieten sollten, diese Art von anwendungsfallspezifischen Informationen klarer / öffentlich verfügbar zu machen, und genau darum geht es in meinem Q&A-Problem.

Skriptklassen lösen das letzte Problem.

Zuerst danke für die lange Antwort, das ist viel und hat eindeutig einige Zeit zum Schreiben gedauert.
Ich freue mich, von Skriptklassen zu hören, wir haben 3.1 nicht verwendet; nur um die FPS-Demo auszuführen.

aber wenn MultiScripts jemals wieder eingeführt werden, dann könnten diese es ziemlich gut vortäuschen.
Es ist völlig verständlich, wenn Godot niemals MultiScripts implementiert. In Wahrheit habe ich nur darauf hingewiesen, dass viele Benutzer auf GitHub nach ähnlichen Workflow-Lösungen gesucht haben, wie wir es versucht haben.

Wann möchten Sie das Signalauslöseverhalten eines Elternteils bei einem Nachkommen haben? Warum lassen Sie nicht einfach den Elternteil direkt den Nachkommen und seine Methode abrufen und aufrufen?

Ich habe das Gefühl, ich sollte das erklären. Damals hatten wir sehr große Skripte mit jeweils ungefähr +/- 30 Funktionen. Aus diesem Grund wollten wir vermeiden, dem ohnehin schon umfangreichen Skript zusätzliche Signalfunktionen hinzuzufügen.
Das Ergebnis war, dass wir lose Skripte erstellt haben, um die Arbeit von dem großen Skript zu entlasten.

Dies ist bereits ein Zeichen dafür, dass das Design des Projekts nicht gut ist.

Das ist in der Tat die Wurzel des Problems. Hauptsächlich, dass wir viele von der Godot-Community empfohlene Designs und einige aus Tutorials ausprobiert haben.
1.) Anfangs hatten wir wahnsinnige Vererbungen, die schnell aufgegeben wurden, als klar wurde, dass das Speichern von Zweigszenen oder das Verschieben eines Objekts in eine andere Szene Verbindungsabbrüche signalisiert.
2.) Dem folgten wir mit großen Skripten. Abgesehen von den abstrakten Namen dieser Skripte, um zu versuchen und zu erklären, was jedes tut, war es schwierig, Probleme zu finden.
Wir wussten, wie die Namen der Funktionen sind, die wo Probleme verursachen, aber nicht genau, wo sie sich befinden.
3.) Dann haben wir beim Lesen des Handbuchs den Child-Node-Ansatz gefunden. Es war vielleicht zu verlockend, weil es direkte Knoten zuließ und wir die Struktur im Editor sehen konnten; Filtern Sie es auch, um genau das gewünschte Skript zu finden.

Am Ende bin ich hier, und ich denke, die letzte Antwort hat vieles angesprochen, worüber ich mich gewundert habe; Ich muss morgen nochmal nachsehen, da es hier 2 Uhr morgens ist.

"Was ist der beste Weg, ein System wie X zu entwerfen", was ... nicht wirklich ein GitHub-Problem ist.

Ich möchte darauf hinweisen, dass wir die meisten unserer anderen Optionen ausgeschöpft haben. Jeder von uns hat sich in den Q&A-Foren umgehört, wir haben Freunde in der Community gefunden und Beispiele von ihnen gesammelt. Scannte die Dokumente auf der Suche nach Erklärungen.
Alle von mir beschriebenen Workflows sind Dinge, die wir versucht haben, uns von Godot-Benutzern zu erklären, die diese Workflows verwenden. Jeder würde in den genannten Engines funktionieren, sie funktionierten nur nicht so gut in Godot.

Nur der letzte Workflow funktionierte irgendwie, außer dass unser Hauptprogrammierer seinen Kopf gegen den Tisch schlug und jemanden mimisch erwürgte.

Es tut uns leid zu lesen, dass Sie Probleme haben, Lösungen für Ihre Probleme zu finden. Will hat Ihnen bereits eine lange Antwort gegeben, also werde ich versuchen, das Gespräch nicht zu sehr zu überladen, aber an diesem Punkt hört es sich so an, als bräuchten Sie eher einen Berater, der Ihnen hilft, die spezifischen Herausforderungen zu lösen, die sich aus Ihren Bedürfnissen ergeben haben.

Hauptsächlich, dass wir viele von der Godot-Community empfohlene Designs und einige aus Tutorials ausprobiert haben

Die meisten von uns in der Gemeinde arbeiten in Projekten von relativ kleinem Umfang. Ich verwende viele Knoten, um den Sinn und die Struktur eines bestimmten Systems in Tutorials zu vermitteln. Dies wird für die meisten Menschen gut skalieren. Aber was für ein kleines oder mittelgroßes Spiel funktioniert, gilt nicht für größere.

In Anlehnung an das, was @willnationsdev zuvor gesagt hat, könnte es sich lohnen, Back-End-Code in Betracht zu ziehen, um das Spiel zu skalieren, sowohl in Bezug auf die Leistung als auch einfach, um weniger Code im Editor selbst zu verwalten. Ansonsten kann ich nicht viel weiterhelfen, da ich, wie viele hier, keine Erfahrung mit größeren Projekten habe. Viel Glück!

Hallo, wir haben nur noch eine Frage.

Wenn wir zwei nicht verwandte Objekte haben, wie ein Gebäude und Wasser, aber wir möchten, dass die Skripte dieser Objekte interagieren, wie machen wir das ohne Nodes oder Preload?
Das Wasser ist eine Textur, sodass es auch nicht mit dem Gebäude kollidieren kann.

@MysteryGM Wollen Sie damit sagen, dass Sie keine Knoten haben möchten, die Gebäude und Wasser darstellen, oder Sie möchten einfach keine Skripte daran anhängen? Es ist nichts Falsches daran, Daten zur Verarbeitung zu haben, die nicht in irgendeiner Weise im Szenenbaum vorhanden sind, abgesehen von einem einzelnen Daten enthaltenden Knoten.

Wenn Sie den ECS-Ansatz wählen möchten, anstatt Skripts an jede Instanz eines Typs anzuhängen und sie einzeln verarbeiten zu lassen, können Sie einen einzelnen „System“-Knoten haben, der die Knoten gemäß einem Typ/ Gruppe, die Sie ihnen zugewiesen haben. Wenn Sie das Anhängen von Skripten an Knoten für ihre individuellen detaillierten Informationen vermeiden möchten, können Sie diese Informationen auch im System speichern, je nachdem, wie zeitlich sie sind. Dies hält Ihre Knoten leichter und kann für Sie effizienter sein, wenn Sie mit Tausenden von Entitäten des gleichen Typs arbeiten.

Mit 50.000 von allem haben Sie längst den Punkt überschritten, an dem Godots objektbasierte Metapher SceneTree -and-nodes nützlich ist.

Das ist nicht viel anders als bei anderen Engines, mit Unity würden Sie mit ihren Spielobjekten, GC, ähnliche Grenzen erreichen, oder mit UE4 würden Sie Probleme finden, Blaupausen so weit zu skalieren - aber vor allem bedeutet diese Menge von irgendetwas die Standardeinstellung visuelle Editoren sind einfach nicht mehr nützlich, und die bereitgestellten Tools beginnen zu brechen oder zumindest schlecht zu funktionieren.

Bei allen Engines ist die Lösung weitgehend gleich: Erstellen Sie Ihre eigenen Lösungen. Welche das sind, hängt mehr von Ihrem Spiel, Ihrer Architektur und den Details ab als von der Engine.

Manager-Klassen, Pub-Sub-Kommunikationsbusse, Nachrichtenbroker, Instanziierungs-Manager ähnlich wie bei Partikeln, Objektpools, benutzerdefinierten Shadern zum Auslagern von Arbeit auf die GPU, Compute-Shadern, Verschieben der Verarbeitung auf Threads oder andere Prozesse/Server – das gibt es Tonnen von Bausteinen für mögliche Lösungen, und welche Sie kombinieren müssen, hängt von Ihrer spezifischen Problemstellung ab.

Unity erleichtert einiges davon mit seiner neuen ECS-Infrastruktur. Bei UE4 bin ich mir nicht sicher. Am Ende müssen Sie auf diesem fortgeschrittenen Niveau jedoch den größten Teil des schweren Hebens selbst erledigen (oder jemanden beauftragen, der erfahren ist, dies für Sie zu tun).

UE4 und Unity sind nur insofern einfacher, als sie älter und etablierter sind und daher eine größere Anzahl von Menschen auf solche Skalierungsprobleme gestoßen ist, was bedeutet, dass mehr Wissen (und anrechenbares Talent) für die Lösung verfügbar ist.

Aber wirklich, am Ende bringt dich kein Motor so weit. Jedes ambitionierte Spiel wird in jeder Engine an Grenzen stoßen. Ich kenne unzählige Beispiele für mittlere bis große Spiele in UE oder Unity, die ähnliche Probleme lösen mussten. Lösen Sie sie entweder oder reduzieren Sie Ihren Umfang.

Was Godot-Spieleentwickler von den Engine-Entwicklern brauchen, ist eine deutliche Entschleunigung des offiziellen Arbeitsablaufs zur Erstellung komplexer Objekte und Systeme.

Das hängt stark von Ihrem Spiel ab. Darauf gibt es bei keinem großen Motor eine eindeutige Antwort.
Sollten Sie den gameobjects-scene-basierten Ansatz in Unity verwenden? Oder das hybride ECS? Das komplett neue ECS? Welche Renderpipeline verwendest du?
Werden Sie Blueprint oder C++ in Ihrem UE4-Projekt verwenden?

Alle Engines bieten unzählige Auswahlmöglichkeiten, unzählige Worklows und viel Freiheit, denn es gibt keine Einheitslösung.

Wenn Sie also konkrete Ratschläge benötigen, wie Sie Ihr spezielles Spiel in Godot angehen, wie Sie es strukturieren und welche Architektur Sie verwenden sollten, müssen Sie viel mehr Kontext und Informationen bereitstellen.

Sagen Sie uns, was Sie erreichen möchten, und vielleicht kann sich jemand mit Rat einschalten. Wenn nicht, besteht die einzige Möglichkeit darin, einen erfahrenen Godot-Entwickler als Berater einzustellen.

Ich kann Groud nur zustimmen:

Alle Lösungen haben Kompromisse, daher macht es keinen Sinn, einen "offiziellen" Workflow zu erstellen.

@mhilbrunner Ich spiele hier nur Devils Advocate, aber ein besseres Engine-Design (wie ein richtiges ECS in den meisten Fällen, in denen Leistung wichtig ist) macht viele dieser Grenzen deutlich höher, als es fast jedes Spiel jemals erfahren würde (so der neue Rust Amethyst Spiel-Engine aufbaut, um sich beispielsweise darauf zu konzentrieren).

Aber ja, ich habe in Godot (2) ein ECS-ähnliches Ding gemacht und es hat viel besser funktioniert als der Scenetree-Instanziierungsstil in Bezug auf Effizienz und Verteilung der Funktionalität. Es kann gemacht werden, nur ein bisschen schmerzhaft, da Godot einige nützliche Primitiven dafür fehlen.

@OvermindDL1

Ich kann nur für mich selbst sprechen, nicht für andere Godot-Entwickler, und ich habe nur Erfahrung mit UE, Unity und Godot, also weiß ich nichts über Rust Amethyst.

Es kann gemacht werden, nur ein bisschen schmerzhaft, da Godot einige nützliche Primitiven dafür fehlen.

Eine Diskussion darüber zu führen, wo es sinnvoll wäre, solche Primitive hinzuzufügen / wie Godot solche Anwendungsfälle besser berücksichtigen kann, wäre meiner Meinung nach sehr wertvoll. Vielleicht nicht in dieser Ausgabe :)

Aber wir sollten dieses Feedback irgendwie sammeln.

Und ich stimme zu, dass es je nach Engine unterschiedliche Grenzen gibt, aber auch hier habe ich gesehen, dass Leute ähnliche Barrieren in Unity und UE4 erreicht haben. Vielleicht später, vielleicht waren die höher - aber am Ende müssen Sie in der Lage sein, Probleme zu lösen, auf die Sie in jeder Engine stoßen. :)

@MysteryGM Wollen Sie damit sagen, dass Sie keine Knoten haben möchten, die Gebäude und Wasser darstellen, oder Sie möchten einfach keine Skripte daran anhängen?

Ich habe bereits ein Skript an das Wasserobjekt angehängt, das den Wassershader speist. Daher kann ich kein Skript mehr an den Wasserknoten anhängen.
Ich habe ein Skript an das Gebäude angehängt, das seine Ressourcenproduktion steuert und Dinge wie Türen damit verbindet. Es hat also auch ein Skript, dem ich keinen weiteren Code hinzufügen möchte.

Was mache ich jetzt, wenn beide Objekte bereits Code haben? Ich kann keine weiteren Knoten hinzufügen, und es ist immer noch unklar, ob Preload eine mögliche Lösung ist.

Meine Frage, wenn ich es als OOP-Design formuliere, lautet: Wie greifen zwei Skripte auf die Schnittstellen des anderen zu?

Das Problem ist, dass GDscript nicht so aussieht, als hätte es eine Möglichkeit, direkt auf andere Skripte zuzugreifen.
Wenn ich möchte, dass Feuer Holz verbrennt, muss ich entweder Holz->erweitern->Feuer oder Feuer->erweitern->Holz haben.

@MysteryGM : Ein Tipp: Signale. Feuer kann ein Signal brennen (Ziel) haben, wobei das Ziel Ihr Holz ist.

Wie greifen zwei Skripte auf die Schnittstellen des anderen zu?

$NodeWithScript.do_function() ?

_/ich spiele immer noch Devils Advocate, nimm das nicht als Maßstab dafür, was in Godot getan werden „sollte“, bestenfalls ist es Bikeshedding_

Ich kann nur für mich selbst sprechen, nicht für andere Godot-Entwickler, und ich habe nur Erfahrung mit UE, Unity und Godot, also weiß ich nichts über Rust Amethyst.

UE verwendet ein Actor SceneTree-Modell. Unity verwendete ein EC-Modell (obwohl sie kürzlich ein ECS erstellt und das alte EC-Modell verworfen haben, ist es noch nicht ganz fertig, sieht aber vielversprechend aus). Und Godot verwendet ein Component SceneTree-Modell. ECS ist eine Teilmenge des Datenflussmusters (insbesondere eine Verallgemeinerung davon).

Kurze Zusammenfassung zu ECS:

  • Eine „Entität“ ist nur eine ganzzahlige ID, obwohl die meisten Engines eine Generation und einen Entitätsindex in ein einzelnes int32 (8-Bit-Generierung und 24-Bit-Index) oder int64 (jeweils 32 Bit, int64 ist wesentlich häufiger, da ECS es Ihnen tatsächlich zulässt) packen auf so große Mengen von Entitäten zu skalieren).

  • Eine 'Komponente' ist eine POD-Struktur in der C /C++-Terminologie, sie sollte auf keinen Fall Funktionalität enthalten. Im Allgemeinen sollte es trivial memcpy'able sein.

  • Eine Komponenten-'Tabelle' ist der Speicher für Komponenten, im Grunde kann es sich nur um ein in der Größe veränderbares Array handeln, aber im Allgemeinen werden einige Typen verwendet:

    • Anpassbares Array: Wird oft verwendet, wenn eine Komponente sehr häufig vorkommt, wie z. B. eine Position.
    • Sparse Array: Wird häufig verwendet, wenn eine Komponente dazu neigt, in Gruppen von Entitäten gleichzeitig verwendet zu werden.
    • Zuordnung: Möglicherweise eine Hash-Zuordnung oder eine Baumzuordnung oder so, abhängig von den erwarteten Leistungsmerkmalen, die jedoch im Allgemeinen für weniger häufige Komponenten verwendet werden.
    • Bitsets: Wird nur als Definition verwendet, ob eine Komponente überhaupt auf einer Entität vorhanden ist, aber nichts speichert, allgemein bekannt als Flag-Komponente.
    • Octree oder ein anderer SceneGraph (Godots Renderer könnte hier passen): Das Szenenbaum-Mapping, das vorgibt, eine Komponente zu sein.
    • Etc...: Viele, viele andere Typen, abhängig von den Zugriffs- und Leistungsmerkmalen, die für eine Komponente erwartet werden.
  • Ein „ System “ ist im Grunde genommen eine Funktion, die einen verbundenen Satz von Komponenten verwendet, obwohl die meisten Bibliotheken eine nicht virtuelle Klasse oder ein Modul oder so haben, arbeitet es über diesem verbundenen Satz von Komponenten, um etwas zu „tun“. Dies könnte das Ändern von Werten in Komponenten, das Hinzufügen oder Entfernen von Komponenten usw. beinhalten. Einige Beispiele:

    • Ein System, das alle Entitäten mit einer Positions- und einer Transformationskomponente nimmt und auf effiziente und Cache-freundliche Weise alle Positionsmatrizen mit den für den gegebenen Tick/Zeitpunkt erforderlichen Transformationen transformiert. Wenn keine Transformation mehr durchgeführt werden muss (eine Entität wird statisch), wird die Transformationskomponente aus der Entität entfernt und sie wird dann nicht mehr verarbeitet.
    • Ein Eingabesystem hört auf Ereignisse von den Eingaben (Maus/Tastatur/Gamepad/usw.) und wandelt diese in Komponenten um, die den relevanten Entitäten hinzugefügt werden oder andere Aktionen ausführen.
    • Ein Furnace-System (Minecraft-Metapher) nimmt Entitäten, die Inventory, Fuel, RecipeMapping, BlockPos, Cooking und andere Komponenten haben, iteriert über diese Entitäten und aktualisiert die relevanten Zustände nach Bedarf, bis nichts mehr zu kochen ist, und wenn der Brennstoff abgelaufen ist, wird es entfernt die Cooking Flag-Komponente, sodass sie nicht mehr verarbeitet wird, bis das Inventar erneut geändert wird, um beliebige Flag-Komponenten festzulegen.

Intern können Sie sich ein ECS als eine Datenbank vorstellen, in der Sie festgelegte Zuordnungen von Daten abonnieren können, obwohl sie, wenn sie gut gemacht sind, extrem gut optimiert sind. Wenn Sie wissen, welche Systeme vor welchen anderen Systemen laufen sollten und welche Systeme nicht überlappend (abhängig von Lesen oder Lesen/Schreiben) arbeiten, können Sie die Aufrufe auch trivial multithreaden. (Ich verwende weiterhin Amethyst und seinen ECS-spezifischen Bibliotheksteil namens specs als Beispiel, weil ich durch die Portierung meiner alten C++-ECS-Bibliothek an der Erstellung mitgewirkt habe.) Das Spezifikationsbuch enthält viele Details zum „Warum“ von ECS. Wie, Effizienz, Verwendung usw. Amethyst geht noch weiter ins Detail, insbesondere darauf, wie ECS mit den allgemeinen Spielsystemen, Rendering usw. verwendet werden sollten.

Wenn Sie eine gut geschriebene C++-ECS-Bibliothek sehen möchten, dann schauen Sie sich https://github.com/skypjack/entt an, denn von allen C++-ECS-Bibliotheken, die ich gesehen habe und die ich nicht erstellt habe, scheint sie die beste zu sein insgesamt (obwohl die Spezifikationen es in meinen einfachen Tests immer noch übertreffen, wenn auch nicht viel, was beeindruckend ist, wenn man bedenkt, dass die Spezifikationen alles, womit ich es jemals verglichen habe, deutlich übertreffen).

Die allgemeine „Nutzung“ von ECS ist, dass Sie eine „Entität“ haben (nur eine ganze Zahl, keine Daten), und Sie haben den Satz von Tabellen, die Komponenten Entitäten zuordnen, und die Systeme, um tatsächlich Arbeit auszuführen. In GDScript-Pseudocode würde ich mir vorstellen, dass es sich um eine einfache API handelt, allerdings mit einer etwas seltsamen Konvention zur "Integration" in den Godot-Szenenbaum, da der Szenenbaum nicht dafür entworfen wurde.

# All of this would generally be wrapped up in one or more function calls for easy
# building.

# Create a new entity
var e = createEntity()

# Map it to some Components, starting with a godot scenetree component
# I'm using long names to be descriptive, but eh...
var eNode = scenetreeComponentTable.set(e, SomeNodeType())
# Generally things like the transformation matrix and so forth would be their own
# components, but since the godot scenetree already bakes all that in then just
# deal with it all via the node type, you definitely lose a little efficiency doing
# it this way though since nodes involve multiple virtual calls to access and
# the usual ECS patterns entirely get rid of virtual calls with potentially only
# the occasional indirect calls inside a table (maps, etc...)

# 8x4 inventory slots
inventoryComponentTable.set(e, 8, 4)
# 1 fuel slot, accepts items that have the "burn" tag
fuelStorageComponentTable.set(e, 1, "burn")
# Give this entity the furnace component that uses the "basicFurnaceRecipes" recipes
furnaceComponentTable(e, "basicFurnaceRecipes")
# Add other components

# All of the above component mappings could also be in, say, a JSON file, and
# loaded something as such:
componentTables.map(e, "res://entity_types/basicFurnace.json")
# Or maybe via a preloaded JSON object or so

# Once at startup:

# And you could make a system something like, I'll use a GDScript class for this:
val furnaceCookSystemHandler = systems.register(FurnaceCookSystem.new())
furnaceCookSystemHandler.staticTickRate(0.05) # 20 times a second exactly

# Where the `FurnaceCookSystem` could be something like:
class FurnaceCookSystem:
  def _entity_matchers():
    furnaceBurnMatcher =
      componentTables.matcher().
      write(inventoryComponentTable).
      write(fuelStorageComponentTable).
      writeEither(inventoryChangedComponentTable, furnaceCookingComponentTable)
      read(furnaceComponentTable)
    return [furnaceBurnMatcher]

  # Assume we have matching semantics here to destructure a list, I'm lazy...
  def _entities_process([furnaceBurnEntities], delta):
    # This function takes a list of entity sets in the same order as the matchers
    # returned above.
    while entity in furnaceBurnEntities:
      val furnace = furnaceComponentTable[entity] # or .get(entity) or whatever API
      val cooking = furnaceCookingComponentTable[entity]
      if cooking == null or cooking.cookTimeRemaining <= 0:
        if cooking != null:
          if inventoryComponentTable.put(item) == False: # No space, try later
            continue
        # Get next item that has a "burnable" tag, if any
        val item = inventoryComponentTable[entity].getAndRemoveFirstOf("burnable")
        if item == null:
          furnaceCookingComponentTable.remove(entity)
        else:
          cooking = furnaceCookingComponentTable.set(entity, item, furnace.cookTime * getCookTimeModifierOfItem(item))
      else:
        cooking.cookTimeRemaining -= delta

 # ... whatever other functions are useful to the system

# Then of course just with the right components on any entity it will just work
# 'as' a furnace.  You can have a whole variety of 'generic' systems that can be
# mixed and match with impunity.  If you want a random rock that can be a furnace
# then just add the proper components, or if you want an Ent that can both be
# chopped down like a tree for wood but will also attack the player then just add
# the proper components, etc.... etc....

@MysteryGM : Ein Tipp: Signale. Feuer kann ein Signal brennen (Ziel) haben, wobei das Ziel Ihr Holz ist.

Entschuldigung, ich meinte Skripte, keine Instanzen. Ich möchte, dass Skripte interagieren, ohne dass ein Knoten im Godot-Baum erforderlich ist.

Entschuldigung, ich meinte Skripte, keine Instanzen. Ich möchte, dass Skripte interagieren, ohne dass ein Knoten im Godot-Baum erforderlich ist.

Vielleicht verstehe ich Ihr Problem falsch, aber ich bin mir ziemlich sicher, dass Sie dies bereits tun können, indem Sie Klassen in GDScript erstellen. Sie benötigen immer noch ein automatisches Laden oder mindestens ein Skript auf einem Knoten, der als Einstiegspunkt dient.

Hast du es auch schon mit C# probiert? Wenn Sie versuchen, ein komplexes System zu erstellen, bei dem Skripts sowohl interagieren als auch Knoten über etwas anderes als das Anhängen von Skripts an die Knoten anhängen, werden Sie mit C# wahrscheinlich eine viel bessere Zeit haben als mit GDScript für ein solches System.

@MysteryGM Damit Skripte ohne Verwendung eines Knotens in der Szene miteinander interagieren können, müssen Sie mindestens eine geladene Version der Skriptressource erhalten. Die einzige Möglichkeit, dies in 3.0 zu tun, besteht darin, das Skript nach Dateipfad preload / load zu erstellen. 3.1 fügt die Funktion "Skriptklasse" für GDScript und NativeScript hinzu, bei der die den Skripten zugewiesenen Namen global registriert werden. GDScript konvertiert dann diese globalen Registrierungen in der Engine manuell in globale Variablen in der Sprache.

Wenn Sie dann die Ressource Script haben, können Sie statische Methoden im Skript aufrufen oder .new() aufrufen, um ein ScriptInstance zu erhalten, und dann Member-Funktionen aufrufen/auf Member-Variablen zugreifen. Wenn Script ein Objekt, eine Referenz, eine Ressource oder einen anderen Nicht-Knotentyp ableitet, reicht es aus, einfach eine Instanz von Script / ScriptInstance zu erstellen den statischen/nicht statischen Inhalt. Wenn es sich um einen Knoten handelt, gilt dasselbe, mit Ausnahme von Dingen, die SceneTree-Zugriff erfordern (wie get_node ). In diesem Fall müssen Sie ihn zuerst mit add_child zum SceneTree hinzufügen.

All dies gilt für jede Skriptsprache, die mit Godot verwendet wird (obwohl das Vorladen eine Operation ist, die meiner Meinung nach für bestimmte Sprachen spezifisch ist ...).

das Skript nach Dateipfad. 3.1 fügt die Funktion „Skriptklasse“ für GDScript hinzu

Wann wird 3.1 offiziell veröffentlicht?

@MysteryGM Wenn der prozentuale Abschluss des Meilensteins hoch genug ist / wenn die Kernentwickler den Fortschritt als weit genug beurteilt haben, dass sie den Build als "stabil" betrachten.

Meilenstein: https://github.com/godotengine/godot/milestone/7

Zum Vergleich: 2.1 und 3.0 sind derzeit zu 99 % fertiggestellt. Ich bin mir nicht ganz sicher, ob das der Status war, den sie hatten, als sie live gingen.

Im Grunde ist die Antwort "wenn es fertig ist".

Vielen Dank für die Antworten und wir entschuldigen uns dafür, dass wir Ihre Zeit in Anspruch genommen haben.
Es sieht so aus, als ob Godot derzeit nicht zu unseren Bedürfnissen passt. Vielleicht bekommen wir in Zukunft die Chance, den Motor wieder zu verwenden.

Wenn ich möchte, dass Feuer Holz verbrennt, muss ich entweder Holz->erweitern->Feuer oder Feuer->erweitern->Holz haben.

@MysteryGM
Siehe hier .
Die Lösung (unabhängig von Engine oder Sprache) könnte darin bestehen, ein "System"-Skript zu haben, das die Interaktionen zwischen Feuer und Wald steuert. Diese Präsentation konzentriert sich auf Komponenten, aber man kann ein System auch mit Objekten arbeiten lassen.

In C# könnte ich sagen, dass Wood IBurnable #$ implementiert, was Fire verwendet.

Hallo, danke für die anhaltende Sorge und wir sind wirklich dankbar für die Unterstützung von @willnationsdev . Wir glauben, dass die Skripte als Export-Ressourcen-Lösung viel Potenzial haben. Wie in #22660 erwähnt.

Da wir noch 10 Tage Zeit haben, um uns für eine Engine zu entscheiden, haben wir noch etwas mit Godot probiert.
Wir haben uns die Workflow-Probleme angesehen und ich glaube, unser Programmierer hat es am besten ausgedrückt:

"Die Godot-Entwickler halten jedes Issue in Github auf einem eigenen Post, öffnen immer ein Issue für einen Fehler , erlauben aber nicht den gleichen Workflow für ihre Engine."
Die Tatsache, dass wir ein Skript erstellen müssen UND wir gezwungen sind, es der Hierarchie hinzuzufügen.

"System"-Skript, das die Interaktionen zwischen Feuer und Wald steuert. Diese Präsentation konzentriert sich auf Komponenten

Ja, das wollen wir, wie machen wir das in GDscript?

In C# könnte ich sagen, dass das Wood IBurnable implementiert, das Fire verwendet.

Godot hat Duck Typing, um dasselbe zu tun wie Interfaces. Was wir wollen, ist, dass Burning eine separate Klasse ist, damit wir es wiederverwenden können, ohne dass wir gezwungen sind, der Hierarchie einen Knoten hinzuzufügen.

Was wir wollen, ist Feuer, Brennen, Holz. Wir wollen kein Feuer (Holz + Brennen).
Der Vorteil dieses Workflows besteht darin, dass wir Burning eigenständig debuggen können, ohne jedes Objekt, das brennen kann, reparieren zu müssen.

In C# deklarieren wir Burning einfach als eigene Klasse. Public Class Burning und unser Problem ist gelöst.
In C++ würden wir Burning einschließen und das Problem lösen.

Ja, das wollen wir, wie machen wir das in GDscript?

@MysteryGM

Ohne in Leistungsoptimierungen einzutauchen, schlage ich nur vor, die Interaktionsauflösung in ein separates Systemskript zu verschieben (nicht in Feuer, nicht in Holz). Das System kann im einfachsten Fall Arrays aller Objekte in der Welt halten und ihre Interaktionen handhaben. In diesem Fall müssen sich Objekte nicht um Typen kümmern, sondern nur das System.

Um die Dinge schneller zu machen, könnte man nur Prüfungen für Objekte durchführen, die tatsächlich kollidiert sind (zum Beispiel durch Senden eines signal vom Objekt an das System, wenn die Kollision auftritt).

Einige GDScript-spezifische Beispiele für Skript-Querverweise (für Version 3.0):

Hier fungiert Enemy als Typ/Schnittstelle, man kann mit dem Operator is danach suchen:

# Cache the enemy class.
const Enemy = preload("enemy.gd")

# Use 'is' to check inheritance.
if (entity is Enemy):
    entity.apply_damage()

Hier zeigt runnerGame auf eine _autoload_-Szene (alias Singleton) mit dem Pfad /root/runner:

onready var runnerGame = get_node("/root/runner")
onready var runnerScript = preload("res://runner/runner.gd")

func _ready():
    runnerGame.setMode(runnerScript.SPAWN_TITLE)

Hier verbinden wir das signal "Gedrückte" der Schaltfläche mit dem Handler (der sich in einem anderen Objekt und Skript befinden könnte, wir verwenden self , um auf dasselbe zu verweisen):

func _button_pressed(which):
    print("Button was pressed: ", which.get_name())

func _ready():
    for b in get_node("buttons").get_children():
        b.connect("pressed", self, "_button_pressed",[b])

Sehen Sie sich auch die Dokumentation hier an, dort sind einige weitere Funktionen verfügbar: http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/gdscript_basics.html#inheritance

Siehe auch die Dokumentation hier, es sind einige weitere Funktionen verfügbar:

Danke für deinen Beitrag zum Thema. Das Problem bei der Vererbung ist, dass sie nur funktioniert, wenn wir alle Beziehungen von Klassen kennen, wenn wir sie implementieren.

Hier ist ein Beispiel:

Schritt A.
MeshInstance+ HomingScript = HomingMissile .
Aber wenn ich jetzt eine zielsuchende Landmine will, habe ich ein Problem.
(MeshInstance+ ProximityScript) = Landmine .
(MeshInstance+ ProximityScript) + HomingScript = ERROR mehr als ein Skript
(MeshInstance+ ProximityScript) + (childNode + HomingScript ) = FAILED, da sich nur der unsichtbare Knoten bewegt.
(MeshInstance+ ProximityScript) + (childNode + ExtendedHomingScript ) = ERFOLG, da wir jetzt die Homing-Klasse erweitern, sodass sie Knoten vom untergeordneten Knoten besitzen kann. Wir bekommen HomingLandmine .

Außer jetzt kann argumentiert werden, dass sowohl Homing Missile als auch Landmine von einer HomingClass ausgehen sollten.

SchrittB.
HomingMissile[von Homing]
HomingLandmine[von Homing] [+ ProximityScript] Das Skript wird nun kopiert und in die Landmine eingefügt.

Später in der Produktion passiert dasselbe mit anderen Drehbüchern, die wir haben.
SchrittC.
Landmine [aus der Nähe]
ProximityAlarm[von Proximity] [+ AlarmScript]
// HomingLandmine[from Proximity] [+ HommingScript] // Jetzt passt auch unsere Landmine hier rein.

Also müssen wir weiter durch Schritt A gehen, um die richtige Vererbung für Schritt B zu finden. Es wiederholt dieses Muster immer wieder und geht über StepF hinaus usw.

Wir haben einen Weg gefunden, Schritt A zu verlängern. Wir vermeiden einfach das Hinzufügen eines Skripts zum obersten Knoten und machen diesen immer zu einem räumlichen oder einem primären Knoten.
(Spatial + MeshInstance+ ProximityScript) + HomingScript = HomingLandmine
Außer, dass dies genau das gleiche Problem ist, aber mit einem teureren ParentSpatial; anstelle von childNode.

Ich entschuldige mich dafür, wie lange das ist.

@MysteryGM

"Die Godot-Entwickler halten jedes Issue in Github auf einem eigenen Post, öffnen immer ein Issue für einen Fehler , erlauben aber nicht den gleichen Workflow für ihre Engine."
Die Tatsache, dass wir ein Skript erstellen müssen UND wir gezwungen sind, es der Hierarchie hinzuzufügen.
...
Was wir wollen, ist Feuer, Brennen, Holz. Wir wollen kein Feuer (Holz + Brennen).
Der Vorteil dieses Workflows besteht darin, dass wir Burning eigenständig debuggen können, ohne jedes Objekt, das brennen kann, reparieren zu müssen.
...
In C# deklarieren wir Burning einfach als eigene Klasse. Public Class Burning und unser Problem ist gelöst.
In C++ würden wir Burning einschließen und das Problem lösen.

Was Sie verstehen müssen ist, dass Godot in diesem Fall nicht anders funktioniert. Während die beste Lösung darin besteht, einen Unterknoten mit einem eigenen Skript zu erstellen (in diesem Fall für „Brennen“), können Sie Burning einfach als eigene Klasse definieren und es über statische Funktionen einbinden/verwenden (oder es instanziieren und dann Eigenschaften/Methoden verwenden)

  • C++

    • Klasse Brennen {};

    • "burning.h" einschließen;

    • Brennen::anwenden(Holz, Feuer);

    • Brennen *b = Brennen::get_singleton(); b->anwenden (Holz, Feuer);

  • C# (bearbeitet für Stiländerungen)

    • öffentliche Klasse Burning {}

    • mit Game.Burning;

    • Burning.apply (Holz, Feuer);

    • Brennen b = Brennen.Instanz; b.anwenden (Holz, Feuer);

  • GDScript (3.1)

    • erweitert Ressource # Burning.gd

    • const Burning = preload("res://burning.gd")



      • in 3.0 kann ein gemeinsames Skript verwenden, um Konstanten für alle Ihre häufig verwendeten Stimuli zu laden.


        erweitert Referenz


        const Burning = preload("res://burning.gd")


        const Wetting = preload("res://wetting.gd")


        erweitert Referenz


        const Stimuli = preload("res://stimuli.gd")


        # Verwenden Sie Stimuli.Burning oder Stimuli.Wetting


      • in 3.1 können nur Skriptklassen verwenden. Brennen und Benetzen erfordern keine "Einbeziehung", da sie global sind.


        Außerdem könnte man, wenn man der globalen Verwendung ablehnt, "Stimuli" zur Skriptklasse mit den gleichen konstanten Deklarationen machen, damit sie immer als Pseudo-Namensraum verfügbar ist.



    • Burning.apply (Holz, Feuer)

    • var b = Brennen.neu()

      b.anwenden (Holz, Feuer)

Für einen Unity/ScriptableObject-Ansatz kann man Godots Resource-Skripte für den gleichen Zweck verwenden.

  • Einstellungen können im Inspektor konfiguriert werden.
  • "Builds" der Funktion können in einer Datei gespeichert werden, sodass bestimmte Einstellungen bei Bedarf auch zur Laufzeit einfach ausgetauscht werden können.
  • Der Editor erstellt mithilfe der Szenendeklaration automatisch eine Instanz der Ressource auf dem Knoten, sodass keine manuelle Aktualisierung erforderlich ist. Ein Array solcher Ressourcen könnte einigermaßen gut funktionieren, obwohl Sie mit dem in 3.1 (bis hoffentlich 3.2) defekten Array-Typ-Hinweissystem ein EditorInspectorPlugin schreiben müssten, um den Inspector-Inhalt richtig zu generieren (was eigentlich das ist, woran ich arbeite on in der FileSystemItemList meines Godot-Next- Repositorys (Warnung, es ist ein frühes WIP), um in meinem Godot-Builder- Repository für Arrays von Dateien/Verzeichnissen verwendet zu werden.

"System"-Skript, das die Interaktionen zwischen Feuer und Wald steuert. Diese Präsentation konzentriert sich auf Komponenten

Ja, das wollen wir, wie machen wir das in GDscript?

Der einfachste Weg, dies zu tun, ist mit einer Art Autoload-Knoten/Szene. Der Grund dafür ist, dass Sie, selbst wenn Sie nur einen Knoten mit Tonnen von Ressourcen für all die verschiedenen Systeme verwenden (um die Anzahl der verwendeten Knoten zu minimieren), wahrscheinlich immer noch Zugriff auf einen Knoten haben möchten, der sich so im Baum befindet dass Sie Zugriff auf Deltazeit, Eingabedaten, Yield-Operationen (insbesondere kombiniert mit Signalnutzung), Animations-/Tween-/Timer-Knoten erhalten, die Liste geht weiter. Darüber hinaus generiert GDScript als Autoload erneut eine globale Variable für den Knoten, sodass auf die "Systeme" überall in Ihrer Codebasis nach Namen zugegriffen werden kann (in diesem Fall ein weiterer geeigneter Ersatz für die Verwendung einer Skriptklasse).

Ich habe tatsächlich ein großes Refactoring eines alten WIP-Plugins, Godot-Skills , das ich gerne machen würde, das meines Erachtens dies und vieles mehr umfasst. Bitte lesen Sie den (sorry, langen) Reddit-Thread zum Thema. Es beinhaltet die Untersuchung der Durchführbarkeit der Verwendung von koordiniertem Multithreading in einer Serverarchitektur (ähnlich der zugrunde liegenden Architektur von Godot), um ein ähnlich generisches und wiederverwendbares Interaktivitätssystem zu implementieren.

Übrigens, wenn Sie jemals in Echtzeit über das Thema chatten möchten, können Sie mich gerne auf Reddit/Discord/Twitter kontaktieren, wo ich denselben Benutzernamen verwende.

@MysteryGM

MeshInstance+ HomingScript = _HomingMissile_.
Aber wenn ich jetzt eine zielsuchende Landmine will, habe ich ein Problem.
(MeshInstance+ ProximityScript) = _Landmine_.
(MeshInstance+ ProximityScript) + HomingScript = ERROR mehr als ein Skript
(MeshInstance+ ProximityScript) + (childNode + HomingScript ) = FAILED, da sich nur der unsichtbare Knoten bewegt.
(MeshInstance+ ProximityScript) + (childNode + ExtendedHomingScript ) = ERFOLG, da wir jetzt die Homing-Klasse erweitern, sodass sie Knoten vom untergeordneten Knoten besitzen kann. Wir bekommen _HomingLandmine_.

Außer jetzt kann argumentiert werden, dass sowohl Homing Missile als auch Landmine von einer HomingClass ausgehen sollten.

Ich glaube, ich vermisse hier etwas. Afaik, der richtige Weg, einen "Komponentenverhalten" -Knoten zu erstellen, ist einer, der sich nicht selbst ändert, sondern direkt einen "Ziel" -Knoten modifiziert, bei dem das Standardziel das übergeordnete Element ist. Dies umgeht das Problem, auf das Sie stoßen, vollständig, wenn ich mich nicht irre.

extends Node
var src_target
export(NodePath) onready var dst_target = get_node(dst_target) if dst_target else null
func _notification(p_what):
    match p_what:
        NOTIFICATION_PARENTED:
           src_target = get_parent()
        NOTIFICATION_UNPARENTED:
           src_target = null
func _physics_process():
    # if necessary, can manually assign src_target elsewhere to be NOT a parent
    if src_target and src_target is KinematicBody2D:
        src_target.move_and_slide(...) # do logic to get parameters that move towards dst_target

So etwas würde bedeuten, dass Sie nichts ändern müssen, indem Sie einfach einen Knoten mit dem Skript zu einem untergeordneten Element des Objekts machen, für das Sie die "Homing" -Funktion haben möchten. Sie müssen nur den exportierten Eigenschaftswert (entweder in der Szene oder zur Laufzeit) zuweisen, um ihm mitzuteilen, wohin es gehen soll. Andere exportierte Eigenschaften können verwendet werden, um die Art der Bewegung zu ändern, und dieses Zeug könnte auch in eine Ressource ausgelagert werden, wenn Sie andere "Builds" haben möchten. Auch hier ermöglicht Ihnen Godot, beim Design Ihres Spiel-Frameworks sehr flexibel zu sein.

Einige Korrekturen:

 - C#
-   - public class Burning {};
+   - public class Burning {}
    - using Game.Burning;
    - Burning.apply(wood, fire); // is it :: here? I forget...
-   - Burning b = Burning::GetSingleton(); b.apply(wood, fire);
+   - Burning b = Burning.GetSingleton(); b.apply(wood, fire);

Ein Semikolon nach den schließenden Klammern der Klasse ist nicht erforderlich. Sie verwenden einen Punkt für statische Mitglieder anstelle von :: .
Als Nebenbemerkung besteht die Konvention für den Zugriff auf ein Singleton darin, eine Eigenschaft (im Allgemeinen mit dem Namen Instance ) anstelle einer Methode zu verwenden.

@neikeq Danke. Ich bin viel zu aus der Übung mit C#, lol.

Was den „Global Scripts“-Ansatz angeht, bin ich sehr dagegen. Es würde Entwickler ermutigen, ihr Spiel auf schlechte Weise zu programmieren. Eine häufige Frage früherer Spieleentwickler für reines C++ und Java, wenn sie Unity/Unreal/Godot/etc ausprobieren, lautet: „Wo ist die Hauptspielschleife, in die ich meinen Code schreiben kann?“. Das Hinzufügen eines solchen Systems würde es diesen Entwicklern ermöglichen, dies zu tun, sodass sie möglicherweise Code in globalen Skripten schreiben, die auf die Objekte verweisen, die sie ändern möchten, anstatt nur ein Skript auf ein Objekt anzuwenden.

Vielleicht könnten wir stattdessen die Leistung des Node Barebones-Knotens verbessern, so dass er keinen Overhead für Objekt-"Komponenten" einführt, die nur Skripte enthalten. Oder vielleicht sogar ein separater einfacher "only-holds-scripts"-Knoten.

@aronfranke

Was den „Global Scripts“-Ansatz angeht, bin ich sehr dagegen. Es würde Entwickler ermutigen, ihr Spiel auf schlechte Weise zu programmieren. Eine häufige Frage früherer Spieleentwickler für reines C++ und Java, wenn sie Unity/Unreal/Godot/etc ausprobieren, lautet: „Wo ist die Hauptspielschleife, in die ich meinen Code schreiben kann?“.

Wie ich bereits erwähnt habe, wenn jemand dagegen ist (vernünftigerweise in einem großen Projekt), dann gibt es kein Problem damit, einfach eine globale Skriptklasse "Namespace" zu erstellen, die Konstanten anderer Skripts verwaltet, um sich weiter nach unten in der API-Hierarchie zu bewegen. Wir sprechen hier nur von Skripten, nicht von tatsächlichen Knotenreferenzen.

Das Hinzufügen eines solchen Systems würde es diesen Entwicklern ermöglichen, dies zu tun, sodass sie möglicherweise Code in globalen Skripten schreiben, die auf die Objekte verweisen, die sie ändern möchten, anstatt nur ein Skript auf ein Objekt anzuwenden.

Dieses System kann bereits von jedem in Godot über Autoloads implementiert werden (es wird kein "Hinzufügen" einer Funktion vorgeschlagen). Darüber hinaus besteht das Problem, auf das sie überhaupt stoßen, darin, dass sie die Systeme selbst nicht als Unterknoten in der Welt hinzufügen möchten (obwohl ich im Folgekommentar auch einen Vorschlag dafür mache), da sie dies getan haben sowohl den Knoten dort als auch das Skript auf diesem Knoten zu haben und möglicherweise die Beziehungen zwischen allen Knoten und Skripten umzugestalten, wenn sie später erkennen, dass Dinge verschoben werden müssen.

Vielleicht könnten wir stattdessen die Leistung von Barebones Node node verbessern, so dass es keinen Overhead für Objekt-"Komponenten" einführt, die nur Skripte enthalten.

Inwiefern? Der einzige Weg, dies transparent zu machen, wäre die Implementierung eines MultiScript-Systems, und es gibt eine ganze Reihe von Problemen, die mit diesem Paradigma einhergehen. Die einzige andere Alternative, die mir einfiel, als ich versuchte, dieses Problem zu lösen , war das GDScript-Trait-System, das ich in #23101 vorgeschlagen hatte, das die MultiScript-Probleme auf eine Sprache beschränkt, aber mit einer Reihe noch schwerwiegenderer Probleme einhergeht.

Oder vielleicht sogar ein separater einfacher "only-holds-scripts"-Knoten.

Sobald wir das Hinweissystem für Array-Typen in 3.2 repariert haben, können wir dies mit nur ...

extends Node
export(Array, Script) behaviors = []

Man könnte die Funktion jetzt sogar mit einem Wörterbuch (um auf die Skripte nach Namen zuzugreifen) und einem EditorInspectorPlugin aus 3.1 implementieren, um eine benutzerdefinierte Benutzeroberfläche zu definieren, wenn diese Knoten im Inspektor geöffnet werden (erstellen Sie eine Benutzeroberfläche mit einem exportierten Array von Skripts, aber haben es fügt das Skript mit einem Schlüssel hinzu, der dem Dateinamen unter der Haube entspricht).

erweitert Ressource # Burning.gd

Ah, ich glaube, ich habe unser Problem gefunden. Keiner unserer Preload-Versuche erstreckte sich von der Ressource. Ich glaube, keiner von uns wusste überhaupt, dass wir benutzerdefinierte Ressourcen erstellen können.

Ich möchte auch darauf hinweisen, dass niemand, der seine Spiele mit uns geteilt oder seinen Arbeitsablauf beschrieben hat, von der Ressource ausgeht.
Fast jeder erweiterte Node. Keine Ahnung, wie viel Unterschied das macht, müssen Tests durchgeführt werden.

FileSystemItemList (Warnung, es ist ein frühes WIP)

Das muss man sich unbedingt mal anschauen.

@MysteryGM

Ich glaube, keiner von uns wusste überhaupt, dass wir benutzerdefinierte Ressourcen erstellen können.

Jawohl! Ich habe erst kürzlich einen Abschnitt zu den Dokumenten hinzugefügt, der den Prozess umreißt. :-D

Sie können JEDEN Engine-Typ mit einem Skript erweitern, einschließlich Object, Reference, Resource und natürlich Node (oder einer beliebigen Ableitung dieser Klassen). Die einzigen Dinge, die nicht erweitert werden können, sind Engine- und Editor-Singletons (wie OS, Engine oder EditorFileSystem).

Danke für deinen Beitrag zum Thema. Das Problem bei der Vererbung ist, dass sie nur funktioniert, wenn wir alle Beziehungen von Klassen kennen, wenn wir sie implementieren.

Gern geschehen. Ich habe die Vererbung am Ende des Kommentars eingefügt, da sie für die Implementierung des Brennholzsystems nicht erforderlich ist.
Es scheint, dass Sie bereits eine Lösung im Sinn haben, indem Sie Paradigmen verwenden, an die Sie gewöhnt sind, und Ihr Problem ist nicht, wie Sie ein Brennholzsystem erstellen, sondern wie Sie die bevorzugten Paradigmen verwenden.
Ich entschuldige mich dann. Ich bin mit der GDScript-Vererbung nicht vertraut, aber ich glaube, andere haben Ihre Frage bereits beantwortet.

OK, wir hatten einige Zeit, um die neue Methode zu testen und fanden, dass sie perfekt funktioniert. Wir konnten bereits Hunderte von Knoten durch Skripte ersetzen; Leistung stark verbessern.

In Anbetracht dessen, dass das Vorladen von Ressourcen das Problem des Einschließens von Skripten löst. Kann auch als Alternative zu MultiScript und ScriptableObject von Unity verwendet werden, indem eine Ressourcenvariable in GDscript exportiert wird.
Kombiniert mit der Tatsache, dass die Dokumente aktualisiert wurden, um die Ressourcen detaillierter zu erläutern.
Ganz zu schweigen davon, dass Godot 3.1 auch über Skriptklassen verfügen wird, die noch mehr Workflows ermöglichen sollen.

Ich denke, das ursprüngliche Ziel dieses Problems wurde gelöst, und dieses Problem kann jetzt geschlossen werden?

Nochmals möchte ich mich bei allen für die Teilnahme an der Diskussion bedanken, und insbesondere bei @willnationsdev , der einen enormen Einblick in die Godot-Engine gegeben hat.

@MysteryGM Ich denke, Ihre Gedanken am Anfang dieses Threads und am Ende dieses Threads könnten gut in einem Blog oder einem Godot-Docs-Entwurf niedergeschrieben werden. Ich denke, die meisten frühen Benutzer machen oft Leistungsfehler, wenn sie versuchen, eine komplexe Skriptorganisation zu erreichen. Wir brauchen gute Beschreibungen von „vorher“ und „nachher“ in Bezug auf das Lernen. Die Lektionen und Muster, die wir in frühen Tutorials lernen, lassen sich nicht gut auf groß angelegte Spiele übertragen, was für mich nur bedeutet, dass wir mehr Blogs / Ratschläge zu groß angelegten Lektionen brauchen.

@pgruenbacher , das ist eine tolle Idee. Damit gibt es für unser Team zwei Probleme: Zum einen können nur zwei von uns Englisch auf einem brauchbaren Niveau, und zum anderen wird es viel Zeit in Anspruch nehmen.

Trotzdem gibt es eine gute Änderung, dass wir einen Entwicklungsblog erstellen und uns Notizen über alles machen, was wir entdecken. Es ist möglich, dass wir einen „Übergang zu Godot“-Blogeintrag machen.

Im Moment arbeite ich an einigen „Godot-Schnellkurs für Künstler“-PDF-Tutorials, weil wir Freiberufler für das Team einstellen wollen, aber Godot noch nicht sehr bekannt ist.
Diese Tutorials zielen darauf ab, Godot professionellen Spielekünstlern vorzustellen.
Sobald ich diese erledigt habe, werde ich sie mit den anderen Godot-Benutzern teilen, ich werde sie zunächst als PDF behalten, weil es einfacher ist, Fehler zu korrigieren, während ich noch lerne.

@pgruenbacher @MysteryGM Auch wenn ich nicht in der gleichen Art wie eine Vorher/Nachher-Erfahrung mit Godot war, haben mich diese Ausgabe und einige damit verbundene wiederkehrende Fragen dazu veranlasst, mit der Arbeit an einem Best-Practices-Artikel für Szenen-/Drehbuchdesign für Godot-Docs zu beginnen. Ich habe einen Zweig auf meiner Gabel, aber es ist sehr früh WIP atm.

Das Lesen von Themen wie diesem ist äußerst entmutigend (in dem Sinne, dass ich eine zweite Vermutung anstellen muss, ob wir den richtigen Motor gewählt haben). Unser Projekt hat weit über 15.000 LoC und ist perfekt organisiert und läuft super. (Ich werde nicht auf bestimmte Punkte eingehen, weil andere Leute hier viel klüger sind als ich).
Vor diesem Hintergrund bin ich froh, dass Sie bei Godot bleiben, MysteryGM! Ich freue mich darauf, den Dev-Blog zu lesen

Meh meiner Meinung nach sind Spiele mit signifikanter Logik besser dran mit dem Code
sowieso von der Spiel-Engine isoliert, also sollte es eigentlich egal sein, wie
der Motor funktioniert. Mein Node-Scripting wird hauptsächlich für das Rendern von Schnittstellen verwendet
und physikalische Logik. Die Spiellogik ist eine gemeinsam genutzte Bibliothek, die separat zusammengestellt wird

Am Mittwoch, den 14. November 2018, Aaron-Fleisher [email protected]
schrieb:

Das Lesen von Themen wie diesem ist äußerst entmutigend (im Sinne von
damit ich noch einmal überprüfe, ob wir den richtigen Motor wählen). Unser Projekt ist gut
über 15.000 LoC und perfekt organisiert und läuft super. (Ich werde nicht gehen
in Details von bestimmten Punkten, weil andere Leute hier viel schlauer sind
als ich).
Vor diesem Hintergrund bin ich froh, dass Sie bei Godot bleiben, MysteryGM! Auf jeden Fall suchen
Ich freue mich darauf, den Dev-Blog zu lesen


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/godotengine/godot/issues/23052#issuecomment-438871197 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ADLZ9pw2-G0kE19meyi7iSkceAldfAMjks5uvLb4gaJpZM4XelSe
.

@Aaron-Fleisher

... lässt mich zweifeln, ob wir den richtigen Motor gewählt haben

Wenn die Engine, die Sie jetzt verwenden, für Sie funktioniert, gibt es keinen Grund, sich zu ärgern, auch wenn Sie einige Workarounds durchführen müssen. Einige Spieler (oder andere Entwickler) stellen möglicherweise Ihre Fähigkeiten/Ihren Verstand in Frage, aber das ist nur die Realität der Spieleentwicklung. Viele leidenschaftliche Menschen sprechen mit scheinbarer Autorität (oft weit über ihrem tatsächlichen Können).

Sie sind derjenige, der Ihre Probleme kennt, und Sie sind derjenige, der die Arbeit machen muss. Lassen Sie sich nicht von dem lähmen, was Ihnen vielleicht weitere 10-20 % Produktivität eingebracht hätte. Speichern Sie es für das nächste Spiel. Oder tun Sie es nicht, da Sie bereits eine Menge in das Erlernen der Tools investiert haben, die Sie bereits kennen. Deine Entscheidung :)

Ich weiß nicht, ich habe irgendwie das Gefühl, dass die Godot-Entwickler nicht wissen, was sie tun.

Bei der ersten Verwendung von Godot 3.0.6 stable wird mir ein hässlicher, dysfunktionaler „Projektmanager“ präsentiert. Wenn ich überhaupt herausfinden kann, wie es funktioniert (und es ist überhaupt nicht intuitiv), stürzt die App jedes Mal ab, wenn ich versuche, ein Beispielprogramm aus der Asset-Bibliothek herunterzuladen. Manchmal reagiert die App einfach nicht mehr. Manchmal gibt die App mysteriöse „condition !connected is true“-Fehler aus. Manchmal stockt der Download. Und jedes Mal dauert das Herunterladen einer 100-MB-Datei ungefähr 10 Minuten, während ich 10 GB an anderer Stelle in der gleichen Zeit herunterladen kann. „Wiederholen“ startet den gesamten Download von vorne.

Ich habe das Gefühl, dass "stabil" hier bedeutet "wird jedes Mal zuverlässig vermasseln".

Sprechen Sie über einen überwältigenden ersten Eindruck.

@dejayc Das ist seltsam. Ich selbst hatte noch nie Probleme mit dem Project Manager (mit 3.0.6 stable oder sogar dem Master-Zweig) unter Windows 10 oder meinem Linux-Mint-Gerät. Ich würde empfehlen, dass Sie hier eine neue Ausgabe zu Ihren Problemen erstellen (da dies nicht wirklich die richtige Ausgabe für ein solches Thema ist), und hoffentlich kann jemand bessere Hilfe anbieten.

@dejayc
Wenn wir alle an Patreon spenden, könnte das Godot-Projekt den Usability-Experten in Vollzeit einstellen.

Obwohl ich Ihnen in einigen Punkten zustimme, sollten Engines auf der Grundlage von Marketingposts in sozialen Medien ausgewählt werden, wie kritisch ihre Nachteile für das jeweilige Projekt sind. Und leider haben alle _viele_ Nachteile, die tiefer gehen als die Oberfläche der Benutzeroberfläche ...

Abgesehen davon habe ich eine Vorschlagsausgabe zum Projektmanager eröffnet, da ich in etwas Freizeit an einigen Verbesserungen in diesem Bereich arbeiten werde.

Ich habe sowohl mit Unity als auch mit Godot gearbeitet und fand den allgemeinen Arbeitsablauf und die Struktur in Godot viel besser und intuitiver (insbesondere das Szenenmodell anstelle von Szene/Prefab von Unity, das "Single-Script"-Modell anstelle der mehreren Komponenten, die Geschwindigkeit beim Herunterladen/Starten der Engine und beim Exportieren und die Möglichkeit, vollständig offline zu arbeiten).

Es gibt viele mögliche Workflows und Modelle in beiden und es ist nie einfach zu wissen, welches das bessere für Sie ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen