Godot: Bessere benutzerdefinierte EditorPlugin-Knoten

Erstellt am 7. Aug. 2016  ·  121Kommentare  ·  Quelle: godotengine/godot

Knoten, die von der Funktion add_custom_type im EditorPlugin erstellt wurden, wird beim Hinzufügen das ausgewählte Skript zugewiesen. Dies macht sie fast nutzlos, da Sie nur die in diesem Skript definierten Funktionen in anderen Knoten verwenden können.

Dies ist völlig anders als bei anderen Nodes und macht Node-Addons ziemlich nutzlos / viel lästiger in der Verwendung.

feature proposal plugin usability

Hilfreichster Kommentar

So wie ich es verstehe, besteht die Erwartung darin, die Möglichkeit zu haben, benutzerdefinierte Knoten zu erstellen, die sich wie integrierte Knoten verhalten, dh sie sollten die folgenden Funktionen haben:

  • Benutzerdefiniertes Symbol, benutzerdefinierte Kennung
  • Instanziierbar über das Add-Node-Widget (und ich denke, per Skript, also dem Global Scope ausgesetzt?)
  • Haben Sie eine benutzerdefinierte API, die über ein Skript codiert ist (z. B. würde RedNode2D Node2D erweitern und eine rote Modulation haben, die über ein benutzerdefiniertes Skript definiert wird)
  • Dann sollte sich dieser benutzerdefinierte Knoten wie ein integrierter Knoten verhalten, d. h. der Benutzer sollte in der Lage sein, ihn ohne Skript zu instanziieren (die benutzerdefinierte API würde dem Benutzer nicht direkt ausgesetzt, genau wie bei einem integrierten Skript, wo es fest codiert ist). in C++) und hängen Sie ein Skript daran an, das den benutzerdefinierten Knoten erweitert (z. B. extends RedNode2D ).

Das wäre die "natürliche" Erwartung beim Deklarieren eines benutzerdefinierten Knotens und eine sehr mächtige Funktion; Ich entnehme dem Obigen, dass es bisher nicht so funktioniert, teilweise aufgrund von Designentscheidungen. Wenn es eine Möglichkeit gibt, eine Funktionalität wie die oben beschriebene zu haben, bin ich mir ziemlich sicher, dass es viele Anwendungen geben würde. Die Assetlib wäre voll von benutzerdefinierten Knoten, die eine Menge Arbeit sofort erledigen und verwendet werden können, als wären sie eingebaut.

Wiedereröffnung, bis ein Konsens darüber besteht, was getan werden kann/sollte oder nicht.

Alle 121 Kommentare

Ich verstehe nicht, was du meinst

@reduz Wenn Sie der Szene einen Knoten hinzufügen, dessen Typ von einem Plugin erstellt wurde, ist das Plugin-Skript bereits angehängt. Daher ist es unmöglich, ein weiteres Skript mit benutzerdefiniertem Verhalten hinzuzufügen.

Natürlich nicht, das ist Kerndesign und wird sich nicht ändern.

Am 7. August 2016 um 18:11 Uhr schrieb „George Marques“ [email protected] :

@reduz https://github.com/reduz Wenn Sie der Szene einen Knoten hinzufügen, der a
-Typ, der von einem Plug-in erstellt wurde, ist das Plug-in-Skript bereits angehängt. So
Es ist unmöglich, ein weiteres Skript mit benutzerdefiniertem Verhalten hinzuzufügen.


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/6067#issuecomment -238108767,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z29F5q8PaoBv4OrzAUayzrfNjfHyZks5qdkoUgaJpZM4JejbZ
.

Das ist traurig. Sie können das Skript jedoch jederzeit dem übergeordneten oder einem untergeordneten Skript hinzufügen.

Schließen als wontfix.

Ich verstehe vielleicht etwas falsch, aber wenn Ihr benutzerdefinierter Typ ein Skript ist,
Wie wird es nicht in den erstellten Knoten aufgenommen? Es macht keinen Sinn für
es anders sein

Am 7. August 2016 um 21:52 Uhr schrieb „George Marques“ [email protected] :

Das ist traurig. Sie können das Skript jedoch jederzeit dem übergeordneten oder einem untergeordneten Skript hinzufügen.

Schließen als wontfix.


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/6067#issuecomment -238120392,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z27Zo4Ixvo4APSC4Fxf5ZqCJRsAxXks5qdn3igaJpZM4JejbZ
.

Ich denke, es würde die Fähigkeit benötigen, zwei (oder mehr) Skripte pro Knoten zu haben, obwohl dies wirklich nicht viel Sinn macht.

Godot hat dies ursprünglich unterstützt, aber es war mehr Ärger als Vorteil

Am 7. August 2016 um 22:36 Uhr schrieb „George Marques“ [email protected] :

Ich denke, es würde die Fähigkeit benötigen, zwei (oder mehr) Skripte pro zu haben
Knoten, obwohl dies wirklich nicht viel Sinn macht.


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/6067#issuecomment -238123729,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z27jidVZl-hHWW3G_ESr8Cqj3eX7Eks5qdogRgaJpZM4JejbZ
.

Das Problem ist, dass benutzerdefinierte Knoten so gut wie nutzlos sind, da sie nicht wirklich "benutzerdefinierte Knoten" sind, sondern nur Basisknoten mit einem voreingestellten Skript und einem anderen Symbol.
Was ich von "benutzerdefinierten Knoten" erwartet habe, ist, dass ich den Knoten erweitern könnte, um alles zu verwenden, was im Skript definiert ist. Beispielszenario:
Ich habe einen benutzerdefinierten Knoten namens Test, der ein Kind von Sprite ist und eine Funktion test() hinzufügt, die true #$ zurückgibt. Dann möchte ich einen neuen Testknoten erstellen, ihm ein Skript zuweisen und die Funktion test() verwenden.
Das ist unmöglich.

Ich denke, zurück zu der Szene, um die Combo dann zu erben + Skript zu erweitern.

Nun, ein voreingestellter Knoten mit einem voreingestellten Skript und einem anderen Symbol zu sein, ist meiner Meinung nach
genug benutzerdefinierte, aber wenn Sie wirklich Ihren eigenen benutzerdefinierten Code einfügen möchten
Dort können Sie immer die mit dem Knoten gelieferten erben. Wir könnten
Machen Sie dies etwas einfacher über die Benutzeroberfläche, wenn dies wirklich gewünscht wird.

Am Montag, 8. August 2016 um 10:40 Uhr, Dominik Banaszak [email protected]
schrieb:

Das Problem ist, dass benutzerdefinierte Knoten so gut wie nutzlos sind, da sie es nicht wirklich sind
"benutzerdefinierte Knoten", sie sind nur Basisknoten mit einem voreingestellten Skript und anders
Symbol. Ich denke, zurück zu der Szene, um die Combo dann zu erben + Skript zu erweitern.


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/6067#issuecomment -238240130,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z27eHoXwgr6buF6CCAHfxwx1dKkCiks5qdzHhgaJpZM4JejbZ
.

Ich würde es lieben, wenn es durch die Benutzeroberfläche automatisiert/erleichtert werden könnte.

So wie ich es verstehe, besteht die Erwartung darin, die Möglichkeit zu haben, benutzerdefinierte Knoten zu erstellen, die sich wie integrierte Knoten verhalten, dh sie sollten die folgenden Funktionen haben:

  • Benutzerdefiniertes Symbol, benutzerdefinierte Kennung
  • Instanziierbar über das Add-Node-Widget (und ich denke, per Skript, also dem Global Scope ausgesetzt?)
  • Haben Sie eine benutzerdefinierte API, die über ein Skript codiert ist (z. B. würde RedNode2D Node2D erweitern und eine rote Modulation haben, die über ein benutzerdefiniertes Skript definiert wird)
  • Dann sollte sich dieser benutzerdefinierte Knoten wie ein integrierter Knoten verhalten, d. h. der Benutzer sollte in der Lage sein, ihn ohne Skript zu instanziieren (die benutzerdefinierte API würde dem Benutzer nicht direkt ausgesetzt, genau wie bei einem integrierten Skript, wo es fest codiert ist). in C++) und hängen Sie ein Skript daran an, das den benutzerdefinierten Knoten erweitert (z. B. extends RedNode2D ).

Das wäre die "natürliche" Erwartung beim Deklarieren eines benutzerdefinierten Knotens und eine sehr mächtige Funktion; Ich entnehme dem Obigen, dass es bisher nicht so funktioniert, teilweise aufgrund von Designentscheidungen. Wenn es eine Möglichkeit gibt, eine Funktionalität wie die oben beschriebene zu haben, bin ich mir ziemlich sicher, dass es viele Anwendungen geben würde. Die Assetlib wäre voll von benutzerdefinierten Knoten, die eine Menge Arbeit sofort erledigen und verwendet werden können, als wären sie eingebaut.

Wiedereröffnung, bis ein Konsens darüber besteht, was getan werden kann/sollte oder nicht.

+1
Dies war eine der ersten großen Hürden für mich, als ich versuchte, ein bestehendes Projekt von „OtherEngine(tm)“ auf Godot zu portieren. Benutzerdefinierte Typen, wie @akien-mga oben erklärt, sollten sich nach der Registrierung einfach wie jeder andere eingebaute Typ verhalten.

Bitte erläutern Sie, in welcher Weise Sie glauben, dass dies nicht der Fall ist

Am 8. August 2016 um 11:50 Uhr schrieb "Ralf Hölzemer" [email protected] :

+1
Dies war eine der ersten großen Hürden für mich, als ich versuchte, eine zu portieren
bestehendes Projekt von "OtherEngine(tm)" zu Godot. Benutzerdefinierte Typen, wie
@akien-mga https://github.com/akien-mga oben erklärt, sollte nur
verhalten sich nach der Registrierung wie jeder andere eingebaute Typ.


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/6067#issuecomment -238261603,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z25PJzv9w7iXO350tRF3FcEuYQYUKks5qd0IrgaJpZM4JejbZ
.

Wie bereits zuvor erwähnt, besteht der größte Nachteil im Moment darin, dass benutzerdefinierte Typen kaum mehr sind als eine schnelle Möglichkeit, den Basistyp dieses Skripts zu instanziieren und dieser Instanz das entsprechende Skript zuzuweisen. Dies macht es unmöglich, diesen Knoten im Editor mit einem anderen Skript zu erweitern - wie Sie es mit eingebauten Typen tun können.

Aber es ist auch unmöglich, Vererbungsbäume mit benutzerdefinierten Knoten in den Dialogen "Neuen Knoten/Ressource erstellen" zu erstellen, da sie nur in diesen Bäumen auftauchen, wenn Sie sie mit einem eingebauten Typ als Eltern über add_custom_type registrieren.

Nehmen wir beispielsweise an, ich möchte alle meine benutzerdefinierten Typen in meinem Projekt von einem einzigen Basistyp erben.

base.gd

extends Node
export (Color) var color

type_a.gd

extends base.gd

type_b.gd

extends base.gd

So wie es jetzt ist, muss ich diese Typen so registrieren. In diesem Fall muss das zweite Argument von add_custom_type "Node" sein, sonst werden sie nicht in den Dialogen angezeigt.

func _enter_tree():
    add_custom_type("Base", "Node", preload("base.gd"), preload("base.png"))
    add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
    add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... und das ist das Ergebnis.

add_node_flat

Obwohl es schön ist, benutzerdefinierte Typen auf diese Weise registrieren zu können, spiegeln die Dialogfelder nicht die Art der Vererbung dieser Typen wie andere eingebaute Typen wider. Für jeden eingebauten Typ kann ich mir diesen Baum ansehen und auf einen Blick sehen, womit ich es zu tun habe. Ich kann zum Beispiel sicher sein, dass Sprite ein Node2D ist und somit alle von Node2D bereitgestellten Funktionen erbt. Dasselbe gilt nicht für benutzerdefinierte Typen.

Wenn jetzt benutzerdefinierte Typen vollständig im globalen Bereich registriert werden könnten, wie das oben erwähnte @akien-mga, wären die Dinge viel einfacher zu verstehen und zu verwenden.

Erstens könnten Sie von einem benutzerdefinierten Typ erben, auf den durch den Typnamen anstelle des Dateipfads/Namens verwiesen wird.

base.gd

extends Node
export (Color) var color

type_a.gd

extends Base

type_b.gd

extends Base

... dann könnte die Registrierung der benutzerdefinierten Typen so vereinfacht werden. Beachten Sie den fehlenden zweiten Parameter von add_custom_type.

func _enter_tree():
    add_custom_type("Base", preload("base.gd"), preload("base.png"))
    add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
    add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... und Sie würden eine viel schönere Übersicht in den "Create new Node/Resource"-Dialogen erhalten:

add_node_tree

... und natürlich die Möglichkeit, diese Typen im Editor mit einem benutzerdefinierten Skript zu erweitern:

custom_type_no_script

... die auch über den Typnamen anstelle des Skriptnamens/-pfads referenziert würden

extends Base

Hier ist das Beispiel-Plugin von oben, um herumzuspielen.
addons.zip

Oh, ich verstehe ... diese beiden Dinge sollten definitiv zusammen mit repariert werden können
Hinzufügen von Vererbungsunterstützung zum Skripterstellungsdialog

Am 8. August 2016 um 13:54 Uhr schrieb "Ralf Hölzemer" [email protected] :

Wie bereits gesagt, ist das derzeit der _größte Nachteil_
benutzerdefinierte Typen sind kaum mehr als eine schnelle Möglichkeit, den Basistyp zu instanziieren
dieses Skripts und weisen Sie dieser Instanz das entsprechende Skript zu. Dies
macht das Erweitern dieses Knotens im Editor mit einem anderen Skript unmöglich -
wie Sie es mit eingebauten Typen tun können.

Aber es ist auch unmöglich, Vererbungsbäume mit benutzerdefinierten Knoten zu erstellen
die Dialoge "Neuen Knoten/Ressource erstellen", da sie nur in diesen angezeigt werden
Bäume, wenn Sie sie mit einem eingebauten Typ als Eltern via registrieren
add_custom_type.

Nehmen wir zum Beispiel an, ich möchte alle meine benutzerdefinierten Typen in my erben
Projekt von einem einzigen Basistyp.

_base.gd http://base.gd_

erweitert Knoten
export (Farbe) var color

_type_a.gd http://type_a.gd_

erweitert base.gd

_type_b.gd http://type_b.gd_

erweitert base.gd

So wie es jetzt ist, muss ich diese Typen so registrieren. In diesem
Fall muss das zweite Argument von add_custom_type "Node" sein, andernfalls
Sie werden nicht in den Dialogen angezeigt.

func _enter_tree():
add_custom_type("Basis", "Knoten", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... und das ist das Ergebnis.

[Bild: add_node_flat]
https://cloud.githubusercontent.com/assets/8785013/17486294/9bcc029c-5d90-11e6-81e6-6fce6b0e7cf0.png

Es ist zwar schön, benutzerdefinierte Typen wie diesen registrieren zu können, aber die
Dialoge spiegeln nicht die Art der Vererbung dieser Typen wie z
andere eingebaute Typen. Für jeden eingebauten Typ kann ich mir diesen Baum ansehen und
sehen Sie auf einen Blick, womit ich es zu tun habe. Da kann ich mir zum Beispiel sicher sein
Sprite _ist ein_ Node2D und erbt daher alle bereitgestellten Funktionen
von_Node2D. Dasselbe gilt nicht für benutzerdefinierte Typen.

Wenn nun benutzerdefinierte Typen vollständig im globalen Geltungsbereich registriert werden könnten, wie z
@akien-mga https://github.com/akien-mga oben erwähnt, würden die Dinge
viel einfacher zu verstehen und zu verwenden.

Erstens könnten Sie von einem benutzerdefinierten Typ erben, auf den von _type name_ verwiesen wird.
anstelle des Dateipfads/-namens.

_base.gd http://base.gd_

erweitert Knoten
export (Farbe) var color

_type_a.gd http://type_a.gd_

verlängert Basis

_type_b.gd http://type_b.gd_

verlängert Basis

... dann könnte die Registrierung der benutzerdefinierten Typen vereinfacht werden
Dies. Beachten Sie den fehlenden zweiten Parameter von add_custom_type.

func _enter_tree():
add_custom_type("Basis", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... und Sie würden eine viel schönere Übersicht im "Neu erstellen" erhalten
Knoten/Ressource"-Dialoge:

[Bild: add_node_tree]
https://cloud.githubusercontent.com/assets/8785013/17487264/619f4da0-5d94-11e6-880f-a00791e30125.png

... und natürlich die Möglichkeit, diese Typen im Editor um a zu erweitern
benutzerdefiniertes Skript:

[Bild: custom_type_no_script]
https://cloud.githubusercontent.com/assets/8785013/17487807/b54aced2-5d96-11e6-90e5-ee838b6a1335.png

... die auch von _type name_ anstelle des Skripts referenziert würden
Name/Pfad

verlängert Basis

Hier ist das Beispiel-Plugin von oben, um herumzuspielen.
addons.zip https://github.com/godotengine/godot/files/407291/addons.zip


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/6067#issuecomment -238299152,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

Was niemals passieren wird, sind Skripte, die von den instanzierten Knoten verschwinden, oder
ausgeblendet ist, muss klargestellt werden, dass der Knoten geskriptet ist, aber
Wenn Sie ein Skript hinzufügen, können Sie das Skript immer noch durch ein solches ersetzen
erbt davon

Am 8. August 2016 um 14:02 Uhr schrieb „Juan Linietsky“ [email protected] :

Oh, ich verstehe ... diese beiden Dinge sollten definitiv zusammen mit repariert werden können
Hinzufügen von Vererbungsunterstützung zum Skripterstellungsdialog

Am 8. August 2016 um 13:54 Uhr schrieb "Ralf Hölzemer" [email protected] :

Wie bereits gesagt, ist das derzeit der _größte Nachteil_
benutzerdefinierte Typen sind kaum mehr als eine schnelle Möglichkeit, den Basistyp zu instanziieren
dieses Skripts und weisen Sie dieser Instanz das entsprechende Skript zu. Dies
macht das Erweitern dieses Knotens im Editor mit einem anderen Skript unmöglich -
wie Sie es mit eingebauten Typen tun können.

Aber es ist auch unmöglich, Vererbungsbäume mit benutzerdefinierten Knoten zu erstellen
die Dialoge "Neuen Knoten/Ressource erstellen", da sie nur in diesen angezeigt werden
Bäume, wenn Sie sie mit einem eingebauten Typ als Eltern via registrieren
add_custom_type.

Nehmen wir zum Beispiel an, ich möchte alle meine benutzerdefinierten Typen in my erben
Projekt von einem einzigen Basistyp.

_base.gd http://base.gd_

erweitert Knoten
export (Farbe) var color

_type_a.gd http://type_a.gd_

erweitert base.gd

_type_b.gd http://type_b.gd_

erweitert base.gd

So wie es jetzt ist, muss ich diese Typen so registrieren. In diesem
Fall muss das zweite Argument von add_custom_type "Node" sein, andernfalls
Sie werden nicht in den Dialogen angezeigt.

func _enter_tree():
add_custom_type("Basis", "Knoten", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", "Node", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", "Node", preload("type_b.gd"), preload("type_b.png"))

... und das ist das Ergebnis.

[Bild: add_node_flat]
https://cloud.githubusercontent.com/assets/8785013/17486294/9bcc029c-5d90-11e6-81e6-6fce6b0e7cf0.png

Es ist zwar schön, benutzerdefinierte Typen wie diesen registrieren zu können, aber die
Dialoge spiegeln nicht die Art der Vererbung dieser Typen wie z
andere eingebaute Typen. Für jeden eingebauten Typ kann ich mir diesen Baum ansehen und
sehen Sie auf einen Blick, womit ich es zu tun habe. Da kann ich mir zum Beispiel sicher sein
Sprite _ist ein_ Node2D und erbt daher alle bereitgestellten Funktionen
von_Node2D. Dasselbe gilt nicht für benutzerdefinierte Typen.

Wenn jetzt benutzerdefinierte Typen vollständig im globalen Geltungsbereich registriert werden könnten,
wie @akien-mga https://github.com/akien-mga oben erwähnt, Dinge
wäre viel einfacher zu verstehen und zu verwenden.

Erstens könnten Sie von einem benutzerdefinierten Typ erben, auf den von _type name_ verwiesen wird.
anstelle des Dateipfads/-namens.

_base.gd http://base.gd_

erweitert Knoten
export (Farbe) var color

_type_a.gd http://type_a.gd_

verlängert Basis

_type_b.gd http://type_b.gd_

verlängert Basis

... dann könnte die Registrierung der benutzerdefinierten Typen vereinfacht werden
Dies. Beachten Sie den fehlenden zweiten Parameter von add_custom_type.

func _enter_tree():
add_custom_type("Basis", preload("base.gd"), preload("base.png"))
add_custom_type("TypeA", preload("type_a.gd"), preload("type_a.png"))
add_custom_type("TypeB", preload("type_b.gd"), preload("type_b.png"))

... und Sie würden eine viel schönere Übersicht im "Neu erstellen" erhalten
Knoten/Ressource"-Dialoge:

[Bild: add_node_tree]
https://cloud.githubusercontent.com/assets/8785013/17487264/619f4da0-5d94-11e6-880f-a00791e30125.png

... und natürlich die Möglichkeit, diese Typen im Editor um a zu erweitern
benutzerdefiniertes Skript:

[Bild: custom_type_no_script]
https://cloud.githubusercontent.com/assets/8785013/17487807/b54aced2-5d96-11e6-90e5-ee838b6a1335.png

... die auch von _type name_ anstelle des Skripts referenziert würden
Name/Pfad

verlängert Basis

Hier ist das Beispiel-Plugin von oben, um herumzuspielen.
addons.zip https://github.com/godotengine/godot/files/407291/addons.zip


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/6067#issuecomment -238299152,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

@reduz
Gibt es einen technischen Grund, um klarzustellen, dass der Knoten geskriptet ist, und wenn ja, muss es sich um einen belegten Skript-Slot handeln?

Es scheint mir eine ziemlich ungeschickte Art, einen benutzerdefinierten Typ anzugeben, und ich denke, niemand würde auf die Idee kommen, dass Sie durch das Ersetzen des aktuellen Skripts auf einem Knoten ein Skript erhalten, das das bereits vorhandene Skript erweitert. So funktioniert das Erweitern per Skript einfach nicht für die Basistypen.

Und was würde passieren, wenn der Benutzer dieses Skriptfeld löscht? Wird der benutzerdefinierte Typ auf das vorherige Skript oder vollständig auf den Basistyp zurückgesetzt? Nochmal, ich glaube nicht, dass das eine gute Idee wäre.

Stattdessen könnte es einfach als benutzerdefinierter Typ im Node-Baum oder im Eigenschaften-Editor über eine andere Farbe, ein Symbol oder etwas anderes angezeigt werden, ohne den leeren Skript-Slot zu opfern.

Was niemals passieren wird, sind Skripte, die von den instanziierten Knoten verschwinden oder ausgeblendet werden. Es muss klargestellt werden, dass der Knoten ein Skript ist, aber das Hinzufügen eines Skripts zu ihm wird es immer noch ermöglichen, das Skript durch eines zu ersetzen, das von ihm erbt

Der Punkt hier ist, dass das Skript, das den benutzerdefinierten Knoten definiert, versteckt werden _sollte_, da es keine Eigenschaft des _instanzierten_ Knotens ist, sondern seines Typs. Daher sollte dieses Skript dem benutzerdefinierten Knoten Eigenschaften verleihen, aber es sollte für den Benutzer des instanzierten Knotens genauso unsichtbar sein wie die C++-Klassen der integrierten Knoten. Es würde eine API bereitstellen, wäre aber nicht modifizierbar, sondern nur erweiterbar. So wie beim Instanziieren eines Sprites scenes/2d/sprite.cpp nicht als Skript des instanzierten Knotens angehängt wird, sollte my_custom_node.gd nicht als änderbares Skript des benutzerdefinierten Knotens der Instanz angehängt werden.

Nun, ich weiß nicht, ob es im Moment technisch _möglich_ ist, aber es wäre der natürliche Anwendungsfall AFAIU. Wenn Sie das Skript des benutzerdefinierten Typs ändern, würde dies den Typ selbst ändern und sich somit auf alle Instanzen dieses Typs auswirken. Aber die instanzierten Knoten, die den benutzerdefinierten Typ verwenden, sollten ihr eigenes Skript haben, das extends CustomNode .

Ich denke, dass diese Funktion Objekt benötigen würde, um einen zusätzlichen Zeiger auf den "benutzerdefinierten Basisskripttyp" zu haben, da Sie diese Informationen benötigen, wenn Sie ein Benutzerskript daraus entfernen möchten (das es eigentlich durch das Basisskript ersetzen sollte).
Sobald Sie das haben, ist der Rest eine Frage der Einbeziehung in alle Fälle, da es zahlreiche Nebenwirkungen haben kann. Am Ende wird nur ein Skript angehängt, nur eine andere Art, damit umzugehen.
Ich bin generell kein großer Fan von Vererbung, aber so würde ich es machen.

Eigentlich könnte dieser Zeiger nicht einmal benötigt werden. Das Markieren des Skripts würde ausreichen. Wenn Sie beispielsweise add_custom_type() mit einem Skript hinzufügen, kann die Engine ein Flag für die Klasse setzen, damit die Informationen verfügbar sind, z. B. "Hey, diese Skriptklasse ist eine Engine-Typerweiterung". Das Entfernen eines Benutzerskripts würde es dann durch die erste geerbte Skriptklasse ersetzen, die als "benutzerdefinierter Typ" gekennzeichnet ist, oder es entfernen, wenn es keine gibt.

Entschuldigung, ich bin dagegen, ein Skript zu verstecken, wenn der Knoten ein Skript hat. Was ist das
Sinn, etwas zu simulieren, das es nicht ist?

Die Tatsache, dass es ein Skript hat, bedeutet nicht, dass der Steckplatz beschäftigt ist oder dass ein benötigt wird
zweites Skript, weil Sie einfach ein neues Skript erstellen können, das das erbt
bestehende.

Was wir tun können, wenn Sie damit einverstanden sind, ist das Skriptsymbol im Szenenbaum auszublenden, wenn
Das zugewiesene Skript ist das aus dem benutzerdefinierten Typ, und erstellen Sie das Skript
create dialog bietet Ihnen automatisch an, bei der Skripterstellung zu erben.
Würde das reichen?

Am 10. August 2016 um 23:01 Uhr schrieb „Marc“ [email protected] :

Eigentlich könnte dieser Zeiger nicht einmal benötigt werden. Markieren des Skripts würde
ausreichen, wenn Sie beispielsweise mit einem Skript die Engine add_custom_type() hinzufügen
kann ein Flag für die Klasse setzen, damit die Informationen verfügbar sind, als "Hey, das
Skriptklasse ist eine Engine-Typ-Erweiterung". Das Entfernen eines Benutzerskripts würde
Ersetzen Sie es dann durch die erste geerbte Skriptklasse, die als "custom
type", oder entfernen Sie es, wenn es keine gibt.


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/6067#issuecomment -239055986,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z2xLGOhgMk__ZoRW1neRu1aRb5Qr_ks5qeoJogaJpZM4JejbZ
.

@reduz ich denke das wäre gut genug :smile:

@reduz Ich stimme zu, und ich habe nicht gesagt, dass wir ein zweites Skript brauchen. Ich habe mich nur gefragt, was passieren würde, wenn Sie ein Skript hinzufügen, das das erste erbt (das vom Plugin definierte Benutzerdefiniert), sich dann aber entscheiden, es zu entfernen. Es würde dann den Knoten ohne Skript auf einen Basis-Engine-Typ zurücksetzen?

Ich nehme an, wir könnten es in dieser Hinsicht irgendwie benutzerfreundlicher machen

Am 11. August 2016 um 06:10 Uhr schrieb „Marc“ [email protected] :

@reduz https://github.com/reduz Ich stimme zu, und ich habe nicht gesagt, dass wir eine brauchen
zweites Skript. Ich habe mich nur gefragt, was passieren würde, wenn Sie ein Skript hinzufügen
das erste erben (das benutzerdefinierte, das durch das Plugin definiert wird), sich dann aber dafür entscheiden
entfernen Sie es. Es würde dann den Knoten auf einen Basis-Engine-Typ ohne irgendwelche zurücksetzen
Skript dann?


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/6067#issuecomment -239109334,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z26JUJ0gjaCFwlsIDsINWp3_nqliwks5qeubygaJpZM4JejbZ
.

Ich grabe den Teil der Erweiterungen durch den knotendefinierten Typ anstelle des in diesem Kommentar beschriebenen Pfads https://github.com/godotengine/godot/issues/6067#issuecomment -238299152.

Einige weitere Vorschläge zum Hinzufügen:

  • node.get_type() auf einem Addon-Typ sollte den Typnamen zurückgeben.

Beispiel:

add_custom_type("MyCustomNode", "Node2D", preload("my_custom_node.gd"), preload("icon.png"))

node.get_type() should return "MyCustomNode" instead of "Node2D"
  • Ein Plugin könnte ein anderes Plugin um seinen Typ erweitern

Beispiel:
Benutzer A erstellt ein Plugin für einen präziseren Sichtbarkeitsmelder auf Basis von Node2D
add_custom_type("PreciseNotifier", "Node2D", preload("precise_notifier.gd"), preload("icon.png"))

Dann entwickelt Benutzer B ein Trigger-Addon basierend auf dem genauen Notifier in einem ANDEREN Addon-Ordner mit einer anderen Konfiguration.
add_custom_type("Trigger", "PreciseNotifier", preload("trigger.gd"), preload("icon.png"))
und im trigger.gd-Skript sollte er es auch um den Typnamen erweitern
extends PreciseAddon
Natürlich sollte der Benutzer beide Addons hinzufügen, um das Trigger-Addon zu verwenden

Es scheint, als ob eine Gruppe einen benutzerdefinierten Knotentyp ohne Skript als einen definieren möchte, der immer noch von dem benutzerdefinierten Knotentyp abgeleitet ist, auf dem er basiert, während die andere Gruppe dasselbe Szenario als einen Knoten definieren möchte, der zu seiner Basis zurückgekehrt ist. Motortyp. Während ich zur ersteren Gruppe gehöre, kann ich auch den Standpunkt der letzteren Gruppe in Bezug auf den benutzerdefinierten Typ verstehen, der immer noch „skriptiert“ ist, und möchte dies in der Benutzeroberfläche deutlich machen.

Ein Kompromiss könnte dann darin bestehen, eine zusätzliche UI-Schaltfläche in der Zeile des Knotens im Szenenbaum-Dock neben seinem Skriptsymbol mit einer Art Skript++-Symbol zu haben. Wenn Sie darauf klicken, wird das typische Popup-Fenster "Skript erstellen" mit einem Skript angezeigt, das bereits vom benutzerdefinierten Typ erbt, z. B. extends Base oder extends "Base" . Das definierte Skript würde dann erstellt und würde sofort das voreingestellte Skript ersetzen. Sie würden also immer noch deutlich zeigen, dass es ein bereits vorhandenes Skript auf dem Knoten gibt, aber Sie hätten auch eine vertraute Oberfläche, um dieses voreingestellte Skript einfach zu ersetzen.

Dieser Vorschlag wäre wahrscheinlich weniger intuitiv, da er benutzerdefinierte Knoten immer noch etwas anders behandelt als ihre Gegenstücke in der Engine. Die Gedanken?

Ich gebe meine 2 Cent viel später zu dieser Diskussion, ich denke, das Problem liegt in der Tatsache, dass mehrere Knoten, die ein Addon erben, standardmäßig dasselbe ursprüngliche Skript teilen; Ich habe nichts dagegen, dass die Sichtbarkeit des Codes, wie Juan ganz am Anfang dieses Threads argumentierte, eine Designentscheidung ist und auch etwas Wichtiges, um das Knotenverhalten für den Entwickler, der das Addon verwendet, transparent zu machen. Normalerweise möchten Sie jedoch das Verhalten verschiedener Knoten im Code ändern, und im Moment besteht die einzige Möglichkeit darin, die ursprüngliche Skriptreferenz zu entfernen, ein neues Skript zu erstellen und den Basisskriptcode zu kopieren und einzufügen. Sie können nicht einmal das Skript des neuen Addon-Knotens save as in eine neue .gd-Datei umwandeln, da dies die Referenz auf alle anderen Knoten ändert, die das ursprüngliche Skript verwenden, also gibt es dieses dreistufige Kopieren und Einfügen Prozedur Eigenart.

Dann ist es nicht SO kompliziert, nur dass sich in diesem speziellen Fall die Option save as im GDScript-Editor nicht so verhält, wie ich es erwarten würde, und ich denke, es wäre benutzerfreundlicher, ein ' Copy and Save'-Schaltfläche im GDScript-Editor, um eine schnelle Anpassung von Addons zu ermöglichen (und in Bezug auf die Architektur ist es sinnvoll, diese Schaltfläche sichtbar zu machen, da dies ein guter Ansatz zum Erstellen von Spielen auf Godot ist, ohne dass geerbte Skripte verwendet werden müssen).

@henriquelalves Ich dachte, das Anpassen benutzerdefinierter Knoten im Code ist im Grunde Vererbung? Wie extends "addons/thing/thing.gd" ? Das geerbte Skript wird immer noch die gleichen Dinge tun wie die Addon-Version, vorausgesetzt, Sie wissen, was Sie überschreiben. Kopieren/Einfügen ist nicht erforderlich.

@Zylann Du hast Recht, aber normalerweise mag ich diesen speziellen Ansatz wegen der Code-Sichtbarkeit und der Eigenheiten der automatischen Vervollständigung nicht (zumindest auf 2.1, ich habe es noch nicht getestet). Und meistens möchte ich keine Methoden überschreiben, sondern nur bestimmte Dinge ändern, die keine erweiterten Variablen im ursprünglichen Addon-Skript sind. Das ist es, was mich am aktuellen save as -Verhalten stört, ich kann nicht schnell die Kopie eines Skripts erstellen, ohne jeden Knotenverweis auf ein solches Skript zu ändern; und dies auf eine UI-freundliche Weise zu lösen, löst das ursprüngliche Problem, mehrere Knoten zum Anpassen zu haben, plus Code-Sichtbarkeit und dergleichen (zumindest in meinem Workflow kann ich der einzige sein, der so denkt, haha).

@henriquelalves Nun, ich kann das Kopieren/Einfügen nicht ausstehen xD Und Sie könnten das Plugin auch mit der Versionierungskontrolle forken und es stattdessen verwenden.

@Zylann Das Forken eines Plugins fügt noch mehr Schritte zu etwas hinzu, das kinderleicht sein sollte, hahaha. Ich denke, ich bleibe beim manuellen Kopieren und Einfügen, wenn dies keine Priorität hat, obwohl ich das Verhalten save as immer noch seltsam finde.

@henriquelalves Kopieren/Einfügen IS Forking^^, aber wenn es ohne Versionskontrolle gemacht wird, wird es Sie in Zukunft in den Rücken beißen, wenn das Plugin aktualisiert wird.

Das aktuelle Verhalten, ein Skript an den benutzerdefinierten Knoten anzuhängen, bietet fast keinen Vorteil, wenn dieser benutzerdefinierte Knoten als Add-On verwendet wird, anstatt das Skript einfach an den Knoten anzuhängen. Der einzige Vorteil ist, dass es im Knotendialog angezeigt wird, was überhaupt kein Vorteil ist.

Ich bin in dem Lager, das sagt, dass sich ein benutzerdefinierter Knoten wie ein erstklassiger eingebauter Typ verhalten sollte. Warum sollte man sich sonst die Mühe machen, ein Addon dafür zu erstellen/zu verwenden? Nur damit Sie es im Dialogfeld sehen können und nicht auf die Schaltfläche Skript hinzufügen klicken müssen?

@RodeoMcCabe Das Problem ist, dass benutzerdefinierte Typen unter der Haube immer noch Skripte sind, die in der Praxis auf einem In-Engine-Knoten liegen, und das kann nicht geändert werden, da benutzerdefinierte Typknoten nicht direkt in die Engine-Quelle kompiliert werden. Was wir tun müssen, ist eine konkrete Reihe von Schritten/Funktionen zu formulieren, die es diesen gescripteten Knoten ermöglichen würden, in den Augen des Benutzers das Verhalten eines In-Engine-Knotens zu simulieren . Beispielsweise...

  1. Hinzufügen des Knotens zum Fenster "Knoten erstellen" (erledigt)
  2. Dem Benutzer erlauben, eine textuelle „kurze Beschreibung“ des Knotens für das Fenster „Knoten erstellen“ bereitzustellen (scheint nicht getan zu werden? - zumindest ist es nicht Teil von add_custom_type ).
  3. Ermöglicht dem Benutzer, Knotenhierarchien anzuzeigen und abstrakte benutzerdefinierte Typen im Fenster "Knoten erstellen" zu definieren. Dies würde wahrscheinlich das Hinzufügen eines Bool zur add_custom_type -Funktion beinhalten, um festzustellen, ob es sich um einen abstrakten Typ handelt oder nicht. Der Assistent zum Erstellen eines Knotens müsste aktualisiert werden, um die Erstellung abstrakter benutzerdefinierter Typen entsprechend zu blockieren.
  4. Lassen Sie den Knoten so aussehen, als hätte er KEIN Skript.

    A. Der Knoten sollte kein „Skript befindet sich auf diesem Knoten“-Symbol im Szenen-Dock haben. Um die Dinge transparenter zu machen, sollte es vielleicht stattdessen ein Symbol "Dies ist ein Knoten vom benutzerdefinierten Typ" geben. Durch Klicken darauf könnte der Benutzer dann direkt zu dem benutzerdefinierten hinzugefügten Skript gelangen. Es unterbricht die "Immersion", aber es wäre aus Gründen der Benutzerfreundlichkeit ein notwendiges Opfer (natürlich möchten Sie sehen und sehen können, wie ein benutzerdefinierter Typknoten funktioniert, wenn Sie möchten).

    B. Die im Inspektor angezeigte Skripteigenschaft sollte standardmäßig leer sein, es sei denn, der Benutzer lädt ein Skript darauf, in diesem Fall muss das Skript von dem Skripttyp abgeleitet werden, der als benutzerdefinierter Typ verwendet wird. Der Benutzer sollte jedoch nicht wissen müssen, wo sich die Skriptdatei des benutzerdefinierten Typs befindet (das Konzept, dass es sich um ein Skript handelt, sollte ihm verborgen bleiben). Das bedeutet, dass entweder der Stringname für die benutzerdefinierte Klasse vom GDScript-Parser wie die anderen In-Engine-Klassen erkannt werden sollte (nicht sicher, wie einfach/schwer das wäre) oder dass es eine Art globale Funktion geben sollte, um den Datensatz abzurufen B. für das Skript in add_custom_type("MyClass", "Node", load(res://addons/git-repo/api/my_class.gd), load(res://addons/git-repo/icons/icon_myclass.svg) , könnte der Benutzer ein Skript mit extends MyClass oder extends custom("MyClass") .

    C. Wenn ein Benutzer ein vom benutzerdefinierten Typ abgeleitetes Skript auf den Knoten lädt, sollte nur dann das Symbol „Dieser Knoten hat ein Skript“ im Szenen-Dock angezeigt werden.

  5. Welches Editor-Symbol auch immer für das Skript verwendet wird, sollte dem Kategorieblock hinzugefügt werden, anstelle des White-Box-ähnlichen Symbols, das derzeit für Skripte verwendet wird (in property_editor.cpp ). Dies sollte Teil der Eigenschaft __meta__ Dictionary für das Knotenobjekt des benutzerdefinierten Typs sein.

  6. Wenn Sie bei einem benutzerdefinierten Typ auf „Skript hinzufügen“ klicken, sollte das Feld „Übernimmt“ mit der in 4b verwendeten Methode vorab ausgefüllt werden.
  7. Wenn Sie ein Skript entfernen, sollte das benutzerdefinierte Typskript immer noch unter der Haube vorhanden sein und NICHT entfernt werden. Die Knoten des benutzerdefinierten Typs würden das Skript des benutzerdefinierten Typs effektiv als Backup-Skript in Fällen verwenden, in denen das geladene Skript auf null gesetzt ist. Daher sollten Sie immer noch das Editor-Symbol und die Skripteigenschaften der Basistypen im Szenen-Dock und im Inspektor-Dock des Editors sehen. Ich bin bereits dabei, eine Funktion zusammenzuführen, um "Skriptvariablen" durch die Namen der tatsächlichen Skripts zu ersetzen, obwohl es wahrscheinlich aktualisiert werden müsste, wenn all diese Änderungen hinzugefügt werden.
  8. Object::get_script() sollte null für Knoten mit einem benutzerdefinierten Typskript und keinem geladenen Skript zurückgeben.
  9. Object::get_property_list , und die analogen Funktionen für Methoden und Signale sollten den Inhalt des benutzerdefinierten Typskripts enthalten, auch wenn kein Skript geladen ist.
  10. Es würde wahrscheinlich eine zweite C++-Objektfunktion wie Object::get_custom_script() oder so etwas benötigen, damit die Engine sehen kann, ob es ein Skript gibt, selbst wenn die Skriptseite dieses zweite Skript nicht kennt.
  11. Versuche, ein nicht vom benutzerdefinierten Typ abgeleitetes Skript auf ein Objekt zu laden, sollten sauber fehlschlagen und einen Fehler melden (wahrscheinlich eine boolsche &is_valid -Referenz in der zugehörigen Funktion), um zu bestätigen, ob das Objekt dazu berechtigt ist. Die zugehörigen Godot-Editor-Szenarien, die Feedback zu diesen Informationen liefern müssen, müssten ebenfalls aktualisiert werden, um dies zu berücksichtigen.

Dies kratzt nur an der Oberfläche, aber ich denke, die Art von Verhalten, nach der die Benutzer suchen, ist ungefähr so ​​umfangreich (also ziemlich intensiv). Wir möchten das Vorhandensein von benutzerdefinierten Typen bei Bedarf zugänglich machen (also das Symbol für benutzerdefinierte Typen im Szenendock in der Zeile des Knotens haben, um sein Skript anzuzeigen), aber wir möchten auch ihre Existenz so weit wie möglich verbergen, damit wir sie wahrnehmen können sie als innermotorische Typen. Es wird eine Menge Arbeit erfordern, es wirklich richtig zu machen, da es wahrscheinlich an VIELEN Stellen Dinge kaputt machen wird.

Klingt irgendetwas davon gut? Ich bin mir sicher, dass es noch mehr Dinge gibt, die ich vermisse, da ich nur ein bisschen darüber nachdenke. Wenn das verrückt klingt, dann lass es mich einfach wissen. ;-)

Bearbeiten: Ah, aber der Vorschlag von reduz, das Skriptsymbol einfach im Szenendock auszublenden, wenn das Skript mit dem benutzerdefinierten Typskript übereinstimmt, könnte ebenfalls wertvoll sein. Nur die Methode get_script() sollte immer noch nichts zurückgeben. Vielleicht gibt es eine Möglichkeit, dies zu tun, ohne eine separate Skripteigenschaft für das Objekt selbst erstellen zu müssen? Idk, denn es gibt bereits viele Annahmen in der Codebasis für 1 Skript pro Objekt, die wir meiner Meinung nach beibehalten möchten, die aber mit dem custom_type -Skriptkonzept schwer zu pflegen sind.

Gute Vorschläge, gut durchdacht. Ich denke, wenn all dies implementiert wäre, würde es das gewünschte Verhalten geben, aber ich denke, dass das Brechen der 1-Skript-pro-Knoten-Regel schlechte Nachrichten sein könnte, die sich durch viele unerwartete Teile des Codes ausbreiten könnten. Nehmen Sie das mit einem Körnchen Salz, da ich die Codebasis nicht so gut kenne und mein C++ mittelmäßig ist. Reduz hat oben angegeben, dass sie ursprünglich versucht haben, mehr als ein Skript pro Knoten zu haben, und "es war mehr Mühe, als es sich gelohnt hat", was für mich vernünftig klingt.

Die Punkte 1 bis 4 sind großartig und meiner Meinung nach erreichbar, ohne die 1-Skript-Regel zu brechen. Abstrakte benutzerdefinierte Typen sind offensichtlich kein Problem, da Sie sie sowieso nicht instanziieren können und der Benutzer daher im Editor kein Skript hinzufügen kann. Es ist jedoch denkbar, dass sie versuchen, dies über Code zu tun, sodass die erforderlichen Überprüfungen und Fehler eingerichtet werden müssten.

Punkt 6 ist auch gut, und hier denke ich, können wir damit durchkommen. Das Erstellen eines neuen Skripts gemäß Punkt 6 ändert das Skript, das derzeit an den benutzerdefinierten Knoten angehängt ist, in das neue (abgeleitete) Skript. Das alte (Basis-)Skript wird aus dem Knoten entfernt. Da das neu angehängte Skript vom Original abgeleitet ist, bleibt die gesamte Funktionalität erhalten. Ich mache das oft, wo ich eine Basisklasse habe (abstrakt oder nicht) und abgeleitete Skripte an Knoten anhänge. Der Unterschied besteht hier darin, dass das neue Skript möglicherweise extends "res://addons/path/to/base-script.gd" anstelle des Namens des benutzerdefinierten Knotens sagen muss, da der benutzerdefinierte Typ dieses Skript nicht mehr angehängt hat .... Obwohl bei näherem Nachdenken remove_custom_type() wurde nicht aufgerufen, und das angehängte Skript stammt immer noch vom alten, also ist das vielleicht nicht nötig? Bitte klären Sie mich in diesem Punkt auf.

Die Punkte 7, 8 und 9 sind gut und wahrscheinlich nicht zu schwer, während die 1-Skript-Regel eingehalten wird. 10 ist nicht notwendig, wenn wir die 1-Skript-Regel beibehalten. 11 ist gut, da sich eingebaute Knoten so verhalten, wenn Sie versuchen, ihnen ein Skript anzuhängen, das den Knotentyp nicht erweitert.

Auf jeden Fall hört es sich nach viel Arbeit an, und wir befinden uns bereits in der Beta-Phase, also denke ich, dass dies für 3.1 oder sogar 3.2 sein wird (habe in letzter Zeit nicht auf die Roadmap geschaut).

@RodeoMcCabe Ja, das wäre definitiv nicht für 3.0.

Das Brechen der 1-Skript-pro-Knoten-Regel könnte eine schlechte Nachricht sein, die sich in vielen unerwarteten Teilen des Codes widerspiegeln könnte

Genau meine Gedanken. Ich denke an eine öffentliche Schnittstelle, in der das Objekt sein benutzerdefiniertes Sicherungsskript kennt, andere Objekte jedoch nichts davon wissen und das Objekt einfach so wahrnehmen, als hätte es ein einzelnes Skript. Der Trick wäre, den Setter und Getter für die script-Eigenschaft zu bearbeiten. Der Getter sollte auf null prüfen. Wenn es null ist, sollte es stattdessen das Sicherungsskript zurückgeben. Der Einrichter sollte ebenfalls überprüfen, ob jedes neue Skript das Backup-Skript erweitert, andernfalls sollte es irgendwie einen Fehler melden.

Abstrakte benutzerdefinierte Typen sind offensichtlich kein Problem, da Sie sie sowieso nicht instanziieren können und der Benutzer daher im Editor kein Skript hinzufügen kann.

Es gibt keine abstrakten Typen auf der Skriptseite (afaik). Willst du damit sagen, dass du weißt, wie man ein Skript abstrakt macht? Die can_instance Methode ist der Skripting-Seite ausgesetzt, überprüft jedoch lediglich, ob das Skript selbst gültig ist und, falls es sich um ein Tool handelt, ob der ScriptServer im Moment Skripting aktiviert hat. Das hat nichts mit der Abstraktheit des Schrifttyps zu tun, glaube ich nicht.

Sie müssen prüfen können, ob die Klasse abstrakt ist, damit die CreateDialog::_update_search Methode weiß, wann der Text ausgegraut/unwählbar usw. werden soll.

Zu Ihrer Information, ich habe ein Problem über den abstrakten Teil des Problems erstellt (#13401).

Ich denke, insgesamt wäre es machbar, wenn wir nur ein privates backup_script -Mitglied zum Typ Object hinzufügen und dieses dann verwenden würden, um die script -Eigenschaftsprüfungen durchzuführen.

Was ich auf meinen benutzerdefinierten Knoten mache, ist, ein Basisskript zu erben, das das benutzerdefinierte Knotenskript standardmäßig leer macht ...


Die automatische Vererbung wirkt sich auf das Plugin selbst aus und es ist nicht möglich, mehr als eines zu erstellen, ohne das Plugin zu duplizieren, oder?

Multiscript wurde dieses Jahr zum zweiten Mal hinzugefügt und war leicht wieder zu beenden (wirft mehrere Probleme auf).


Das Zulassen einer Szene als Basis für den benutzerdefinierten Knoten anstelle eines Skripts kann dazu führen, dass der Stamm frei von Skripten ist.

Was ich auf meinen benutzerdefinierten Knoten mache, ist, ein Basisskript zu erben, das das benutzerdefinierte Knotenskript standardmäßig leer macht ...

Entschuldigung, wollen Sie damit sagen, dass dies irgendwie die Abstraktheit beeinflusst, oder einen anderen Vorschlag, den ich zuvor gemacht habe? Ich sehe nicht, wo das zusammenhängt ...

Die automatische Vererbung wirkt sich auf das Plugin selbst aus und es ist nicht möglich, mehr als eines zu erstellen, ohne das Plugin zu duplizieren, richtig?

Wollen Sie sagen, dass der Versuch, das Plugin zweimal in den Ordner /addons/ einzufügen und beides im Plugin-Bereich der Projekteinstellungen zu aktivieren, irgendwie zu Problemen führen würde (ich meine, das klingt ziemlich normal, wenn Ihr Plugin benutzerdefinierte Es dürfen nicht mehrere benutzerdefinierte Typen mit demselben Namen definiert sein).

Ich bin mir nicht sicher, was Sie mit "es wird nicht möglich sein, mehr als eines zu erstellen, ohne das Plugin zu duplizieren" meinen. Sie können problemlos mehrere Instanzen eines benutzerdefinierten Typknotens erstellen (?), da nur der Knoten erstellt und das definierte benutzerdefinierte Typskript automatisch angehängt wird. Mein Vorschlag würde beinhalten, den Skripterstellungsprozess von CreateDialog zu ändern, um ...

  1. Lassen Sie das eingebaute Skript des Knotens entscheiden, ob der Knoten instanziiert werden kann oder nicht (abstrakt).
  2. Erstellen Sie einen integrierten Knotentyp.
  3. Legen Sie benutzerdefiniertes Skript als backup_script -Eigenschaft des Knotens fest (nicht für die Skripting-API verfügbar).
  4. Lassen Sie den eigenen Object -Code des Knotens die Aufgabe übernehmen, alle anderen dazu zu bringen, backup_script als die offizielle script -Eigenschaft des Objekts anzusehen.
  5. Aktualisieren Sie die Metadaten für das Editor-Symbol
  6. Aktualisieren Sie die Metadaten für die Kurzbeschreibung (?)

...anstatt...

  1. Erstellen Sie den integrierten Knoten.
  2. Hängen Sie das benutzerdefinierte Typskript als Eigenschaft script an.
  3. Aktualisieren Sie die Metadaten für das Symbol des benutzerdefinierten Editors.

Multiscript wurde dieses Jahr zum zweiten Mal hinzugefügt und war leicht wieder zu beenden (wirft mehrere Probleme auf).

Ich stimme zu. Ich denke, das Multiskripting von Objekten wäre an dieser Stelle eine schlechte Idee (und wird sowieso nicht einmal wirklich benötigt). Das ist nicht das, was ich vorschlage. In der Öffentlichkeit sollte Object immer noch nur 1 Skript haben, aber ich empfehle, ein Backup-Skript zur Verfügung zu haben, das die Rolle des Skripts übernimmt (also sich selbst der Eigenschaft script zuweist). immer dann, wenn die Haupteigenschaft script auf null / entladen usw. gesetzt ist. Dadurch können wir "benutzerdefinierte Typen" effektiver unterstützen, ohne die Schnittstelle der Codebasis zur Objektklasse zu ändern. Wir können dann einfach einen dedizierten Setter/Getter für diese Sicherungsskripteigenschaft haben, der es Code (wie dem Code, der benutzerdefinierte Typskripte in CreateDialog zuweist) erlaubt, seine Existenz hinzuzufügen oder zu entfernen. Auf diese Weise handelt es sich um eine Opt-in-Änderung der Funktionsweise der script -Eigenschaft, die zu vergleichsweise weniger notwendigen Änderungen an der Engine führt.

Ich denke, eine neue Option für das Kontextmenü auf Knoten würde dieses Problem lösen. "Skript durch geerbt ersetzen". Dies könnte sogar ein Untermenü mit allen erkannten Skripten haben, die vom aktuellen erben, und am Ende ein "Neues Skript", wenn Sie darauf klicken das neue Skript Der Dialog sollte den Pfad des Skripts im Feld "Erweitert" anzeigen.

Ist es nicht einfach einfacher und transparenter, einfach ein Editor-Tool zum Ersetzen und Vererben von Skripten hinzuzufügen? Ich meine, das ist nur ein Problem, denn wenn wir einen Addon-Knoten erstellen, erwarten wir, dass er skriptlos ist – aber Addon-Knoten sind wirklich nur angepasste Knoten, die Sie dem Create Node-Baum hinzufügen, und der Benutzer sollte das wissen. Aus der UX-Perspektive (ich bin allerdings kein Experte) denke ich nicht, dass wir Transparenz der Bequemlichkeit opfern sollten.

@MarianoGnu @henriquelalves Beide sind nicht wirklich gleich. Die Implikation eines „benutzerdefinierten Typs“ ist, dass Sie einen In-Engine-Knotentyp simulieren. Das würde bedeuten, dass das Skript selbst nicht entfernt werden kann. Die Funktionalität, die es in den Knoten einfügt, ist darin integriert, genauso wie Sie nicht in der Lage wären, die Node2D-Ness eines Node2D zu entfernen, damit es sich wie ein reiner Knoten verhält.

Akiens beliebter positiver Beitrag oben behandelt ähnliche Details:

Der Punkt hier ist, dass das Skript, das den benutzerdefinierten Knoten definiert, ausgeblendet werden sollte, da es keine Eigenschaft des instanzierten Knotens, sondern seines Typs ist. Daher sollte dieses Skript dem benutzerdefinierten Knoten Eigenschaften verleihen, aber es sollte für den Benutzer des instanzierten Knotens genauso unsichtbar sein wie die C++-Klassen der integrierten Knoten. Es würde eine API bereitstellen, wäre aber nicht modifizierbar, sondern nur erweiterbar.

Wenn wir irgendwelche Editor-Tools erstellen, um das „Skript durch geerbte ersetzen“ zu erleichtern, wäre das cool, aber keine der Funktionen sollte in der Lage sein, die Ebenen der Skripthierarchie auf oder unter dem benutzerdefinierten Typskript zu sehen, da es so sein soll um "eingebautes" Verhalten zu simulieren.

Damit auf den Inhalt von gdscript_parser und anderen Skriptinhalten aus zugegriffen werden kann, ist es möglicherweise am besten sicherzustellen, dass benutzerdefinierte Typinformationen im ClassDB-Singleton enthalten sind und nicht nur EditorNode::get_editor_data().get_custom_types() seitdem Module haben keinen Zugriff auf diese Informationen, sollten aber wirklich Zugriff darauf haben.

Ich habe kein persönliches Problem damit, das Skript verfügbar zu machen, dies ist wirklich eine Frage der Terminologie und Philosophie. Gemäß dem, was Sie erwähnt haben, könnten Sie ClassDB eine neue Klasse hinzufügen und stattdessen eine Skripteigenschaft zu dieser Klasse hinzufügen Der Knoten und die Klasse sollten überprüfen, ob ein Methodenskript vorhanden ist, und sie aufrufen, bevor sie die übergeordnete Klasse aufrufen. Ich glaube, es ist möglich, würde aber die Abwärtskompatibilität mit früheren Versionen beeinträchtigen, wenn dies nicht vor RC1 geschehen wäre

@willnationsdev Ich verstehe, ich stimme einfach nicht von ganzem Herzen zu, dass benutzerdefinierte Typen als In-Engine-Knoten behandelt werden. Für mich liegt die „Leistungsfähigkeit“ von Editor-Addons darin, wie einfach es ist, ein „Paket“ aus benutzerdefinierten Knoten und Editor-Tools zu erstellen und es über GitHub zu teilen; Alle diese Tools und Knoten sind eigentlich nur Szenen und Skripte, die Sie kopieren und einfügen können, aber Godot stellt die Addon-API bereit, um dies zu erleichtern. Als ich es zum ersten Mal benutzte, erwartete ich auch, dass die Addons skriptlos sein würden, aber nur, weil die Engine selbst so aussah, als würde sie sie als In-Engine-Knoten behandeln, und das ist ein UX-Problem, kein Architekturproblem. Was ich denke, würde dies korrigieren, ist:

  1. Benutzerdefinierte Typen in der Baumstruktur „Knoten erstellen“ werden mit einer anderen Farbe angezeigt (was deutlich anzeigt, dass es sich um benutzerdefinierte Typen handelt).
  2. Wenn Sie sie zu Ihrer Szene hinzufügen, ist das Skriptsymbol vorhanden, aber leicht transparent (was darauf hinweist, dass sie ein Standardskript enthalten, das jedoch ersetzt werden kann). Durch Klicken auf das Skriptsymbol wird das benutzerdefinierte Skript im Editor angezeigt.
  3. Die Schaltfläche „Skript hinzufügen“ bei benutzerdefinierten Typen würde die Option „Erbt“ automatisch mit dem benutzerdefinierten Skript ausfüllen.

Dann bin ich definitiv kein Experte, also könnte meine ursprüngliche Annahme von Custom-Types != In-Engine Nodes falsch sein; Außerdem ist Ihre Lösung die klarste, die ich in diesem Thread gesehen habe, daher verstehe ich vollkommen, ob die Godot-Entwicklung so verläuft.

BEARBEITEN: Ich habe es noch einmal gelesen, und meine "Lösung" sind im Grunde Ihre ersten 6 Lösungsschritte, hahaha.

@henriquelalves @MarianoGnu Ich denke, eine Mischung aus diesen wäre sicherlich notwendig. Das Hinzufügen der benutzerdefinierten Typklasse zur ClassDB ist imo ein Muss. Ich liebe alle drei Vorschläge, die du hattest, Henrique. Besonders Idee 2 (viel besser als mein separater Vorschlag für benutzerdefinierte Symbole). Und ich stimme Ihnen zu, dass wir sicherstellen müssen, dass „WAS benutzerdefinierte Typen sind“ bis zu einem gewissen Grad transparent bleibt. Ich denke, dass ein Gleichgewicht gewahrt werden muss: Die Leute sollten verstehen können, ob etwas ein benutzerdefinierter Typ ist UND was das bedeutet, aber wir sollten auch so viel wie möglich tun, damit sich benutzerdefinierte Typen wie Engine-Typen anfühlen.

@willnationsdev Ich habe dies aus der Assetlib genommen und den Code des benutzerdefinierten Knotens in ein "Basis" -Skript verschoben:
Collision_path_2d-1-modified.zip

Das unmittelbare Problem, das ich dabei sehe, ist, dass das Plugin das Skript lädt, und dieses Skript ist einzigartig, wenn ich einen weiteren benutzerdefinierten Knoten hinzufüge, wird es _dasselbe_ Skript haben.

Was bedeutet dann eine Skriptersetzung für das Plugin in diesem Fall? (vielleicht nichts, ich bin mir nicht sicher).

Wenn beim Ersetzen eines Skripts keine Probleme auftreten (der Werkzeugmodus ist in einigen Fällen möglicherweise nicht zufrieden), kann das Menü für benutzerdefinierte Knoten einen Eintrag „benutzerdefiniertes Skript erweitern“ hinzufügen, um diesen Ersetzungsprozess durchzuführen.

@henriquelalves @eon-s Ich denke, wir denken dasselbe. Ich bin damit einverstanden, dass dies mehr als alles andere ein UX-Problem ist. Bisher bin ich von diesem Ansatz parteiisch, weil ich denke, dass es die Dinge so einfach wie möglich hält, was meiner Meinung nach immer gut ist.

Wenn beim Ersetzen eines Skripts keine Probleme auftreten (der Werkzeugmodus ist in einigen Fällen möglicherweise nicht zufrieden), kann das Menü für benutzerdefinierte Knoten einen Eintrag „benutzerdefiniertes Skript erweitern“ hinzufügen, um diesen Ersetzungsprozess durchzuführen.

Ich denke, da das Erweiterungsskript vom Plugin-Skript erben muss, wäre es kein Problem, es zu ersetzen. Aber auch hier bin ich mit der Codebasis nicht sehr vertraut. Wie auch immer, ich habe meine 2 Cent gegeben, ich überlasse es den echten Entwicklern von hier ;)

@willnationsdev Entschuldigung, ich bin wegen der abstrakten Sachen durcheinander gekommen. Meine "abstrakten" Basisklassen haben einfach eine print-Anweisung in _init(), um mir mitzuteilen, ob ich sie versehentlich instanziiert habe ....

Nur um hier einzustimmen, benutzerdefinierte Knotentypen sollten sich absolut wie Engine-Typen verhalten, einschließlich der Einrichtung eines benutzerdefinierten Skripts, der Möglichkeit, in GDScript nach Namen zu verweisen und zu erben, und der Unfähigkeit, das Basisskript des Typs zu entfernen. Dies ahmt das Verhalten der von der Engine implementierten Knoten nach und fördert die interne Konsistenz und Benutzerfreundlichkeit.

In Bezug auf das Zeigen, dass es sich um einen "benutzerdefinierten" Knoten handelt, schlage ich vor, dass der Knoten einen Eintrag in der Dropdown-Liste des Inspektors über "In Hilfe anzeigen" hat, der die Basisskriptdatei des Objekts anzeigt. Aus Benutzer- und Entwicklersicht sollten Sie wissen, dass es sich um einen benutzerdefinierten Knoten handelt, indem Sie ihn verwenden (wer hat ihn sonst noch zum Projekt hinzugefügt?), Und das Ziel von "benutzerdefinierten" Knoten (IMO) besteht darin, die Definition von Typen in GDScript zu ermöglichen, die nicht unterscheidbar sind von eingebauten Motortypen.

@Web-eWorks Ich arbeite tatsächlich daran (genau in diesem Moment) und habe einen anständigen Teil davon erledigt (habe aber noch ein wenig zu tun). Ich habe ein Backup-Skript in der Object-Klasse eingerichtet und Speicher für benutzerdefinierte Typen in der ClassDB erstellt, zusammen mit der Aktualisierung der EditorPlugin-Methoden zur Verwendung der neuen API. Es müssen noch Aktualisierungen an den zugehörigen ClassDB-Funktionen vorgenommen werden (Zeug wie can_instance und get_parent_class usw.) und das gesamte Editor-/CreateDialog-Zeug aktualisiert werden.

@willnationsdev Es sollte beachtet werden, dass die Registrierung in ClassDB auch bedeutet, dass Leute, die Plugins erstellen, alle ihre Klassen voranstellen sollten, um Kollisionen zu vermeiden^^"

@Zylann Ja, das wäre leider nötig.

An diesem Punkt denke ich, dass ich die meisten Bindungen und Kernänderungen aussortiert habe. Jetzt müssen nur noch die Klassen Editor, CreateDialog und EditorHelp / DocData (und der GDScript-Compiler) aktualisiert werden.

Wie ich bereits erwähnt habe. Ich denke immer noch nicht, dass die vorgeschlagene Lösung gut ist.
Bitte erkundigen Sie sich bei mir, bevor Sie etwas versuchen, das höchstwahrscheinlich sein wird
abgelehnt.

Am 7. Februar 2018 um 20:05 Uhr schrieb „Will Nations“ [email protected] :

@Zylann https://github.com/zylann Ja, das wäre nötig,
bedauerlicherweise.

An diesem Punkt denke ich, dass ich die meisten Bindungen und den Kern aussortiert habe
Änderungen. Es ist nur eine Frage der Aktualisierung von Editor, CreateDialog und
EditorHelp / DocData-Klassen jetzt.


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/6067#issuecomment-363893711 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z2xIYRcs0BFDqTyiFwqlhQWTqjEZtks5tSgIVgaJpZM4JejbZ
.

@reduz Nun, ich habe versucht, die Bedenken zu berücksichtigen, die Sie zuvor dargelegt haben.

Ich implementiere kein Multi-Script-System. Ich mache auch keine Skripte, die sich als ClassInfo-Objekte in der ClassDB tarnen. Bisher habe ich lediglich ein Skript (über RefPtr) an die Vererbungshierarchien in der ClassDB angehängt. Die Objektklasse verwendet immer nur dann ein "backup_script", wenn die reguläre Skriptzuweisung versucht, die Vererbungshierarchie des Backup-Skripts zu verletzen.

Oh, ich verstehe.. was ist dann der Anwendungsfall dafür?

Am 7. Februar 2018 um 20:32 Uhr schrieb „Will Nations“ [email protected] :

@reduz https://github.com/reduz Nun, ich habe versucht, darauf einzugehen
berücksichtigen Sie die Bedenken, die Sie zuvor dargelegt haben.

Ich implementiere kein Multi-Script-System. Ich bin es auch nicht
Skripte als ClassInfo-Objekte in der ClassDB maskieren. Alles was ich habe
Bisher ist ein Skript (über RefPtr) an die Vererbung angehängt
Hierarchien in der ClassDB. Die Object-Klasse verwendet immer nur a
"backup_script", wann immer die reguläre Skriptzuweisung versucht, zu verletzen
in der Vererbungshierarchie des Sicherungsskripts.


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/6067#issuecomment-363900920 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z2yn68Iy6AgAKJHZ4qImH4UBAm5skks5tSghSgaJpZM4JejbZ
.

Der Anwendungsfall ist, wenn jemand mithilfe eines EditorPlugins einen neuen Knotentyp in die Engine einführen möchte, aber nicht möchte, dass der Skripttyp dieses Knotens bearbeitet werden kann (sie möchten, dass die Interaktion damit einen In-Engine-Typ nachahmt ). Wenn ich beispielsweise versuche, get_script() auf einem Knoten nur mit seinem Backup-Skript auszuführen, wird null zurückgegeben. Wenn ich versuche, set_script(null) , wird das Skript auf das Backup-Skript gesetzt. Wenn ich versuche, set_script(a_script) zu verwenden, wird das Skript nur dann erfolgreich zugewiesen, wenn sich das neue Skript in der Vererbungshierarchie des Sicherungsskripts befindet.

Für UX plane ich, das Skriptsymbol im Editor als transparentes Symbol anzuzeigen, wenn nur das Sicherungsskript vorhanden ist. In diesem Fall ist die Schaltfläche zum Hinzufügen eines Skripts immer noch eine Schaltfläche "Skript hinzufügen" und nicht eine Schaltfläche "Skript entfernen", und wenn Sie darauf klicken, wird der Text mit dem Namen des Typs vorab ausgefüllt (obwohl ich möglicherweise machen muss Es wird mit dem Skriptpfad vorbelegt, wenn der Benutzer den Skripttyp von GDScript / VisualScript usw. weg ändert). Sobald ein anderes Skript zugewiesen wurde, würde das transparente Symbol wieder undurchsichtig werden. Wenn Sie in beiden Fällen auf das Skriptsymbol klicken, gelangen Sie zum Quellcode des aktiven Skripts (dem Quellcode des Backup-Skripts, wenn kein anderes Skript vorhanden ist).

Ich muss zugeben, dass ich den Nutzen nicht wirklich sehe, also noch einmal, was ist das
konkrete Anwendungsfälle, an die Sie denken?

Am 7. Februar 2018 um 20:46 Uhr schrieb „Will Nations“ [email protected] :

Der Anwendungsfall ist, wenn jemand einen neuen Node-Typ einführen möchte
die Engine mit einem EditorPlugin, aber sie wollen nicht die geskriptete Art von
dass dieser Knoten bearbeitet werden kann (sie möchten, dass die Interaktion damit eine nachahmt
In-Engine-Typ). Also zum Beispiel, wenn ich versuche, get_script() auf einem Knoten auszuführen
mit nur seinem Backup-Skript, dann wird es null zurückgeben. Wenn ich es versuche
set_script(null), dann wird das Skript auf das Backup-Skript gesetzt. Wenn ich
versuchen, set_script(a_script) zu setzen, dann wird es nur erfolgreich zugewiesen
das Skript, wenn sich das neue Skript in der Vererbungshierarchie der Sicherung befindet
Skript.

Für UX plane ich, das Skriptsymbol im Editor als
transparentes Symbol, wenn nur das Backup-Skript vorhanden ist. In diesem Fall ist die
Die Schaltfläche zum Hinzufügen eines Skripts ist immer noch eine Schaltfläche "Skript hinzufügen" und nicht mehr eine
Schaltfläche "Skript entfernen", und wenn Sie darauf klicken, wird der Text mit dem Namen vorausgefüllt
des Typs (obwohl ich ihn möglicherweise mit dem Skriptpfad vorbelegen muss
wenn der Benutzer die Art des Skripts weg von GDScript / VisualScript ändert,
etc.). Sobald ein anderes Skript zugewiesen wurde, wird das transparente Symbol
würde wieder undurchsichtig werden. Klicken Sie in beiden Fällen auf das Skriptsymbol
bringt Sie zum aktiven Skript-Quellcode (dem Backup-Skript-Quellcode, wenn
es ist kein anderes Skript vorhanden).


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/6067#issuecomment-363904934 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AF-Z26oeOMT4HpjzDsX8eygMSeUhbTgVks5tSgurgaJpZM4JejbZ
.

Der Anwendungsfall auf hoher Ebene besteht darin, Plugins (EditorPlugins, das PluginScript/SubModule-System) zu erlauben, „narrensichere“ benutzerdefinierte Knotentypen zu definieren. Derzeit ist das benutzerdefinierte Typsystem eine dünne Fabrik für „Skript auf einem Knoten“, die zahlreiche Workflow- und Benutzerfreundlichkeitsprobleme hat, wenn Sie versuchen, neue Knotentypen zu erstellen, von denen das geringste die völlige Unfähigkeit ist, einfach, intuitiv und effektiv zu sein Erweitern Sie den benutzerdefinierten Knoten mit Gameplay-Code (im Gegensatz zu integrierten Knoten). Ein dringenderes Problem ist die Unfähigkeit, benutzerdefinierte Knoten zu erstellen, die von anderen benutzerdefinierten Knoten erben.

Einige spezifische Anwendungsfälle bestehen darin, Low-Level-Knoten zu erstellen: vielleicht eine auf Marschwürfeln basierende Voxel-GridMap-Implementierung für zerstörbares Gelände, ala Minecraft oder jedes andere Geländesystem, das Marschwürfel/zwei Konturen verwendet; benutzerdefinierte Steuerungstypen (kreisförmiger Menücontainer, wie er in vielen modernen Spielen implementiert ist, jede Art von Low-Level-Steuerung, die gerade hoch genug ist, um außerhalb der Engine-Spezifikation zu liegen); und an jedem Ort, an dem Sie ein Plugin erstellen möchten, das neue Knoten registriert. In jedem dieser Fälle möchten Sie normalerweise ein benutzerdefiniertes Skript hinzufügen, um den Gameplay-Code zu handhaben, und es getrennt vom "Implementierungs" -Code (geschrieben in GDScript/GDNative) haben.

Ich denke, was hier nicht kommuniziert wird, ist, dass das Ziel darin besteht, benutzerdefinierte Knoten dazu zu bringen, sich wie Engine-Knoten zu verhalten, ohne ein Engine-Modul schreiben und dagegen kompilieren zu müssen.

Diese Verbesserung wird nicht unbedingt durch ein bestimmtes Merkmal angetrieben (obwohl es viele gibt), sondern eher durch die Begründung „der aktuelle Weg ist rückständig, schwach und mühsam“. Bei vollständiger Implementierung würde dieses System eine äußerst leistungsfähige Methode zum Erweitern der integrierten Typen der Engine von GDScript / GDNative ermöglichen, ohne dass die Engine neu kompiliert werden müsste. Aus gestalterischer Sicht ist dies buchstäblich eine direkte Verbesserung gegenüber dem aktuellen System.

Wenn Sie nach all dem einen bestimmten Anwendungsfall wollen: das gesamte Plugin / AssetLibrary-Ökosystem .
Das ist der Umfang dessen, was von dieser Änderung profitiert.

Ok, hier ist ein explizites Beispiel:

Ich habe ein Plugin, an dem ich arbeite, godot-skills , das eine Vielzahl neuer Knotentypen einführt:

Wirkung: Nodifizierung eines Funktors
Targeter: ähnlich, findet und sammelt aber nur andere Nodes
Fähigkeit: Kombiniert Hierarchien von Targetern und Effekten, um Knoten zu finden und Effekte auf sie alle anzuwenden
SkillUser: "besitzt" mehrere Skills

Ich möchte, dass jeder dieser Knoten Dinge sind, die Benutzer erstellen und direkt zu einer Szene hinzufügen können. Jeder einzelne dieser Knoten ist jedoch so konzipiert, dass er als Basistyp dient. Sie haben nicht viele Funktionen, die sofort einsatzbereit sind, und müssen ein Ableitungsskript auf jedem Knoten platzieren, an dem sie sonst beteiligt wären. Für Anwendungsfälle wie diese kann es hilfreich sein, einen Knoten zu erstellen, von dem Sie nicht möchten, dass der Benutzer einen bestimmten Satz von Skriptfunktionen entfernen kann. Ich möchte beispielsweise verhindern, dass Benutzer ein nicht von Targeter abgeleitetes Skript auf einem beliebigen Targeter-Knoten platzieren, den sie ihrer Szene hinzufügen. Dies liegt daran, dass Skills sofortige Funktionalität erhalten, wenn Targeter als Kinder vorhanden sind (ähnlich wie Area2D- und CollisionShape2D-Knoten).

Der aktuelle Workflow erfordert, dass Benutzer ...

  1. Fügen Sie einen Knoten vom benutzerdefinierten Typ hinzu
    2a. Entfernen Sie das angehängte Skript und klicken Sie auf die Schaltfläche Skript hinzufügen ODER
    2b. Legen Sie die Skripteigenschaft für den Knoten fest
  2. Finden Sie im Dialogfenster, wo das EditorPlugin das benutzerdefinierte Typskript speichert, das Sie ableiten möchten.

Dieses System würde es Ihnen ermöglichen, all dies durch Folgendes zu ersetzen:

  1. Fügen Sie einen benutzerdefinierten Knotentyp hinzu.
  2. Als Skript hinzufügen (was automatisch mit dem Ableiten des benutzerdefinierten Typskripts beginnt)

Benutzer könnten ihre eigenen benutzerdefinierten Typen dynamisch hinzufügen, die die In-Engine-Typen ableiten (für eine einfachere Benutzerfreundlichkeit). Es würde auch die Sicherheit der Funktionalität des Plugins verstärken, indem es das Vorhandensein der Skriptfunktionalität auf dem fraglichen Knoten erzwingt. Derzeit können Benutzer das Skript einfach entfernen und Dinge beschädigen (nicht wünschenswert). Wenn jemand das Skript auf dem Knoten "löschen" möchte, sollte dieser Knoten außerdem seine benutzerdefinierte Typfunktionalität nicht verlieren (dies ist eine große). Es sollte wieder das benutzerdefinierte Typskript haben.

Ok, also ein Update. Aktuell habe ich folgendes.

  • Die ClassDB können jetzt benutzerdefinierte Typen direkt hinzufügen und entfernen.
  • Das EditorPlugin verfügt über ähnliche benutzerdefinierte Typmethoden, die nicht nur den benutzerdefinierten Typ, sondern auch andere Editor-bezogene Daten wie das Symbol hinzufügen und entfernen. Diese Methoden sind mit einem neuen Signal verbunden, das ausgegeben wird, wenn EditorPlugin aktiv/inaktiv umgeschaltet wird.
  • GDScripts können jetzt ordnungsgemäß direkt von den Namen benutzerdefinierter Typen erben, um vom Skript zu erben.
  • Das Szenendock erstellt ein transparentes Skriptsymbol, wenn das aktuelle Skript mit dem benutzerdefinierten Skripttyp des Knotens übereinstimmt. Wenn Sie darauf klicken, wird das benutzerdefinierte Typskript im Editor geöffnet. In diesem Zustand wird die Schaltfläche „Skript hinzufügen“ statt „Skript entfernen“ angezeigt. Wenn diese Schaltfläche ausgewählt ist, füllt diese Schaltfläche das Feld „Übernimmt“ vorab mit dem Namen des benutzerdefinierten Typskripts (falls nicht null).
  • Alle Versuche, ein Skript zu entfernen, führen dazu, dass das benutzerdefinierte Typskript als Skriptwert neu zugewiesen wird. Um das Skript zu entfernen, müssen Sie daher zuerst den Wert des benutzerdefinierten Typskripts mit set_custom_script(RefPtr()); löschen.
  • Das Dialogfeld "Knoten erstellen" zeigt Vererbungsbeziehungen und abstrakte Knoten für benutzerdefinierte Typen korrekt an.
  • Die Datei project.godot wird mit allen benutzerdefinierten Typen gefüllt, sodass ausgeführte Spiele sie in main.cpp einrichten können, bevor der Rest des Spiels beginnt.

Noch zu erledigende Aufgaben...

  • Benutzern erlauben, Klassen-API-Dokumente für benutzerdefinierte Typen zu generieren.
  • Beheben Sie insgesamt einen separaten Fehler, der Benutzer daran hindert, das Feld "Inherits" in script_create_dialog.cpp zu bearbeiten.
  • Finden Sie eine Möglichkeit, benutzerdefinierte Typen zur globalen GDScript-Karte/dem Array dynamisch hinzuzufügen und zu entfernen *
  • Implementieren Sie die Unterstützung benutzerdefinierter Typen in VisualScript

* Ich habe tatsächlich ein paar Fragen dazu.

Erstens sehe ich nur add_global_constant / _add_global in der Datei gdscript_compiler.cpp ohne Möglichkeit, Globals aus der GDScriptLanguage-Klasse zu entfernen. Wird es einfach komplett neu initialisiert, wenn Singletons hinzugefügt oder entfernt werden? Wie werden globale Identifikatoren dynamisch bearbeitet? Dies wäre so, dass Benutzer MyNode.static_func() ausführen können, ohne das Skript zuerst in eine Variable laden zu müssen.

Wo ich gerade dabei bin, habe ich das Gefühl, dass Godots GDScript stark von der Einführung von Namespaces profitieren könnte, insbesondere als Teil dieser Änderung. Wir müssten das richtige Trennzeichen finden, um sie zu kennzeichnen, aber Sie könnten Bedenken hinsichtlich Namenskollisionen von Engine- und Plugin-Typen ausräumen, wenn Sie Ihre eigenen Skripte erstellen. Angenommen, \ ist beispielsweise das Trennzeichen der Wahl...

extends Node # an in-engine type.
extends \ # triggers an error if left alone, but would prompt a dropdown of the plugin API names for auto-completion as well as the names of any scripts in the current project that are not part of a plugin.
extends \MyPlugin\ # triggers an error if left alone, but would prompt a dropdown of the scripted types that exist for the plugin
extends \MyNode # extends my_node.gd somewhere in res://
extends \MyPlugin\MyNode # extends my_node.gd somewhere in res://addons/[my_plugin_something?]/

func _ready():
    print(\MyNode.CONSTANT) # would print CONSTANT in the current project's my_node.gd script

Wie auch immer, all dies ^ sind nur Ideen, die im Moment herumgeworfen werden. Wenn Namensräume eingeführt würden, könnten Sie Skripten sogar automatisch einen Namen basierend auf ihrem Dateinamen zuordnen, indem Sie das Signal resource_saved in EditorNode verwenden. Sie WÜRDEN NICHT unbedingt benutzerdefinierte Typen sein (in dem Sinne, dass Sie das Skript nicht aus dem Objekt entfernen können), aber sie WÜRDEN allein über den Namen zugänglich sein, was äußerst nützlich und intuitiv wäre. Skripte könnten sogar die standardmäßige automatische Benennung ( filename.capitalize().replace(" ", "") ?) überschreiben, indem sie oben einen Namensraum-Titel angeben, z. B. \MyPlugin\mynode . Jetzt ist plötzlich "\MyPlugin\mynode" eine globale Kennung für dieses Skript.

Hier ist ein Ausschnitt meiner bisherigen Fortschritte.

@willnationsdev bitte wähle nicht \ , es wird bereits für Escaping und Multiline verwendet. . , : oder :: sehen besser aus.

@Zylann Ich hatte vor, das Trennzeichen auch als Präfix für alle Knoten zu verwenden, die dem Projekt hinzugefügt werden. Dann würde zum Beispiel ein Skript bei res://container.gd keine Kollisionen mit der eigentlichen Klasse Container haben wollen. Wenn wir einen Punkt (.) verwenden, könnte es so aussehen.

var engine_type = Container.new()
var script_type = .Container.new()
var plugin_script_type = .MyPlugin.Container.new()

Hat jemand Einwände gegen diese Art von Format?

Bearbeiten:

Dies kann jedoch zu Problemen innerhalb abgeleiteter Klassenfunktionen führen, die die Methode des übergeordneten Elements in ihnen aufrufen:

func _virtual_method():
    ._virtual_method() # parent stuff
    # my stuff

Hmm... stellt das ein Problem für Konstanten und/oder Variablen dar? Wenn nicht, können wir einfach davon ausgehen, dass Klammern bedeuten, dass es sich um eine Superfunktion handelt, und andernfalls handelt es sich um einen möglichen Namespace-Bezeichner.

Ehrlich gesagt würde ich mit dem Namespace erst einmal warten - es könnte später eingeführt werden, und ich würde das aktuelle System lieber so schnell wie möglich einführen. Wir bräuchten auch ein _wirklich_ durchdachtes System zur automatischen Namensregistrierung, eventuell bis hin zu einer Überarbeitung der gesamten Addon-Organisationsstruktur, was ein ziemlicher Aufwand ist und den Rahmen dieser Ausgabe sprengen würde.

Persönlich würde ich es vorziehen, den Namen für ein „automatisch registriertes“ Skript durch eine Deklaration in der Datei zu steuern, dh

register <NAME> extends <PARENT>

oder eine ähnliche Syntax, die auf dem aktuellen extend <NAME> -Prolog basiert, der bereits für GDScript vorhanden ist.

BEARBEITEN: Ich wollte auch fragen, wie das Zuweisen von Skripts, die von einem Elternteil (z. B. Spatial) zu einem benutzerdefinierten Kind (z. B. Sprite3D-> CustomType) stammen, gehandhabt wird? Dies funktioniert bereits für Engine-Typen, und die Einschränkung zugewiesener Skripts, die vom benutzerdefinierten Typ selbst abgeleitet werden sollen, wird nicht sehr gut funktionieren.

@Web-eWorks Fair genug. Ich werde daran arbeiten, die aktuelle API zu perfektionieren, und dann werde ich ein neues Problem für das Namespacen eröffnen, sobald die PR eingereicht wurde.

Wenn ich gut verstehe, was @Web-eWorks bedeutet, habe ich selbst noch diese Frage: Wie kommt man um die Tatsache herum, dass ein Object nur ein einziges Skript haben kann? Wie werden sie ... "skriptfähig" sein? Denn abgesehen davon ist die Registrierung bei ClassDB nichts anderes als eine globale Kennung in Bezug auf die Nutzung für Programmierer und Designer.

@Zylann Was ich in meinem Fork gemacht habe, ist eine custom_script Eigenschaft für Object zu erstellen. Es wird immer nur dann bedeutsam, wenn ihm ein Wert zugewiesen wird, aber wenn ihm ein Skript zugewiesen wird , dient es als Backup-Skript / Einschränkung dafür, was die Haupteigenschaft script sein kann. Durch das Löschen script wird es auf custom_script gesetzt, und wenn Sie script ein neues Script zuweisen, wird es nur dann erfolgreich zugewiesen, wenn das Script Die Instanz custom_script ab. Und all dies wird hinter den Kulissen von Object verwaltet, was die Engine betrifft, haben Object s immer noch nur 1 tatsächliches Skript.

Der ClassDB-Inhalt hat nur eine sekundäre Zuordnung benutzerdefinierter Typen, die registriert werden und das Skript selbst und einige andere Informationen dem Namen zuordnen, den Sie ihm zugewiesen haben. Anschließend stellt es diesen Namen und seine Vererbungshierarchie mit verwandten Vererbungsmethoden bereit ( get_class_list , is_parent_class , get_parent usw.). Und dies geschieht als Opt-in-Flag für einige der Methoden. get_class_list nimmt jetzt ein Bool-Flag, wo es nur benutzerdefinierte Typen enthält, wenn Sie true als zweiten Parameter übergeben. Auf diese Weise wird verhindert, dass die Kompatibilität mit dem Rest des Motors beeinträchtigt wird.

@willnationsdev Also , mit einem System, das Skripte dazu bringt, sich wie eingebaute Klassen zu verhalten, was hindert Benutzer daran, zu wollen, dass alle ihre Skripte und Addons als erstklassige Bürger wie die eingebauten Klassen betrachtet werden, und den "alten" Weg fallen lassen?

Ah. Die Art und Weise, wie Skripte derzeit funktionieren, ist, dass Sie ein Skript, das extends Node auf ein VBoxContainer setzt, und es funktioniert immer noch einwandfrei. Wenn die aktuelle Implementierung dieses Verhalten für benutzerdefinierte Typen unterbricht, wird es einige Probleme geben - gibt es eine Möglichkeit, das Verhalten des benutzerdefinierten Skripts beizubehalten, während ein "normales" Skript direkt von einem Engine-Typ abgeleitet wird?

@Zylann Das ist eigentlich genau der Grund, warum ich Namensräume einführen möchte, damit Skripte und Skripte von Plugins sicher über Namen integriert werden können, ohne mit In-Engine-Typen zu kollidieren. Nichts würde die Menschen daran hindern, nur den neuen Weg zu verwenden und den alten Weg zu ignorieren. Und ich denke eigentlich, dass das insgesamt besser wäre. Es ist mühsam, jedes Mal einen expliziten Pfad verwenden zu müssen.

@Web-eWorks Ich bin mir nicht sicher, ob ich hier richtig folge, aber ...

Benutzerdefinierte Typen funktionieren speziell wie In-Engine-Typen für die Vererbung. Wenn Sie also von einem benutzerdefinierten Typ aus erweitern, ist es so, als würden Sie von einem völlig anderen Zweig der In-Engine-Hierarchie aus erweitern. Ex. Wenn ich einen benutzerdefinierten Typ MyNode erstelle, der Node erweitert, kann ich dieses Skript nicht auf ein VBoxContainer setzen, genauso wie ich kein Node2D setzen kann VBoxContainer . Das wäre eigentlich das beabsichtigte Verhalten.

Nun, mit dem Namespace-Konzept hätten Sie idealerweise Skripts benannt, die KEINE benutzerdefinierten Typen sind. In diesem Fall könnte ich also ein Skript erstellen, das Node erweitert und es auf Node , VBoxContainer UND MyNode setzt. Ist das sinnvoll?

Was ich also sagen will, ist, wenn Sie einen benutzerdefinierten Typ MyNode MeshInstance , einen Knoten davon im Editor instanziieren und versuchen, ein Skript hinzuzufügen, das Spatial erbt zum MyNode typisierten Knoten, wird das richtig funktionieren? Es funktioniert richtig mit 'Engine'-Knoten, und das ist das Verhalten, das wir nachahmen müssen.

Es sollte Namespace-unabhängig sein, da es hier eher darum geht, sicherzustellen, dass das Skript des benutzerdefinierten Typs unabhängig vom Punkt in der Vererbungshierarchie des Skripts auf Benutzerebene aufgerufen wird.

@Web-eWorks Ja, das würde funktionieren. Jeder Eintrag der "ersten Ebene" in der $# custom_types -Map ClassDB muss mit einem Typ in der classes -Map zurückverlinken, andernfalls tritt ein Fehler auf und der benutzerdefinierte Typ ist nicht vorhanden nicht erstellt. Dadurch wird sichergestellt, dass die Vererbungskette erhalten bleibt, wenn von benutzerdefinierten Typen zurück zu den Engine-Typen bis hin zu Object wird.

@willnationsdev Nur um sicherzugehen - wenn Sie eine _ready -Methode in MyNode und einen fertigen Knoten in Ihrem Benutzerskript hinzufügen, der von Spatial abgeleitet ist, wird er wie Spatial._ready(), MeshInstance._ready(), MyNode._ready(), script._ready() aufgerufen ? (Oder welche Bestellung _ready verschickt wird.)

Ich bleibe nach wie vor bei meiner Ansicht, dass dies unnötig und verwirrend ist. Dieses Problem muss über die Editor-Benutzeroberfläche gelöst werden, nicht über die Core-Engine.

@reduz Dies kann jedoch nicht allein über die Editor-Benutzeroberfläche gelöst werden. Nicht, wenn Sie die Manipulation des Skripts auf dem Objekt durch Benutzer kontrollieren möchten. Es scheint mir, dass dies eine Funktion ist, die viele Leute einrichten möchten.

Schlagen Sie vor, dass der gdscript_compiler auf Inhalte in EditorData verweisen sollte, um neue globale Bezeichner für Skripttypen einzurichten, anstatt sie alle in der ClassDB zu verfolgen und der ClassDB zu erlauben, alle Vererbungsinformationen in der Engine zu verwalten?

Sicherlich gibt es einen Teil davon, der aus der Perspektive der Editor-Benutzeroberfläche gelöst werden muss, aber es gibt auch einen Teil, der im Kern gelöst werden muss. Das Hinzufügen von benutzerdefinierten Typen zur Engine, _eigentliche_ Typen aus der Sicht der ClassDB, ist ein sehr mächtiges und letztendlich notwendiges Feature. Was die Verwirrung betrifft, behaupte ich immer noch, dass es nicht verwirrender ist als das derzeitige System, und sehr wahrscheinlich weniger.

@Web-eWorks Ich stimme zu. Die Vererbungsdaten im Editor verfolgen zu lassen wäre meiner Meinung nach eigentlich viel verwirrender. Und es würde zu seltsamen Problemumgehungen führen, da diese Art von Informationen nicht mehr existieren würden, wenn Sie das Spiel ohne den Editor ausführen (weshalb ich tatsächlich damit beginnen musste, die Informationen in project.godot zu laden, um sie zu laden ClassDB beim Start. Kein EditorPlugins zum Hinzufügen der benutzerdefinierten Typen führte dazu, dass die Kompilierung der GDScripts fehlschlug, wenn die Szene ausgeführt wurde).

@Web-eWorks Und um Ihre frühere Frage zu beantworten, ja, das funktioniert richtig.

In meinem Testszenario habe ich Node.gd , das GDSkillsEffect > GDSkillsAPI > Node erweitert, und die in jedem Skript implementierten _ready-Methoden werden ordnungsgemäß ausgelöst Reihenfolge: API, Effekt, Node.gd.

Ich erlebe derzeit einen Endlosschleifenfehler irgendeiner Art, wenn zwei Skripte beide versuchen, namentlich von benutzerdefinierten Skripten zu erben. Ex. Wenn Node.gd extends GDSkillsEffect hat und gdskills_effect.gd extends GDSkillsAPI hat, wird der Versuch, gdskills_effect.gd oder gdskills_api.gd zu ändern und zu speichern, dazu führen, dass der Editor dies tut unendlich "laden" und dann abstürzen. Das ist momentan wohl mein größter Bug.

@willnationsdev Ahh, nein, ich spreche von Node.gd Verlängerung Node , _not_ GDSkillsEffect . Wenn _das_ funktioniert, dann ist alles gut.

Hier ist zum Beispiel eine Darstellung des Szenenbaums:

-> User Script:
  extends Node
  func _ready(): pass

@Web-eWorks Ah, ich verstehe, was du meinst. Nun, es SOLLTE funktionieren, aber ich habe es gerade getestet und es scheint, als ob meine Logik in Object::set_script() es aus irgendeinem Grund blockiert, also ist das ein Fehler, den ich beheben muss. XD Es schlägt fehl, weil es festgestellt hat, dass Node das benutzerdefinierte Typskript nicht ableitet (was wahr ist, yay), aber es sollte in diesem Fall nicht fehlschlagen, lol.

@Web-eWorks Wie ich bereits erwähnt habe, muss dies NICHT in ClassDB geändert werden.

Ich glaube nicht wirklich, dass dies im Kern gelöst werden muss, da jede Skriptsprache anders damit umgeht. Sie können einfach eine neue Klasse in Mono erstellen und es wird funktionieren. Für GDScript kann es ein einfacher Fall sein, eine Skriptdatei als vorinstallierte globale Datei bereitzustellen, und das war's. Eine Einheitslösung, wie sie in der PR vorgeschlagen wird, ist definitiv nicht der richtige Weg.

@willnationsdev Ich schätze deine Bemühungen, aber das wurde bereits ohne Ende diskutiert und der Konsens ist folgender:

  • Das Hinzufügen eines benutzerdefinierten Typs ist für jede Skriptsprache unterschiedlich, daher ist es NICHT der richtige Weg, etwas in ClassDB zu hacken, das eigentlich nur dazu gedacht ist, C++-Sachen zu registrieren.
  • Bevor wir so weit gehen, können wir die Benutzerfreundlichkeit der Benutzeroberfläche für Fälle verbessern, in denen Sie das Skript eines benutzerdefinierten Knotens erweitern möchten, sodass nur eine einfache Vererbung erstellt wird.
  • Im Allgemeinen ist es nie der richtige Weg, der Kern-Engine Hacks hinzuzufügen, um Sonderfälle zu bewältigen. Core muss hackfrei bleiben.

@willnationsdev Als Referenz ist das Engine-Verhalten so, dass jedes Skript, das _etwas_ gleich oder früher in der Vererbungshierarchie erweitert, zu einem Knoten hinzugefügt werden kann. Somit kann ein Skript, das extends Spatial zu einem MeshInstance hinzugefügt werden kann, aber nicht zu einem Control oder Node , da keines der letzteren Spatial ist oder von ihm erbt

@reduz Aber fügt das Erstellen einer neuen Klasse in Mono diese der Vererbungshierarchie der Engine hinzu? Oder das Dialogfeld "Knoten erstellen" des Editors? Vielleicht muss ein neues Thema eröffnet werden, das kurz und bündig erklärt, was der Zweck davon ist, weil ich denke, wir sprechen hier nicht über dasselbe.

Der Sinn der ClassDB-Modifikationen besteht darin, die Registrierung neuer Arten von Knoten (oder Ressourcen) zu ermöglichen, ohne dass die Engine neu kompiliert werden muss. Keine neuen benutzerdefinierten Globals in GDScript hinzuzufügen, obwohl dies ein tangentiales Problem ist, an dem @willnationsdev im selben Zweig arbeitet.

Der Punkt dabei ist nicht, Hacks hinzuzufügen, sondern ein gut gestaltetes _System_ zu erstellen, um die Typen der Engine zu erweitern.

@Web-eWorks Die Engine-Vererbungshierarchie gilt für C++, nicht für Skripte. Der Versuch, beide zu mischen, ist zunächst konzeptionell falsch.

Vielleicht liegt das Missverständnis darin, dass der Dialog zum Erstellen von Knoten es so aussehen lässt, als wäre eine neue Klasse hinzugefügt worden, daher kann es eine gute Idee sein, solche benutzerdefinierten Typen als eindeutig ein Skript enthaltend zu markieren.

@Web-eWorks Wenn Sie Mono verwenden, sieht es transparent aus, als ob eine neue Klasse hinzugefügt wurde, da es sich um eine neue Klasse handelt. Für GDScript, da Klassen standardmäßig Dateien sind, kann dies nicht auf diese Weise geschehen, daher besteht die Möglichkeit, dies zu tun, darin, eine neue globale mit einer dedizierten Benutzeroberfläche hinzuzufügen, um sie einzurichten (wie wir es für Singleton-Autoloads getan haben) ... aber dies ist immer noch eine Skriptklasse, keine Engine-Klasse.

@willnationsdev Mein ganzer Punkt dabei ist, dass ich denke, dass es falsch ist, es so aussehen zu lassen, als würden Sie der Engine tatsächlich neue Klassen hinzufügen, weil dies nicht der Fall ist. Es ist offen für Verwirrung. Es ist nur ein Knoten mit einem Skript. Anstatt das Skript auszublenden, denke ich, dass es richtig ist, es im Erstellungsdialog sichtbarer zu machen.

@reduz Nun, das ist die Sache. Node+Script ist eine Szene. Der add_custom_type-Mechanismus sollte sich wie Mono verhalten und eine „neue Klasse“ registrieren, auch wenn es sich technisch gesehen nicht um eine „Klasse“ handelt. Wenn es eine Möglichkeit gibt, dies zu tun, ohne die ClassDB berühren zu müssen, bin ich ganz Ohr.

Außerdem schlug @akien-mga vor, dass wir in der Szenenbaumansicht die Skripte benutzerdefinierter Knoten ausblenden könnten, um Benutzer nicht zu verwirren, weil sie dieses Skript erstellt und versehentlich bearbeitet haben (aber es trotzdem im Inspektor unten anzeigen). .

In solchen Knoten öffnet das Hinzufügen eines Skripts den Erstellungsdialog in einem Vererbungsmodus, sodass er für den Arbeitsablauf des Benutzers immer noch ziemlich transparent ist, während klar ist, dass es sich um einen benutzerdefinierten Knoten und nicht um einen Teil der Engine handelt.

@willnationsdev Irgendwelche Einwände dagegen, dass ich eine neue, prägnantere Ausgabe eröffne, die speziell den Umfang der Implementierung beschreibt?

@Web-eWorks Knoten + Skript ist keine Szene, Knoten in einem Baumlayout sind eine Szene. Sie können auch benutzerdefinierte Ressourcentypen hinzufügen, nicht nur Knoten.

Und nein, es sollte sich nicht wie das Registrieren einer neuen Klasse verhalten. Es muss ziemlich klar sein, dass es sich um eine C++-Klasse mit einem vorab hinzugefügten Skript handelt.

@Web-eWorks Ja, das ist kein Problem für mich. Bitte erwähnen Sie mich, damit ich einen Ping erhalte, wenn Sie dies tun. Nicht sicher, ob wir eine separate Ausgabe brauchen?

Betrachten Sie es aus einem anderen Blickwinkel. Ihr Argument ist, es für den Benutzer so aussehen zu lassen, als würden Sie die Engine-Typen um neue Engine-Typen erweitern.

Mein Standpunkt ist, dass Sie die Engine-Typen mit Skripten erweitern, nicht mit neuen Engine-Typen. Und dass der Benutzer nicht dumm ist und dies wissen muss.

@reduz Was ich mit Node + Script meinte, war, dass dieser Mechanismus bereits durch das Instanziieren von Szenen abgedeckt wurde.

Vielleicht verstehe ich die Mono-Implementierung falsch, aber sind Mono-Klassen nicht immer noch Skripte?

@reduz Ich stimme Ihnen größtenteils zu, auch wenn Sie sagten, dass das Hinzufügen eines Skripts zu einem benutzerdefinierten Knoten einfach vorschlagen würde, es zu erben. Aber wie soll das Ihrer Meinung nach mit benutzerdefinierten GDNative-Typen funktionieren?

@reduz Eines unserer Ziele ist es jedoch, zuzulassen, dass benutzerdefinierte Typskripte, diese vorab zugewiesenen Skripte, die in den C++-Klassen platziert sind, nicht entfernt werden können. Dies ist im Editorkontext nicht möglich, da Sie ein Skript jederzeit zur Laufzeit entfernen können (es sei denn, Sie möchten diese Funktionalität beibehalten und nur ein benutzerdefiniertes Typskript zur Entwurfszeit im Editor sichern).

Ich wäre auf jeden Fall offen für eine alternative Methode. In jedem Fall besteht die einfachste Implementierung darin, dass das Objekt sich selbst Skripts bedingt zuweist (wie ich es in meiner Implementierung getan habe), indem eine Registrierungsklasse eines Drittanbieters überprüft wird (ob dies die ClassDB, ProjectSettings, EditorData oder wer weiß was sonst noch ist) . Es wird dann für den Editor selbst sehr einfach, sich bei diesem Drittanbieter zu erkundigen und die Dinge anders anzuzeigen (ebenfalls so, wie ich es in meiner Implementierung getan habe). Es wäre nicht zu viel Arbeit, aber ich glaube nicht, die Registrierung in einen anderen Kontext als die ClassDB zu verschieben.

^ Wäre dieser Kompromiss akzeptabel? Andernfalls müssen Sie jede mögliche Stelle im Mikromanagement verwalten, an der Object ein Skript zugewiesen bekommt, um es mit dem Drittanbieter zu überprüfen. Das wäre viel komplexer.

Die von mir durchgeführte Implementierung war bisher sehr klar, welche "Typen" Skripte sind und welche nicht. Schließlich können Sie das mit benutzerdefinierten Typen verknüpfte Skript im Szenen-Dock in dem von mir geteilten Video immer noch deutlich sehen und darauf zugreifen.

@willnationsdev Ich verstehe, was Sie versuchen, aber ich glaube nicht, dass dies jemals sauber gemacht werden kann. Es verbirgt eine Komplexität, die keinen Grund hat, auf eine Weise versteckt zu werden, die niemals vollständig wie erwartet funktionieren wird.

@Zylann Ich denke, es ist dasselbe, aber entweder a) das Skript ist gdnative internal b) es verwendet eine interne Methode von gdnative. Ich kenne mich zu wenig damit aus, um es ehrlich zu sagen.

@reduz Wollen Sie damit sagen, dass Sie keine Form der Erstellung skriptbasierter Einschränkungen für Objekte zulassen möchten? Denn ich könnte die Prüflogik in den Editor selbst verschieben, und das würde Ihnen die Überprüfung der Einschränkungen zur Entwurfszeit genauso einfach ermöglichen (Änderungen der Benutzeroberfläche, wie Sie sagen), aber sie würden zur Laufzeit nicht funktionieren, also würden die Leute es immer noch tun in der Lage, Dinge zu ändern, sobald das Spiel läuft. Würde das für dich besser funktionieren? Ich würde es immer noch vorziehen, Dinge zur Laufzeit überprüfen zu können ...

@willnationsdev welche Art von skriptbasierten Einschränkungen möchten Sie

Dieselben Einschränkungen, um die es bei der benutzerdefinierten Skripteigenschaft von Anfang an ging: Erzwingen, dass das zugewiesene Skript ein anderes Skript ableitet.

Ich würde empfehlen, das Skriptsymbol für das erweiterte Skript in der Szenenhierarchie auszublenden und für den Fall, dass jemand auf die Schaltfläche "Skript hinzufügen" klickt, anstatt die Basisklasse des Knotens zu erben, erbt er das angegriffene Skript. Es ist transparent und muss überhaupt nicht mit ClassDB herumspielen

Wenn ich mir also nur einige der Informationen in script_language.h , habe ich das Gefühl, ich könnte den neuen Inhalt, den ich in ClassDB hinzugefügt habe, wirklich einfach in die Klasse ScriptLanguage verschieben und eine erstellen eine Art ScriptDB Singleton, das immer nur erstellt wird, wenn die Skriptsprache beabsichtigt, es zu verwenden. Und da object.cpp bereits script_language.h enthält, könnte es in set_script(const RefPtr &p_script) Folgendes tun ...

  1. Prüfen Sie, ob p_script tatsächlich ein Skript ist
  2. Prüfen Sie, zu welcher Sprache p_script gehört
  3. übergeben Sie die Instanz p_script und die Instanz custom_script der Instanz Object an die Instanz ScriptDB für die zugehörigen ScriptLanguage ,
  4. eine Antwort vom ScriptDB erhalten, ob das p_script dem Object zugewiesen werden kann, angesichts der Einschränkungen, die durch das custom_script für das Object impliziert werden

Dies würde es uns ermöglichen, sowohl ClassDB von Änderungen als auch object.h sauber zu halten (abgesehen von einem Setter/Getter für custom_script ). Es verhindert auch eine unnötige Komplikation der Skriptsprachen, die sich nicht auf Godot verlassen müssen, um Bezeichner und Namespaces zu definieren (wie GDScript und VisualScript es brauchen würden, im Gegensatz zu C#, C++, Python usw.).

Dann müssten Sie nur noch ScriptServer Methoden definieren, die Bezeichner-/Namespace-Prüfungen in allen anwendbaren Skriptsprachen durchführen können, um die experimentelle ClassDB Funktionalität zur Bestätigung benutzerdefinierter Typen/Vererbung benutzerdefinierter Typen zu ersetzen Hierarchien. Leicht genug.

Klingt irgendetwas davon nach einer akzeptablen Alternative @reduz?

Ich füge hier nur meine Stimme hinzu. Ich habe gerade angefangen, mit Godot zu arbeiten, und als ich über benutzerdefinierte Typ-Addons las, dachte ich tatsächlich, dass ich einen neuen wiederverwendbaren Basistyp erstellen würde. Wenn Sie beispielsweise ein KinematicBody erstellen, können Sie ein Skript daran anhängen, aber es würde immer noch alle seine KinematicBody Dinge tun.

Dies wird auf zwei Arten verstärkt:

  1. Sie werden Typen genannt. Während sich Sprachen darin unterscheiden, ob ein Typ erweiterbar ist oder nicht (Javascript: ja, golang: nein, Python: ja), ist ein Typ, den Sie allgemein definieren, erweiterbar, wenn die erstklassigen Sprachtypen erweiterbar sind. In Godot sind die ersten Klassentypen erweiterbar, die benutzerdefinierten Typen jedoch nicht (zumindest nicht auf die gleiche Weise). Sie anders zu nennen, wie vorgefertigte Szenen oder Vorlagenszenen, würde helfen, sie als unterschiedlich zu kennzeichnen.
  1. Sie erscheinen im selben Baum wie die erstklassigen Knoten im Fenster „Neuen Knoten erstellen“. Dies bedeutet, dass Sie sie auf die gleiche Weise verwenden. Wenn Sie einen separaten Abschnitt für "Prefabs" oder "Templates" oder wie auch immer Sie sie nennen möchten, haben, würden Sie sie wieder als unterschiedlich bezeichnen.

@JPTeesdale Leider ist an dieser Stelle die Implementierung die größere Sorge, nicht so sehr die Frage "Wie definierst du das?". Und benutzerdefinierte Godot-Typen SIND erweiterbar (sie sind nur Skripte). Der Editor hat einfach noch nicht die Codeunterstützung, um Vererbungsbeziehungen zwischen benutzerdefinierten Typen im Knotenerstellungsdialog anzuzeigen, aber die Daten sind verfügbar. Ich sehe auch keinen Grund, sie von "benutzerdefiniertem Typ" in etwas anderes umzubenennen. "Prefab" und "Template" sind weder wirklich passende Begriffe, noch sind sie in erster Linie Szenen (es sind einfach nur Skripte, schlicht und einfach).

Ich denke, es ist viel einfacher als die beabsichtigte Lösung:

  1. Fügen Sie der Objektklasse eine im Inspektor verborgene Eigenschaft mit dem Namen "custom_type_script" hinzu und weisen Sie das benutzerdefinierte Skript zu, um diese Eigenschaft anstelle von Skript auszuwählen
  2. Wenn Sie versuchen, den Knoten zu erweitern, überprüfen Sie, ob diese Eigenschaft null ist, wenn nicht, erweitern Sie dieses Skript anstelle der Knotenklasse (schreiben Sie "erweitern "res:/path/to/script.gd")
  3. Ändern Sie get_script_instance so, dass es auf die Instanz des benutzerdefinierten Skripts verweist, wenn die des Knotenskripts null ist

@MarianoGnu Nun, in Bezug auf das Erstellen der Editoränderungen ist es einfacher, die Eigenschaft script automatisch auszufüllen und zu verhindern, dass sie überhaupt jemals null wird (weil der Editor immer nur die script -Eigenschaft, und wir müssen nicht jedes Mal suchen, wenn sie auf die script -Eigenschaft verweist, und diesen Code ändern, wenn wir nur den Wert von script ändern.) .

Abgesehen davon besteht ein Teil des Ziels der Wiederholung dieses Prozesses darin, Skriptsprachen im Allgemeinen zu ermöglichen, sich für die Verwendung von Bezeichnern anstelle von Dateipfaden zu entscheiden, um Skriptklassen zu finden. Das ist der einzige Grund, warum das ScriptDB -Konzept oder ClassDB -Modifikationen überhaupt jemals vorgeschlagen wurden. Aber jetzt verstehe ich, warum Juan so sehr gegen die ClassDB -Änderungen protestiert hat, daher der Vorschlag, die Informationen allein in der Skript-API zu speichern. Es enthält in sich alle Informationen in der jeweiligen Skriptsprache.

Eine Kombination könnte durchgeführt werden, anstatt das unsichtbare Skript im Objekt zu speichern, fügen Sie es in der ScriptDB hinzu, fügen Sie dem Skriptleser einen Pre-Pass hinzu, um "extend CustomClassName" durch "extend "res:/path/stored/inScriptDB.gd" zu ersetzen " im Precompiler von GdScript, da es sehr mühsam ist, das Skript außerhalb der Skript-Hierarchie zu erben (Hierarchie muss eine gerade Linie von unten bis zum Stamm sein, eine Verzweigung führt zu Verwirrung)

weil es sehr mühsam ist, das Skript außerhalb der Skript-Erbe-Hierarchie zu haben (Hierarchie muss eine gerade Linie von unten bis zum Stamm sein, eine Verzweigung führt zu Verwirrung)

@MarianoGnu Vielleicht gibt es hier ein Missverständnis. An welchem ​​Punkt gibt es Ihrer Meinung nach keine gerade Linie der Vererbung? Soweit ich Dinge implementiert habe, gibt es immer eine sehr klare Vererbungshierarchie zwischen Skripten. Ich habe nichts daran geändert, wie die Vererbungshierarchien selbst funktionieren. Ich habe es gerade ermöglicht, ein bestimmtes Skript einem StringName zuzuordnen und es in irgendeiner Art von Datenbank nachzuschlagen.

Und wenn wir uns bereits damit beschäftigen, gibt es keinen Grund, den Text des Skripts wieder durch einen Pfad im GDScript-Compiler zu ersetzen. Der Compiler weist lediglich eine Script -Instanz einer script -Variablen zu. Ob ich das Skript über die Methode ResourceLoader::load(path) geladen habe oder es mit Class/ScriptDB::get_script(namespace_and/or_identifier) geholt habe, spielt keine Rolle.

Ich wollte nur erwähnen, dass ich als neuer Benutzer von Godot ein Plugin unter dem Eindruck erstellt habe, dass mein "Custom Node" aus dem Plugin als eingebauter Knoten fungieren würde. Das heißt, als ich es aus der Knotenliste auswählte, erwartete ich, dass ich einen Knoten ohne Skript erhalten würde, aber mit der Funktionalität, die ich im Plugin geskriptet hatte, das bereits eingebaut war (wie es für die eingebauten Knoten ist). Ich dachte nur, ich sollte eine andere Meinung von jemandem geben, der gerade reinkommt (obwohl es so aussieht, als wäre die Diskussion hier bereits umfangreich gewesen).

Da ein "benutzerdefinierter Knoten" nur ein Skript ist, was ist überhaupt der Unterschied dazu, das Skript nur einem eingebauten Knoten zuzuweisen? Was soll die benutzerdefinierte Knotenfunktion tun?

@MCrafterzz Es wurde diskutiert, dass benutzerdefinierte Knoten die Möglichkeit haben sollten, ein Skript über einen benutzerdefinierten Knoten hinzuzufügen, der aus einem Plugin erstellt wurde.

Derzeit ist ein benutzerdefinierter Knoten nur ein Knoten, der mit einem bereits angehängten Skript erstellt wurde und Symbol und Name bereits geändert haben.

@willnationsdev Wie weit bist du mit der Implementierung dieser Funktion gekommen?
Ich würde mir wirklich wünschen, dass dieses Feature vor 3.1 verfügbar wäre, es wird eine wirklich erstaunliche Ergänzung sein.
Für das Godot-Plugin und Addon-System.

Ich will niemanden unter Druck setzen. Also nimm es bitte nicht auf die Arbeit.

Ich habe ein komplett neues Backend für das benutzerdefinierte Typsystem implementiert. Das neue ermöglicht es Benutzern, alle ursprünglichen Funktionen auszuführen und es so zu gestalten, dass die Schaltfläche "Skript hinzufügen" ein neues Skript hinzufügt, das das benutzerdefinierte Skript standardmäßig erweitert (anstatt das benutzerdefinierte Skript zu öffnen) und es so macht Sie können das benutzerdefinierte Skript nicht entfernen (Sie müssten wie bei jedem anderen Engine-Typ den Befehl Change Type Editor verwenden).

@swarnimarun

Darüber hinaus wird es Benutzern ermöglichen, Typen in einer globalen Datei zu registrieren, die Zugriff auf Zuordnungen von Typnamen zu Dateipfaden bietet. GDScript kann diese Zuordnungen als im Wesentlichen einfache globale Typnamen wahrnehmen. Außerdem müssen Typen keine benutzerdefinierten Typen sein, um registriert zu werden, und die Typen können entweder Skripte oder Szenen sein.

Bisher habe ich das neue Backend implementiert und die ursprüngliche benutzerdefinierte Typskriptfunktion neu eingerichtet. Derzeit wird an neuen Funktionen gearbeitet. Ab jetzt wahrscheinlich in einer Woche. Ich bin diese Woche sonst beschäftigt.

@willnationsdev Keine Sorge, wenn es in 3.1 geht, bin ich zufrieden.
Und mir wurde klar, dass es ziemlich viel Arbeit sein könnte.
Mach weiter so.

Derzeit hat der Editor die Möglichkeit, das Skript eines beliebigen Knotens einfach zu erweitern:

extend

Der Knoten selbst sieht derzeit so aus:

2

Und @reduz 's Hauptanliegen war es, die Tatsache zu verbergen, dass bereits ein Skript angehängt ist. Einerseits ist es sinnvoll, das dem Nutzer nicht zu verheimlichen. Aber auf der anderen Seite werden benutzerdefinierte Knoten so ziemlich immer mit angehängten Skripten versehen sein. Ohne Skripte sind benutzerdefinierte Knoten nur vorhandene reguläre Knoten mit benutzerdefinierten Symbolen und ohne zusätzliche Funktionalität.

Und obwohl Sie das benutzerdefinierte Skript erweitern können, ist es sehr ärgerlich, dass einfache benutzerdefinierte Knoten genauso aussehen wie erweiterte benutzerdefinierte Knoten.

Hier ist also meine einfache Lösung: Wenn das Skript eines benutzerdefinierten Knotens dasselbe ist wie das Skript in der Definition des benutzerdefinierten Knotens, sollte das Skriptsymbol wie folgt ausgeblendet werden:

3

Bedeutung:

4

Leute, Beispiel aus dem wirklichen Leben: Wenn ich viele benutzerdefinierte Notizen der gleichen Art habe, jedes Skript für seine eigene Instanz angepasst, was passiert, wenn ich das benutzerdefinierte Basisknotenskript ändern möchte? Ich sage Ihnen: DAS SCHLECHTESTE, weil ich es UND alle anderen Instanzen entsprechend ändern muss, was zu einer hohen Wahrscheinlichkeit von menschlichen und Tippfehlern führt.

Sie wollen kein Skript verstecken? Gut, dann zeigen Sie das custom_node-Skript UND das Projektknotenskript.

@aaronfranke Meiner Meinung nach ist das die beste Lösung. Auch instanzierte Szenen könnten davon profitieren.

@zatherz et al, jetzt wo #30697 implementiert ist, was kann noch verbessert werden? Gibt es noch etwas in https://github.com/godotengine/godot/issues/6067#issuecomment -238250383, das wichtig ist?

Schließen wie durch #30697 behoben. Während der ursprüngliche Vorschlag im OP, der in https://github.com/godotengine/godot/issues/6067#issuecomment -238250383 ausgearbeitet wurde, nicht implementiert wurde, wird dies aufgrund der Bedenken von @reduz in https:// nicht geschehen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen