Godot: Mejores nodos EditorPlugin personalizados

Creado en 7 ago. 2016  ·  121Comentarios  ·  Fuente: godotengine/godot

Los nodos creados por la función add_custom_type en EditorPlugin tienen asignado el script seleccionado al agregarlos. Esto los hace casi inútiles, ya que solo puede usar las funciones definidas en ese script en otros nodos.

Esto es completamente diferente de otros nodos y hace que los complementos de nodos sean bastante inútiles/mucho más molestos de usar.

feature proposal plugin usability

Comentario más útil

Según tengo entendido, la expectativa es tener la posibilidad de crear nodos personalizados que se comporten como nodos incorporados, es decir, deben tener las siguientes características:

  • Icono personalizado, identificador personalizado
  • Instanciable a través del widget Agregar nodo (y supongo que a través de un script, ¿tan expuesto a Global Scope?)
  • Tener una API personalizada codificada a través de un script (por ejemplo RedNode2D extendería Node2D y tendría una modulación roja definida a través de un script personalizado)
  • Luego, este nodo personalizado debería comportarse como un nodo incorporado, es decir, el usuario debería poder instanciarlo sin ningún script (la API personalizada no estaría directamente expuesta al usuario, al igual que para el script incorporado donde está codificado). en C++) y adjunte un script que extienda el nodo personalizado (por ejemplo extends RedNode2D ).

Esa sería la expectativa "natural" al declarar un nodo personalizado y sería una característica muy poderosa; Deduzco de lo anterior que no funciona de esta manera hasta ahora, en parte debido a decisiones de diseño. Si hay una manera de tener una funcionalidad como la que describí anteriormente, estoy bastante seguro de que tendría muchas aplicaciones. La librería de activos estaría llena de nodos personalizados que hacen mucho trabajo desde el primer momento y se pueden usar como si estuvieran integrados.

Reapertura hasta que haya un consenso sobre lo que se puede/debe hacer o no.

Todos 121 comentarios

no entiendo lo que quieres decir

@reduz cuando agrega a la escena un nodo que es un tipo creado por un complemento, ya tiene adjunto el script del complemento. Por lo tanto, es imposible agregar otro script con un comportamiento personalizado.

Por supuesto que no, esto es por diseño central y no cambiará.

El 7 de agosto de 2016 a las 18:11, "George Marques" [email protected] escribió:

@reduz https://github.com/reduz cuando agregas a la escena un nodo que
tipo creado por un complemento, ya tiene adjunto el script del complemento. Entonces
es imposible agregar otro script con un comportamiento personalizado.


Estás recibiendo esto porque te mencionaron.

Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238108767 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z29F5q8PaoBv4OrzAUayzrfNjfHyZks5qdkoUgaJpZM4JejbZ
.

Esto es triste. Pero siempre puede agregar el script al padre o al hijo.

Cerrando como wontfix.

Puede que esté malinterpretando algo, pero si su tipo personalizado es un script,
¿Cómo no se incluirá en el nodo creado? no tiene sentido para
que sea diferente

El 7 de agosto de 2016 a las 21:52, "George Marques" [email protected] escribió:

Esto es triste. Pero siempre puede agregar el script al padre o al hijo.

Cerrando como wontfix.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238120392 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z27Zo4Ixvo4APSC4Fxf5ZqCJRsAxXks5qdn3igaJpZM4JejbZ
.

Supongo que necesitaría la capacidad de tener dos (o más) scripts por nodo, aunque esto realmente no tiene mucho sentido.

Godot originalmente apoyó esto, pero fue más un problema que una ventaja.

El 7 de agosto de 2016 a las 22:36, "George Marques" [email protected] escribió:

Supongo que necesitaría la capacidad de tener dos (o más) guiones por
nodo, aunque esto realmente no tiene mucho sentido.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238123729 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z27jidVZl-hHWW3G_ESr8Cqj3eX7Eks5qdogRgaJpZM4JejbZ
.

El problema es que los nodos personalizados son prácticamente inútiles, ya que en realidad no son "nodos personalizados", son solo nodos base con un script preestablecido y un ícono diferente.
Lo que esperaba de los "nodos personalizados" es que podría extender el nodo para usar lo que esté definido en el script. Escenario de ejemplo:
Tengo un nodo personalizado llamado Test que es hijo de Sprite y agrega una función test() que devuelve true . Luego, me gustaría crear un nuevo nodo de prueba, asignarle un script y usar la función test() .
Esto es imposible.

Supongo que volveré a la escena para heredar + secuencia de comandos para extender el combo entonces.

Bueno, ser un nodo preestablecido con un script preestablecido y un ícono diferente es IMO
suficiente de personalizado, pero si realmente quiere poner su propio código personalizado en
allí, siempre puedes heredar los que vienen con el nodo. Pudimos
haga esto un poco más fácil desde la interfaz de usuario si realmente lo desea.

El lunes 8 de agosto de 2016 a las 10:40 a.m., Dominik Banaszak [email protected]
escribió:

El problema es que los nodos personalizados son casi inútiles ya que en realidad no son
"nodos personalizados", son solo nodos base con un script preestablecido y diferentes
icono. Supongo que volveré a la escena para heredar + secuencia de comandos para extender el combo entonces.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238240130 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z27eHoXwgr6buF6CCAHfxwx1dKkCiks5qdzHhgaJpZM4JejbZ
.

Me encantaría que pudiera automatizarse o simplificarse a través de la interfaz de usuario.

Según tengo entendido, la expectativa es tener la posibilidad de crear nodos personalizados que se comporten como nodos incorporados, es decir, deben tener las siguientes características:

  • Icono personalizado, identificador personalizado
  • Instanciable a través del widget Agregar nodo (y supongo que a través de un script, ¿tan expuesto a Global Scope?)
  • Tener una API personalizada codificada a través de un script (por ejemplo RedNode2D extendería Node2D y tendría una modulación roja definida a través de un script personalizado)
  • Luego, este nodo personalizado debería comportarse como un nodo incorporado, es decir, el usuario debería poder instanciarlo sin ningún script (la API personalizada no estaría directamente expuesta al usuario, al igual que para el script incorporado donde está codificado). en C++) y adjunte un script que extienda el nodo personalizado (por ejemplo extends RedNode2D ).

Esa sería la expectativa "natural" al declarar un nodo personalizado y sería una característica muy poderosa; Deduzco de lo anterior que no funciona de esta manera hasta ahora, en parte debido a decisiones de diseño. Si hay una manera de tener una funcionalidad como la que describí anteriormente, estoy bastante seguro de que tendría muchas aplicaciones. La librería de activos estaría llena de nodos personalizados que hacen mucho trabajo desde el primer momento y se pueden usar como si estuvieran integrados.

Reapertura hasta que haya un consenso sobre lo que se puede/debe hacer o no.

+1
Este fue uno de los primeros obstáculos importantes para mí cuando intenté portar un proyecto existente de "OtherEngine(tm)" a Godot. Los tipos personalizados, como @akien-mga explicado anteriormente, deberían comportarse como cualquier otro tipo integrado después del registro.

Por favor, explique de qué manera cree que no lo hacen.

El 8 de agosto de 2016 a las 11:50 a. m., "Ralf Hölzemer" [email protected] escribió:

+1
Este fue uno de los primeros obstáculos importantes para mí cuando traté de portar un
proyecto existente de "OtherEngine(tm)" a Godot. Tipos personalizados, como
@akien-mga https://github.com/akien-mga explicado anteriormente, debería simplemente
comportarse como cualquier otro tipo incorporado después del registro.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238261603 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z25PJzv9w7iXO350tRF3FcEuYQYUKks5qd0IrgaJpZM4JejbZ
.

Como ya se dijo anteriormente, el mayor inconveniente en este momento es que los tipos personalizados son poco más que una forma rápida de instanciar el tipo base de ese script y asignar el script apropiado a esa instancia. Esto hace que sea imposible extender ese nodo en el editor con otra secuencia de comandos, como se puede hacer con los tipos integrados.

Pero también es imposible crear árboles de herencia con nodos personalizados en los cuadros de diálogo "Crear nuevo nodo/recurso" porque solo aparecen en estos árboles cuando los registra con un tipo integrado como padre a través de add_custom_type.

Por ejemplo, supongamos que quiero heredar todos mis tipos personalizados en mi proyecto desde un solo tipo base.

base.gd

extends Node
export (Color) var color

tipo_a.gd

extends base.gd

tipo_b.gd

extends base.gd

Tal como está ahora, tengo que registrar esos tipos como este. En este caso, el segundo argumento de add_custom_type debe ser "Nodo", de lo contrario, no aparecerán en los cuadros de diálogo.

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"))

... Y este es el resultado.

add_node_flat

Si bien es bueno poder registrar tipos personalizados como este, los cuadros de diálogo no reflejan la naturaleza de la herencia de esos tipos como otros tipos integrados. Para cualquier tipo incorporado, puedo mirar ese árbol y ver de un vistazo con qué estoy tratando. Puedo, por ejemplo, estar seguro de que Sprite es un Node2D y, por lo tanto, hereda todas las funciones proporcionadas por Node2D. No ocurre lo mismo con los tipos personalizados.

Ahora, si los tipos personalizados pudieran registrarse completamente en el ámbito global, como @akien-mga mencionado anteriormente, las cosas serían mucho más simples de entender y usar.

En primer lugar, podría heredar de un tipo personalizado al que se hace referencia por nombre de tipo en lugar de la ruta/nombre del archivo.

base.gd

extends Node
export (Color) var color

tipo_a.gd

extends Base

tipo_b.gd

extends Base

... entonces, el registro de los tipos personalizados podría simplificarse así. Tenga en cuenta el segundo parámetro faltante de 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"))

... y obtendrá una visión general mucho más agradable en los cuadros de diálogo "Crear nuevo nodo/recurso":

add_node_tree

... y, por supuesto, la capacidad de extender esos tipos en el editor con un script personalizado:

custom_type_no_script

... que también sería referenciado por el nombre del tipo en lugar del nombre/ruta del script

extends Base

Aquí está el complemento de ejemplo de arriba para jugar.
complementos.zip

Oh, ya veo... estas dos cosas definitivamente deberían ser reparables, junto con
agregando soporte de herencia al diálogo de creación de scripts

El 8 de agosto de 2016 a las 13:54, "Ralf Hölzemer" [email protected] escribió:

Como ya se dijo anteriormente, el _mayor inconveniente_ en este momento es que
los tipos personalizados son poco más que una forma rápida de instanciar el tipo base
de ese script y asigne el script apropiado a esa instancia. Esta
hace imposible extender ese nodo en el editor con otro script -
como se puede hacer con los tipos integrados.

Pero también es imposible construir árboles de herencia con nodos personalizados en
los cuadros de diálogo "Crear nuevo nodo/recurso" porque solo aparecen en estos
árboles cuando los registra con un tipo incorporado como padre a través de
agregar_tipo_personalizado.

Por ejemplo, supongamos que quiero heredar todos mis tipos personalizados en mi
proyecto a partir de un solo tipo base.

_base.gd http://base.gd_

extiende el nodo
exportar (Color) var color

_tipo_a.gd http://tipo_a.gd_

extiende base.gd

_tipo_b.gd http://tipo_b.gd_

extiende base.gd

Tal como está ahora, tengo que registrar esos tipos como este. En esto
caso, el segundo argumento de add_custom_type tiene que ser "Nodo", de lo contrario
no aparecerán en los diálogos.

función _enter_tree():
add_custom_type("Base", "Nodo", precarga("base.gd"), precarga("base.png"))
add_custom_type("TipoA", "Nodo", precarga("tipo_a.gd"), precarga("tipo_a.png"))
add_custom_type("TipoB", "Nodo", precarga("tipo_b.gd"), precarga("tipo_b.png"))

... Y este es el resultado.

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

Si bien es bueno poder registrar tipos personalizados como este, el
los diálogos no reflejan la naturaleza de la herencia de esos tipos como
otros tipos incorporados. Para cualquier tipo incorporado, puedo mirar ese árbol y
ver de un vistazo lo que estoy tratando. Puedo, por ejemplo, estar seguro de que
Sprite _es un_ Nodo2D y por lo tanto hereda todas las funciones _proporcionadas
por_ Nodo2D. No ocurre lo mismo con los tipos personalizados.

Ahora, si los tipos personalizados pudieran registrarse completamente en el ámbito global, como
@akien-mga https://github.com/akien-mga mencionado anteriormente, las cosas
ser mucho más simple de entender y usar.

Primero, podría heredar de un tipo personalizado al que hace referencia _nombre de tipo_
en lugar de la ruta/nombre del archivo.

_base.gd http://base.gd_

extiende el nodo
exportar (Color) var color

_tipo_a.gd http://tipo_a.gd_

extiende la base

_tipo_b.gd http://tipo_b.gd_

extiende la base

... entonces, el registro de los tipos personalizados podría simplificarse como
esta. Tenga en cuenta el segundo parámetro faltante de add_custom_type.

función _enter_tree():
add_custom_type("Base", precarga("base.gd"), precarga("base.png"))
add_custom_type("TipoA", precarga("tipo_a.gd"), precarga("tipo_a.png"))
add_custom_type("TipoB", precarga("tipo_b.gd"), precarga("tipo_b.png"))

... y obtendría una visión general mucho más agradable en "Crear nuevo
Diálogos de nodo/recurso":

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

... y, por supuesto, la capacidad de extender esos tipos en el editor con un
guión personalizado:

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

... que también sería referenciado por _nombre de tipo_ en lugar de la secuencia de comandos
nombre/ruta

extiende la base

Aquí está el complemento de ejemplo de arriba para jugar.
complementos.zip https://github.com/godotengine/godot/files/407291/addons.zip


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238299152 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

Lo que nunca sucederá es que los scripts desaparezcan de los nodos instanciados, o
estar oculto, debe quedar claro que el nodo está programado, pero
agregarle un script aún permitirá reemplazar el script por uno que
hereda de ella

El 8 de agosto de 2016 a las 14:02, "Juan Linietsky" [email protected] escribió:

Oh, ya veo... estas dos cosas definitivamente deberían ser reparables, junto con
agregando soporte de herencia al diálogo de creación de scripts

El 8 de agosto de 2016 a las 13:54, "Ralf Hölzemer" [email protected] escribió:

Como ya se dijo anteriormente, el _mayor inconveniente_ en este momento es que
los tipos personalizados son poco más que una forma rápida de instanciar el tipo base
de ese script y asigne el script apropiado a esa instancia. Esta
hace imposible extender ese nodo en el editor con otro script -
como se puede hacer con los tipos integrados.

Pero también es imposible construir árboles de herencia con nodos personalizados en
los cuadros de diálogo "Crear nuevo nodo/recurso" porque solo aparecen en estos
árboles cuando los registra con un tipo incorporado como padre a través de
agregar_tipo_personalizado.

Por ejemplo, supongamos que quiero heredar todos mis tipos personalizados en mi
proyecto a partir de un solo tipo base.

_base.gd http://base.gd_

extiende el nodo
exportar (Color) var color

_tipo_a.gd http://tipo_a.gd_

extiende base.gd

_tipo_b.gd http://tipo_b.gd_

extiende base.gd

Tal como está ahora, tengo que registrar esos tipos como este. En esto
caso, el segundo argumento de add_custom_type tiene que ser "Nodo", de lo contrario
no aparecerán en los diálogos.

función _enter_tree():
add_custom_type("Base", "Nodo", precarga("base.gd"), precarga("base.png"))
add_custom_type("TipoA", "Nodo", precarga("tipo_a.gd"), precarga("tipo_a.png"))
add_custom_type("TipoB", "Nodo", precarga("tipo_b.gd"), precarga("tipo_b.png"))

... Y este es el resultado.

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

Si bien es bueno poder registrar tipos personalizados como este, el
los diálogos no reflejan la naturaleza de la herencia de esos tipos como
otros tipos incorporados. Para cualquier tipo incorporado, puedo mirar ese árbol y
ver de un vistazo lo que estoy tratando. Puedo, por ejemplo, estar seguro de que
Sprite _es un_ Nodo2D y por lo tanto hereda todas las funciones _proporcionadas
por_ Nodo2D. No ocurre lo mismo con los tipos personalizados.

Ahora, si los tipos personalizados pudieran registrarse completamente en el ámbito global,
como @akien-mga https://github.com/akien-mga mencionado anteriormente, cosas
sería mucho más simple de entender y usar.

Primero, podría heredar de un tipo personalizado al que hace referencia _nombre de tipo_
en lugar de la ruta/nombre del archivo.

_base.gd http://base.gd_

extiende el nodo
exportar (Color) var color

_tipo_a.gd http://tipo_a.gd_

extiende la base

_tipo_b.gd http://tipo_b.gd_

extiende la base

... entonces, el registro de los tipos personalizados podría simplificarse como
esta. Tenga en cuenta el segundo parámetro faltante de add_custom_type.

función _enter_tree():
add_custom_type("Base", precarga("base.gd"), precarga("base.png"))
add_custom_type("TipoA", precarga("tipo_a.gd"), precarga("tipo_a.png"))
add_custom_type("TipoB", precarga("tipo_b.gd"), precarga("tipo_b.png"))

... y obtendría una visión general mucho más agradable en "Crear nuevo
Diálogos de nodo/recurso":

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

... y, por supuesto, la capacidad de extender esos tipos en el editor con un
guión personalizado:

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

... que también sería referenciado por _nombre de tipo_ en lugar de la secuencia de comandos
nombre/ruta

extiende la base

Aquí está el complemento de ejemplo de arriba para jugar.
complementos.zip https://github.com/godotengine/godot/files/407291/addons.zip


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-238299152 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z20FQioFVkVcvhhbvDQ7jQKv5De7Hks5qd19QgaJpZM4JejbZ
.

@reduz
¿Hay alguna razón técnica para dejar en claro que el nodo tiene un script y, de ser así, tiene que ser un espacio de script ocupado?

Me parece una forma bastante torpe de indicar un tipo personalizado y creo que a nadie se le ocurriría la idea de que al reemplazar el script actual en un nodo, se obtiene un script que amplía el script que ya estaba allí. Esa no es la forma en que la extensión a través de un script funciona para los tipos base.

¿Y qué pasaría si el usuario borra ese campo de script? ¿El tipo personalizado vuelve al script anterior o vuelve completamente al tipo base? Una vez más, no creo que esto sea una buena idea.

En su lugar, podría indicarse simplemente como un tipo personalizado en el árbol de nodos o en el editor de propiedades a través de un color diferente, algún ícono u otra cosa, sin sacrificar la ranura de script vacía.

Lo que nunca sucederá es que las secuencias de comandos desaparezcan de los nodos instanciados o se oculten. Debe quedar claro que el nodo tiene secuencias de comandos, pero agregar una secuencia de comandos aún permitirá reemplazar la secuencia de comandos por una que herede de él.

El punto aquí es que el script que define el nodo personalizado _debería_ estar oculto, porque no es una propiedad del nodo _instanciado_ sino de su tipo. Por lo tanto, este script debería conferir propiedades al nodo personalizado, pero debería ser tan invisible para el usuario del nodo instanciado como lo son las clases C++ de los nodos integrados. Proporcionaría una API, pero no sería modificable, solo extensible. Al igual que cuando instancias un Sprite, no obtienes scenes/2d/sprite.cpp adjunto como el script del nodo instanciado, no deberías obtener my_custom_node.gd adjunto como el script modificable del nodo personalizado de la instancia.

Ahora, no sé si es técnicamente _posible_ en este momento, pero sería el caso de uso natural AFAIU. Si modifica la secuencia de comandos del tipo personalizado, modificaría el tipo en sí y, por lo tanto, afectaría a todas las instancias de este tipo. Pero los nodos instanciados que usan el tipo personalizado deben tener su propio script que extends CustomNode .

Creo que esa función necesitaría que Object tenga un puntero adicional al "tipo de script personalizado base", porque necesita esa información cuando desea eliminar un script de usuario (que en realidad debería reemplazarlo por el script base).
Una vez tengas eso, el resto es cuestión de incluirlo en todos los casos, ya que puede introducir numerosos efectos secundarios. Al final, solo habrá un guión adjunto, solo una forma diferente de manejarlo.
No soy un gran fanático de la herencia en general, pero así es como lo haría.

En realidad, ese puntero ni siquiera podría ser necesario. Marcar el script sería suficiente, por ejemplo, si agrega_custom_type() con un script, el motor puede establecer un indicador en la clase para que la información esté disponible, como "hey, esta clase de script es una extensión de tipo de motor". Eliminar una secuencia de comandos de usuario la reemplazaría con la primera clase de secuencia de comandos heredada marcada como "tipo personalizado" o la eliminaría si no hay ninguna.

Lo siento, estoy en contra de ocultar un script si el nodo tiene un script. ¿Cuál es el
punto de simular algo que no es?

El hecho de que tenga un script no significa que la ranura esté ocupada o que necesite un
segundo script, porque simplemente puede crear un nuevo script heredando el
existente.

Lo que podemos hacer, si está de acuerdo, es ocultar el icono del guión en el árbol de escenas si
el script asignado es el del tipo personalizado, y haga el script
El cuadro de diálogo de creación le ofrece automáticamente heredar al crear el script.
¿Sería esto suficiente?

El 10 de agosto de 2016 a las 23:01, "Marc" [email protected] escribió:

En realidad, ese puntero ni siquiera podría ser necesario. Marcar el guión sería
ser suficiente, por ejemplo, si agrega_custom_type() con un script, el motor
puede establecer una marca en la clase para que la información esté disponible, como "oye, esto
clase de secuencia de comandos es una extensión de tipo de motor". Eliminar una secuencia de comandos de usuario
luego reemplácelo con la primera clase de secuencia de comandos heredada marcada como "personalizada".
escriba", o elimínelo si no hay ninguno.


Estás recibiendo esto porque te mencionaron.

Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-239055986 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z2xLGOhgMk__ZoRW1neRu1aRb5Qr_ks5qeoJogaJpZM4JejbZ
.

@reduz Creo que eso sería lo suficientemente bueno :smile:

@reduz Estoy de acuerdo, y no dije que necesitamos un segundo guión. Me preguntaba qué sucedería si agrega un script que hereda el primero (el personalizado definido por el complemento), pero luego decide eliminarlo. ¿Entonces revertiría el nodo a un tipo de motor básico sin ningún script?

Supongo que de alguna manera podríamos hacerlo más fácil de usar en ese sentido.

El 11 de agosto de 2016 a las 06:10, "Marc" [email protected] escribió:

@reduz https://github.com/reduz Estoy de acuerdo, y no dije que necesitamos un
segundo guión. Me preguntaba qué pasaría si agregas un script
heredando el primero (el personalizado definido por el complemento), pero luego deciden
quitarlo Luego revertiría el nodo a un tipo de motor básico sin ningún tipo de
guion entonces?


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-239109334 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z26JUJ0gjaCFwlsIDsINWp3_nqliwks5qeubygaJpZM4JejbZ
.

Excavo la parte de las extensiones por el Tipo definido por el nodo en lugar de la ruta descrita en este comentario https://github.com/godotengine/godot/issues/6067#issuecomment -238299152.

Algunas sugerencias más para agregar:

  • node.get_type() en un tipo de complemento debería devolver el nombre del tipo.

Ejemplo:

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

node.get_type() should return "MyCustomNode" instead of "Node2D"
  • Un complemento podría extender otro complemento por su tipo

Ejemplo:
El usuario A crea un complemento para un notificador de visibilidad más preciso basado en Node2D
add_custom_type("PreciseNotifier", "Node2D", preload("precise_notifier.gd"), preload("icon.png"))

Luego, el usuario B desarrolla un complemento Trigger basado en el notificador preciso en OTRA carpeta de complementos con otra configuración.
add_custom_type("Trigger", "PreciseNotifier", preload("trigger.gd"), preload("icon.png"))
y en el script trigger.gd, también debería extenderlo con el nombre del tipo
extends PreciseAddon
Por supuesto, el usuario debe agregar ambos complementos para usar el activador.

Parece que un grupo quiere definir un tipo de nodo personalizado sin secuencia de comandos como uno que todavía se deriva del tipo de nodo personalizado en el que se basa, mientras que el otro grupo quiere definir ese mismo escenario como un nodo que ha vuelto a su base en- tipo de motor. Si bien pertenezco al primer grupo, también puedo ver el punto del último grupo con respecto a que el tipo personalizado todavía está "programado" y quiere dejarlo claro en la interfaz de usuario.

Entonces, un compromiso puede ser tener un botón de interfaz de usuario adicional en la fila del nodo en el panel del árbol de escenas junto a su ícono de secuencia de comandos con una especie de ícono de secuencia de comandos ++. Al hacer clic, pasaría por la típica ventana emergente "Crear un script" con un script que ya hereda del tipo personalizado, por ejemplo, extends Base o extends "Base" . El script definido se crearía y reemplazaría inmediatamente el script preestablecido. Por lo tanto, aún mostraría claramente que ya existe una secuencia de comandos en el nodo, pero también tendría una interfaz familiar para reemplazar fácilmente esa secuencia de comandos preestablecida.

Esta propuesta probablemente sería menos intuitiva, ya que todavía trata los nodos personalizados de manera algo diferente a sus contrapartes en el motor. ¿Pensamientos?

Dando mis 2 centavos más adelante en esta discusión, creo que el problema radica en el hecho de que varios nodos que heredan un complemento comparten el mismo script original de forma predeterminada; No me importa que la visibilidad del código, como argumentó Juan al comienzo de este hilo, es una elección de diseño y también algo importante para que el comportamiento del nodo sea transparente para el desarrollador que usa el complemento. Pero, por lo general, le gustaría cambiar el comportamiento de diferentes nodos en el código y, en este momento, la única forma de hacerlo es eliminando la referencia del script original, creando un nuevo script y copiando y pegando el código del script base. Ni siquiera puede save as la secuencia de comandos del nuevo nodo adicional en un nuevo archivo .gd, ya que esto cambiará la referencia a todos los demás nodos que usan la secuencia de comandos original, por lo que existe este copiar y pegar de tres pasos peculiaridad del procedimiento.

De nuevo, no es TAN complicado, es solo que en este caso particular, la opción save as en el editor GDScript no se comporta como esperaría, y creo que sería más amigable para la interfaz de usuario tener un ' copiar y guardar' en el editor de GDScript para permitir una rápida personalización de los complementos (y en cuanto a la arquitectura, hacer que este botón sea visible tiene sentido, ya que es un buen enfoque para crear juegos en Godot sin la necesidad de usar scripts heredados).

@henriquelalves Pensé que personalizar nodos personalizados en el código es básicamente herencia. Como, extends "addons/thing/thing.gd" ? El script heredado seguirá haciendo las mismas cosas que la versión adicional, dado que sabe lo que está anulando. No es necesario copiar/pegar.

@Zylann Tiene razón, pero por lo general no me gusta este enfoque en particular debido a la visibilidad del código y las peculiaridades de autocompletado (al menos en 2.1, no lo he probado hasta ahora). Y la mayoría de las veces no quiero anular métodos, solo cambiar cosas particulares que no son variables extendidas en el script adicional original. Eso es lo que me molesta del comportamiento actual save as , no puedo crear rápidamente la copia de un script sin cambiar cada referencia de nodo a dicho script; y resolver esto de una manera amigable con la interfaz de usuario resuelve el problema original de tener múltiples nodos para personalizar, además de tener visibilidad del código y demás (al menos en mi flujo de trabajo, puedo ser el único que piensa así jaja).

@henriquelalves bueno, no soporto copiar/pegar tbh xD Y también podría bifurcar el complemento con control de versiones y usarlo en su lugar en primer lugar.

@Zylann Bifurcar un complemento es agregar aún más pasos a algo que debería ser muy simple, jajaja. Supongo que me quedaré con copiar y pegar manualmente si esto no es una prioridad, aunque sigo pensando que el comportamiento save as es extraño.

@henriquelalves Copiar/pegar ES bifurcar ^^ pero si se hace sin control de versión, te morderá la espalda en el futuro si el complemento se actualiza.

El comportamiento actual de tener una secuencia de comandos adjunta al nodo personalizado casi no proporciona ningún beneficio de tener ese nodo personalizado como un complemento en lugar de simplemente adjuntar la secuencia de comandos al nodo. El único beneficio es que aparece en el cuadro de diálogo del nodo, que en realidad no es un beneficio en absoluto.

Estoy en el campamento que dice que un nodo personalizado debe comportarse como un tipo integrado de primer nivel. De lo contrario, ¿por qué molestarse en crear/usar un complemento para ello? ¿Solo para que pueda verlo en el cuadro de diálogo y no tener que hacer clic en el botón Agregar secuencia de comandos?

@RodeoMcCabe El problema es que, bajo el capó, los tipos personalizados siguen siendo secuencias de comandos en capas sobre un nodo en el motor en la práctica, y eso no se puede cambiar ya que los nodos de tipo personalizado no se compilan directamente en la fuente del motor. Lo que tenemos que hacer es formular un conjunto concreto de pasos/características que permitan a estos nodos programados simular , a los ojos del usuario, los comportamientos de un nodo en el motor. Por ejemplo...

  1. Agregar el nodo a la ventana "crear un nodo" (hecho)
  2. Permitir que el usuario proporcione una "breve descripción" textual del nodo para la ventana "crear un nodo" (¿no parece estar hecho? - al menos, no es parte de add_custom_type ).
  3. Permitir al usuario mostrar jerarquías de nodos y definir tipos personalizados abstractos en la ventana "crear un nodo". Esto probablemente implicaría agregar un bool a la función add_custom_type para saber si es un tipo abstracto o no. El asistente "Crear un nodo" debería actualizarse para bloquear la creación de tipos personalizados abstractos en consecuencia.
  4. Haga que el nodo PARECE como si NO TENGA un script.

    una. El nodo no debe tener un ícono de "guión en este nodo" en el panel Escena. Para hacer las cosas más transparentes, tal vez debería haber un icono de "este es un nodo de tipo personalizado" en su lugar. Hacer clic en eso podría llevar al usuario directamente al script agregado de tipo personalizado. Rompe la "inmersión", pero sería un sacrificio necesario por razones de usabilidad (obviamente, querrá poder mirar y ver cómo funciona un nodo de tipo personalizado, si lo desea).

    B. La propiedad de secuencia de comandos que se muestra en el Inspector debería, de forma predeterminada, mostrarse vacía, a menos que el usuario cargue una secuencia de comandos en ella, en cuyo caso la secuencia de comandos debe derivar del tipo de secuencia de comandos utilizado como tipo personalizado. Sin embargo, el usuario no debería tener que conocer la ubicación del archivo de secuencia de comandos del tipo personalizado (el concepto de que ES una secuencia de comandos debe estar oculto para ellos). Esto significa que el analizador GDScript debe reconocer el nombre de la cadena para la clase personalizada como las otras clases en el motor (no estoy seguro de cuán fácil/difícil sería) o debería haber algún tipo de función global para obtener el registro a través de el nombre de la clase, por ejemplo, para el script en add_custom_type("MyClass", "Node", load(res://addons/git-repo/api/my_class.gd), load(res://addons/git-repo/icons/icon_myclass.svg) , el usuario podría crear un script con extends MyClass o extends custom("MyClass") .

    C. Si un usuario carga una secuencia de comandos derivada de un tipo personalizado en el nodo, solo entonces debería aparecer el icono "este nodo tiene una secuencia de comandos" en el panel de escena.

  5. Cualquiera que sea el ícono del editor que se use para el script debe agregarse al bloque de categoría en lugar del ícono de cuadro blanco que se usa actualmente para los scripts (en property_editor.cpp ). Esto debería ser parte de la propiedad del diccionario __meta__ para el objeto de nodo de tipo personalizado.

  6. Cuando hace clic en "agregar un script" en un tipo personalizado, debe completar previamente el campo "Hereda" con cualquier método que se use en 4b.
  7. Si elimina una secuencia de comandos, la secuencia de comandos de tipo personalizado aún debe existir bajo el capó y NO eliminarse. Los nodos de tipo personalizado utilizarían efectivamente el script de tipo personalizado como un script de respaldo en los casos en que el script cargado se establece en nulo. Como tal, aún debería ver el ícono del editor de tipos base y las propiedades del script en el panel de Escenas del Editor y el panel de Inspector. Ya estoy en el proceso de fusionar una función para reemplazar "Variables de secuencia de comandos" con los nombres de las secuencias de comandos reales, aunque es probable que deba actualizarse si se agregan todos estos cambios.
  8. Object::get_script() debería devolver null para nodos con un script de tipo personalizado y sin script cargado.
  9. Object::get_property_list , y las funciones análogas para métodos y señales deben incluir el contenido del script de tipo personalizado incluso si no hay un script cargado.
  10. Es probable que se necesite una segunda función de objeto de C++ como Object::get_custom_script() o algo así para que el motor pueda ver si hay una secuencia de comandos, incluso si el lado de la secuencia de comandos no tiene conocimiento de esta segunda secuencia de comandos.
  11. Los intentos de cargar un script derivado de un tipo no personalizado en un Objeto deberían fallar limpiamente e informar un error (probablemente un bool de referencia &is_valid en la función asociada) para confirmar si el Objeto puede hacerlo. Los escenarios asociados del Editor Godot que deben proporcionar comentarios sobre esta información también deberían actualizarse para tener esto en cuenta.

Esto es solo rascar la superficie, pero creo que el tipo de comportamiento que buscan los usuarios es así de extenso (así que es bastante intenso). Queremos que la existencia de tipos personalizados sea accesible si es necesario (así que tenga el ícono de tipo personalizado en el panel Escena en la fila del nodo para ver su secuencia de comandos), pero también queremos ocultar su existencia tanto como sea posible para que podamos percibir ellos como tipos en el motor. Tomará mucho trabajo hacerlo bien, ya que probablemente romperá cosas en MUCHOS lugares.

¿Algo de esto suena bien? Estoy seguro de que hay más elementos que me faltan ya que solo lo estoy pensando un poco. Si esto suena loco, házmelo saber. ;-)

Editar: ah, pero la sugerencia de reduz de simplemente ocultar el ícono del script en el panel de escena si el script coincide con el script de tipo personalizado también podría ser valioso. Solo que el método get_script() aún no debería devolver nada. ¿Quizás haya una manera de hacerlo sin tener que crear una propiedad de script separada en el Objeto mismo? No sé, porque ya hay muchas suposiciones en el código base para 1 secuencia de comandos por objeto, que creo que queremos mantener, pero que son difíciles de mantener con el concepto de secuencia de comandos custom_type .

Buenas sugerencias, bien pensadas. Creo que si todo esto se implementara, daría el comportamiento que estamos buscando, sin embargo, creo que romper la regla de 1 secuencia de comandos por nodo podría ser una mala noticia que podría resonar en muchas partes inesperadas del código. Tómalo con pinzas, ya que no conozco muy bien el código base y mi C++ es mediocre. Reduz declaró anteriormente que originalmente intentaron tener más de un script por nodo y "fue más problemático de lo que valió la pena", lo que me parece razonable.

Los puntos 1 a 4 son geniales y creo que se pueden lograr sin romper la regla de 1 guión. Los tipos personalizados abstractos obviamente no son un problema, ya que no puede crear instancias de ellos de todos modos y, por lo tanto, el usuario no puede agregarle un script en el editor. Sin embargo, es concebible que intenten hacerlo a través del código, por lo que se deben realizar las comprobaciones y los errores necesarios.

El punto 6 también es bueno, y aquí es donde creo que podemos salirnos con la nuestra. La creación de un nuevo script según el punto 6 cambiará el script actualmente adjunto al nodo personalizado al nuevo script (derivado). El antiguo script (base) se elimina del nodo. Dado que el nuevo script adjunto se deriva del original, se mantiene toda la funcionalidad. A menudo hago esto, donde tengo una clase base (abstracta o no) y adjunto scripts derivados a los nodos. La diferencia aquí es que la nueva secuencia de comandos podría tener que decir extends "res://addons/path/to/base-script.gd" en lugar de simplemente el nombre del nodo personalizado, porque el tipo personalizado ya no tiene esa secuencia de comandos adjunta... Aunque pensándolo bien, remove_custom_type() no se llamó, y el script adjunto aún se deriva del anterior, ¿así que tal vez esto no sea necesario? Por favor, aclare para mí en este punto.

Los puntos 7, 8 y 9 son buenos, y probablemente no demasiado difíciles manteniendo la regla de 1 guión. 10 no es necesario si mantenemos la regla de 1 guión. 11 es bueno, ya que así es como se comportan los nodos integrados si intenta adjuntarles un script que no amplíe el tipo de nodo.

En cualquier caso, parece mucho trabajo, y ya estamos en versión beta, así que supongo que esto será para 3.1 o incluso 3.2 (no he mirado la hoja de ruta recientemente).

@RodeoMcCabe Sí, esto definitivamente no sería para 3.0.

romper la regla de 1 secuencia de comandos por nodo podría ser una mala noticia que podría resonar en muchas partes inesperadas del código

Mis pensamientos exactamente. Estoy pensando en una interfaz pública en la que el Objeto es consciente de su secuencia de comandos de copia de seguridad personalizada, pero otros objetos no lo saben y simplemente perciben que el Objeto tiene una única secuencia de comandos. El truco estaría en editar el setter y el getter para la propiedad del script. El getter debe verificar si hay nulo. Si es nulo, debería devolver el script de respaldo en su lugar. El setter también debe verificar que cualquier script nuevo amplíe el script de respaldo, de lo contrario, debería informar una falla de alguna manera.

Los tipos personalizados abstractos obviamente no son un problema, ya que no puede crear instancias de ellos de todos modos y, por lo tanto, el usuario no puede agregarle un script en el editor.

No hay tipos abstractos en el lado de las secuencias de comandos (afaik). ¿Estás diciendo que sabes cómo hacer un guión abstracto? El método can_instance está expuesto al lado de las secuencias de comandos, pero todo lo que hace es verificar si la secuencia de comandos en sí es válida y, si es una herramienta, si ScriptServer tiene las secuencias de comandos habilitadas en este momento. No tiene nada que ver con la abstracción del tipo de guión, no lo creo.

Debe poder verificar si la clase es abstracta para que el método CreateDialog::_update_search sepa cuándo hacer que el texto esté atenuado/no seleccionable, etc.

FYI, creé un problema sobre la parte abstracta del problema (# 13401).

Creo que, en general, sería factible si solo agregamos un miembro privado backup_script al tipo Object y luego lo usamos para hacer las comprobaciones de propiedad script .

Lo que hago en mis nodos personalizados es heredar una secuencia de comandos base, que hace que la secuencia de comandos del nodo personalizado esté vacía de forma predeterminada...


La herencia automática afectará al complemento en sí, y no será posible hacer más de uno sin duplicar el complemento, ¿verdad?

Multiscript se agregó por segunda vez este año y fue fácil eliminarlo nuevamente (plantea múltiples problemas).


Permitir una escena como base para el nodo personalizado en lugar de una secuencia de comandos puede permitir que la raíz esté libre de secuencias de comandos.

Lo que hago en mis nodos personalizados es heredar una secuencia de comandos base, que hace que la secuencia de comandos del nodo personalizado esté vacía de forma predeterminada...

Lo siento, ¿estás diciendo que esto de alguna manera afecta la abstracción o alguna otra sugerencia que hice antes? No veo donde se conecta esto...

La herencia automática afectará al propio complemento y no será posible crear más de uno sin duplicar el complemento, ¿verdad?

¿Está tratando de decir que intentar incluir el complemento en la carpeta /addons/ dos veces y habilitar ambos en la sección Complemento de Configuración del proyecto causaría problemas de alguna manera (quiero decir, eso suena bastante normal si su complemento está agregando personalizado tipos. No se pueden definir varios tipos personalizados con el mismo nombre).

No estoy seguro de lo que quiere decir con "no será posible hacer más de uno sin duplicar el complemento". Puede crear varias instancias de un nodo de tipo personalizado muy bien (?) Ya que solo creará el nodo y adjuntará automáticamente el script de tipo personalizado definido. Mi sugerencia implicaría cambiar el proceso de creación de scripts de CreateDialog para hacer...

  1. Deje que el script integrado del nodo decida si el nodo se puede instanciar o no (resumen).
  2. Crear un tipo de nodo integrado.
  3. Establezca la secuencia de comandos personalizada como la propiedad backup_script del nodo (no expuesta a la API de secuencias de comandos).
  4. Deje que el propio código Object del nodo maneje la tarea de engañar a todos los demás para que vean backup_script como la propiedad oficial script del objeto.
  5. Actualice los metadatos del icono del editor
  6. Actualice los metadatos para la descripción breve (?)

...en vez de...

  1. Cree el nodo integrado.
  2. Adjunte el script de tipo personalizado como la propiedad script .
  3. actualice los metadatos para el icono del editor personalizado.

Multiscript se agregó por segunda vez este año y fue fácil eliminarlo nuevamente (plantea múltiples problemas).

Estoy de acuerdo. Creo que los objetos multiscripting serían una mala idea en este punto (y de todos modos ni siquiera es realmente necesario). Eso no es lo que estoy sugiriendo. A la vista del público, Object aún debería tener solo 1 secuencia de comandos, pero recomiendo tener una secuencia de comandos de respaldo disponible que asuma el rol de ser la secuencia de comandos (así que se asigna a la propiedad script ) siempre que la propiedad principal script se establezca en nulo/descargado, etc. Esto nos permitirá admitir "tipos personalizados" de manera más efectiva sin alterar la interfaz de la base de código hacia la clase Object. Entonces podemos tener un setter/getter dedicado para esta propiedad de script de respaldo que permite que el código (como el código que asigna scripts de tipo personalizado en CreateDialog ) agregue o elimine su existencia. De esta forma, se trata de una modificación opcional de cómo funciona la propiedad script y dará como resultado comparativamente menos cambios necesarios en el motor.

Creo que una nueva opción para el menú contextual en los nodos resolvería este problema "Reemplazar script por heredado", esto incluso podría tener un submenú con todos los scripts detectados que heredan del actual y un "Nuevo script" al final, al hacer clic en el nuevo script. El cuadro de diálogo debería mostrar la ruta del script en el campo "extiende".

¿No es más fácil y más transparente simplemente agregar una herramienta de edición de "Reemplazar y heredar script"? Quiero decir, esto es solo un problema porque cuando creamos un nodo adicional, esperamos que no tenga secuencias de comandos, pero los nodos adicionales son en realidad nodos personalizados que agrega al árbol Crear nodo, y el usuario debe saberlo. Desde una perspectiva de UX (aunque no soy un experto), no creo que debamos sacrificar la transparencia por conveniencia.

@MarianoGnu @henriquelalves Ninguno de los dos es realmente lo mismo. La implicación de un "tipo personalizado" es que está simulando un tipo de nodo en el motor. Eso implicaría que el script en sí no se puede eliminar. La funcionalidad que imbuye en el nodo está integrada en él, de la misma manera que no podría eliminar el Node2D-ness de un Node2D para que actúe como un Nodo puro.

La popular publicación de Akien que se votó arriba cubre detalles similares:

El punto aquí es que la secuencia de comandos que define el nodo personalizado debe ocultarse, porque no es una propiedad del nodo instanciado sino de su tipo. Por lo tanto, este script debería conferir propiedades al nodo personalizado, pero debería ser tan invisible para el usuario del nodo instanciado como lo son las clases C++ de los nodos integrados. Proporcionaría una API, pero no sería modificable, solo extensible.

Si creamos alguna herramienta de edición para facilitar el "reemplazo del script por cosas heredadas", sería genial, pero ninguna de las funciones debería poder ver las capas de la jerarquía del script en o debajo del script de tipo personalizado, ya que se supone que para simular el comportamiento "incorporado".

De hecho, para que el contenido sea accesible desde gdscript_parser y otro contenido de secuencias de comandos, puede ser mejor asegurarse de que la información de tipo personalizado esté incluida en el singleton ClassDB en lugar de solo EditorNode::get_editor_data().get_custom_types() ya que los módulos no tendrán acceso a esa información, pero realmente deberían tener acceso a ella.

No tengo ningún problema personal con la exposición del script, esto es realmente una cuestión de terminología y filosofía, de acuerdo con lo que mencionó, lo que podría hacerse es agregar una nueva clase a ClassDB y agregar una propiedad de script a esa clase en lugar de el nodo y la clase deben verificar que existe un script de métodos y llamarlos antes de llamar a su clase principal. Creo que es posible, pero rompería la compatibilidad con versiones anteriores si no se hace antes de RC1

@willnationsdev Ya veo, simplemente no estoy totalmente de acuerdo con que los tipos personalizados se traten como nodos en el motor. Para mí, la 'potencia' de Editor Addons radica en lo fácil que es crear un "paquete" de nodos personalizados y herramientas de edición y compartirlo a través de github; todas esas herramientas y nodos son, de hecho, solo escenas y guiones que puedes copiar y pegar, pero Godot proporciona la API Addon para facilitar esto. Cuando lo usé por primera vez, también esperaba que los complementos no tuvieran secuencias de comandos, pero solo porque el motor en sí parecía que los estaba tratando como nodos en el motor, y eso es un problema de UX, no arquitectónico. Lo que creo que corregiría esto es:

  1. Los tipos personalizados en el árbol Crear nodo se muestran con un color diferente (lo que indica claramente que son tipos personalizados).
  2. Cuando los agrega a su escena, el ícono del guión está allí, pero ligeramente transparente (lo que indica que tienen un guión predeterminado con ellos, pero que se pueden sustituir). Al hacer clic en el ícono de la secuencia de comandos, se mostraría la secuencia de comandos de tipo personalizado en el editor.
  3. El botón "Agregar secuencia de comandos" en los tipos personalizados completaría automáticamente la opción "Hereda" con la secuencia de comandos de tipo personalizado.

De nuevo, definitivamente no soy un experto, por lo que mi suposición original de Custom-Types != In-Engine Nodes podría ser incorrecta; Además, su solución es la más clara que vi en este hilo, por lo que entiendo totalmente si el desarrollo de Godot va de esa manera.

EDITAR: Lo leí de nuevo, y mi "solución" son básicamente tus primeros 6 pasos de solución, jajaja.

@henriquelalves @MarianoGnu Creo que sin duda sería necesaria una combinación de esos. Tener la clase de tipo personalizada agregada a ClassDB es imprescindible, en mi opinión. Me encantaron las tres sugerencias que tuviste Henrique. Especialmente la idea 2 (mucho mejor que mi sugerencia de icono de tipo personalizado por separado). Y estoy de acuerdo con usted en que debemos asegurarnos de que "QUÉ son los tipos personalizados" permanezca transparente hasta cierto punto. Siento que se debe mantener un equilibrio: las personas deberían poder entender si algo es un tipo personalizado Y lo que eso significa, pero también debemos hacer todo lo posible para que los tipos personalizados se sientan como tipos de motores.

@willnationsdev Tomé esto de assetlib, moví el código del nodo personalizado a un script "base":
colisión_ruta_2d-1-modificado.zip

El problema inmediato que veo es que el complemento carga el script, y ese script es único, si agrego otro nodo personalizado, tendrá _el mismo_ script.

Entonces, ¿qué significa un reemplazo de script para el complemento en ese caso? (tal vez nada, no estoy seguro).

Si no hay problemas para reemplazar una secuencia de comandos (el modo de herramienta puede no ser adecuado en algunos casos), el menú para nodos personalizados puede agregar una entrada de "extender secuencia de comandos personalizada" para realizar ese proceso de reemplazo.

@henriquelalves @eon-s Creo que estamos pensando lo mismo. Estoy de acuerdo con que esto sea un problema de UX más que nada. Hasta ahora soy partidario de este enfoque porque creo que mantiene las cosas lo más simples posible, lo que siempre es bueno en mi opinión.

Si no hay problemas para reemplazar una secuencia de comandos (el modo de herramienta puede no ser adecuado en algunos casos), el menú para nodos personalizados puede agregar una entrada de "extender secuencia de comandos personalizada" para realizar ese proceso de reemplazo.

Creo que dado que la secuencia de comandos de extensión tiene que heredar de la secuencia de comandos del complemento, reemplazarla no sería un problema. Pero, de nuevo, no estoy muy familiarizado con el código base. De todos modos, he dado mis 2 centavos, se lo dejaré a los verdaderos desarrolladores desde aquí;)

@willnationsdev Lo siento, me confundí con las cosas abstractas. Mis clases base "abstractas" simplemente tienen una declaración de impresión en _init() para decirme si lo instalé por accidente...

Solo para intervenir aquí, los tipos de nodos personalizados deben comportarse absolutamente como tipos de motores, incluida la configuración de un script personalizado, la capacidad de hacer referencia y heredar por nombre en GDScript y la incapacidad de eliminar el script base del tipo. Esto imita el comportamiento de los nodos implementados por el motor, promoviendo la consistencia interna y la facilidad de uso.

Con respecto a la cuestión de mostrar que es un nodo "personalizado", propongo que el nodo tenga una entrada en el menú desplegable del Inspector arriba de "Mostrar en ayuda" que muestre el archivo de script base del objeto. Desde el punto de vista del usuario y del desarrollador, debe saber que es un nodo personalizado con solo usarlo (¿quién más lo agregó al proyecto?), y el objetivo de los nodos "personalizados" (IMO) es permitir definir tipos en GDScript que son indistinguibles de los tipos de motores integrados.

@Web-eWorks De hecho, estoy trabajando en esto (en este mismo momento) y he terminado una parte decente (aunque todavía tengo un poco de camino por recorrer). Configuré un script de respaldo en la clase Object y creé almacenamiento para tipos personalizados en ClassDB junto con la actualización de los métodos EditorPlugin para usar la nueva API. Todavía tengo que hacer actualizaciones a las funciones de ClassDB relacionadas (cosas como can_instance y get_parent_class , etc.) y actualizar todas las cosas del Editor/CreateDialog.

@willnationsdev , debe tenerse en cuenta que registrarse en ClassDB también significa que las personas que crean complementos deben prefijar sus clases para evitar colisiones ^^"

@Zylann Sí, eso sería necesario, desafortunadamente.

En este punto, creo que he solucionado la mayoría de los enlaces y los cambios principales. Solo es cuestión de actualizar ahora las clases Editor, CreateDialog y EditorHelp/DocData (y el compilador GDScript).

Como mencioné antes... Sigo sin pensar que la solución propuesta sea buena.
Por favor, consulte conmigo antes de intentar algo que probablemente será
rechazado.

El 7 de febrero de 2018 a las 20:05, "Naciones de voluntad" [email protected] escribió:

@Zylann https://github.com/zylann Sí, eso sería necesario,
Desafortunadamente.

En este punto, creo que he solucionado la mayoría de los enlaces y el núcleo.
cambios. Solo es cuestión de actualizar el Editor, CreateDialog y
Clases EditorHelp / DocData ahora.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363893711 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z2xIYRcs0BFDqTyiFwqlhQWTqjEZtks5tSgIVgaJpZM4JejbZ
.

@reduz Bueno, he estado tratando de tener en cuenta las preocupaciones que expuso anteriormente.

No estoy implementando ningún tipo de sistema de múltiples scripts. Tampoco estoy haciendo scripts enmascarados como objetos ClassInfo en ClassDB. Todo lo que he hecho hasta ahora es adjuntar un script (a través de RefPtr) a las jerarquías de herencia en ClassDB. La clase Object solo usará un "backup_script" siempre que la asignación de script regular intente infringir la jerarquía de herencia del script de respaldo.

Oh, ya veo ... ¿cuál es el caso de uso para esto entonces?

El 7 de febrero de 2018 a las 20:32, "Naciones de voluntad" [email protected] escribió:

@reduz https://github.com/reduz Bueno, he estado tratando de tomar en
en cuenta las preocupaciones que expuso anteriormente.

No estoy implementando ningún tipo de sistema de múltiples scripts. yo tampoco lo soy
hacer que los scripts se enmascaren como objetos ClassInfo en ClassDB. todo lo que tengo
hecho hasta ahora es adjuntar un script (a través de RefPtr) a la herencia
jerarquías en ClassDB. La clase Object solo usará un
"backup_script" cada vez que la asignación de secuencia de comandos regular intenta infringir
en la jerarquía de herencia del script de copia de seguridad.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363900920 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z2yn68Iy6AgAKJHZ4qImH4UBAm5skks5tSghSgaJpZM4JejbZ
.

El caso de uso es para cuando alguien desea introducir un nuevo tipo de nodo en el motor utilizando un EditorPlugin, pero no desea que el tipo de secuencia de comandos de ese nodo sea editable (quiere que la interacción con él imite un tipo en el motor ). Entonces, por ejemplo, si intento get_script() en un nodo con solo su secuencia de comandos de respaldo, devolverá un valor nulo. Si intento set_script(null) , la secuencia de comandos se establece en la secuencia de comandos de copia de seguridad. Si intento set_script(a_script) , solo asignará correctamente el script si el nuevo script está en la jerarquía de herencia del script de respaldo.

Para UX, planeo hacer que el ícono del script aparezca en el editor como un ícono transparente si solo está presente el script de respaldo. En ese caso, el botón para agregar una secuencia de comandos seguirá siendo un botón de "agregar una secuencia de comandos" en lugar de un botón de "eliminar secuencia de comandos", y al hacer clic en él se rellenará automáticamente el texto con el nombre del tipo (aunque es posible que deba hacer se rellena automáticamente con la ruta del script si el usuario cambia el tipo de script fuera de GDScript/VisualScript, etc.). Una vez que se haya asignado una secuencia de comandos diferente, el icono transparente volverá a ser opaco. Al hacer clic en el ícono de la secuencia de comandos en cualquier caso, accederá al código fuente de la secuencia de comandos activa (el código fuente de la secuencia de comandos de respaldo si no hay otra secuencia de comandos presente).

Tengo que admitir que realmente no veo el beneficio de esto, así que, de nuevo, ¿cuál es el
casos de uso específicos en los que está pensando?

El 7 de febrero de 2018 a las 20:46, "Naciones de voluntad" [email protected] escribió:

El caso de uso es para cuando alguien desea introducir un nuevo tipo de Nodo para
el motor usando un EditorPlugin, pero no desean el tipo de guión de
ese nodo sea editable (quieren que la interacción con él imite un
tipo en el motor). Entonces, por ejemplo, si intento get_script() en un nodo
con solo su script de respaldo, entonces devolverá nulo. si intento
set_script(null), luego el script se establece en el script de copia de seguridad. Si yo
intente set_script(a_script), entonces solo asignará con éxito
el script si el nuevo script está en la jerarquía de herencia de la copia de seguridad
texto.

Para UX, planeo hacer que el ícono del script aparezca en el editor como un
icono transparente si solo está presente el script de copia de seguridad. En ese caso, el
botón para agregar un script seguirá siendo un botón "agregar un script" en lugar de un botón
botón "eliminar secuencia de comandos", y al hacer clic en él se rellenará automáticamente el texto con el nombre
del tipo (aunque es posible que deba hacer que se complete previamente con la ruta del script
si el usuario cambia el tipo de secuencia de comandos fuera de GDScript/VisualScript,
etc). Una vez que se ha asignado un script diferente, el icono transparente
volvería a ser opaco. Al hacer clic en el ícono del script en cualquier caso,
lo llevará al código fuente del script activo (el código fuente del script de respaldo si
ningún otro guión está presente).


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/godotengine/godot/issues/6067#issuecomment-363904934 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AF-Z26oeOMT4HpjzDsX8eygMSeUhbTgVks5tSgurgaJpZM4JejbZ
.

El caso de uso de alto nivel es permitir que los complementos (EditorPlugins, el sistema PluginScript/SubModule) definan tipos de nodos personalizados "infalibles". Actualmente, el sistema de tipos personalizados es una pequeña fábrica de "secuencias de comandos en un nodo", que tiene numerosos problemas de flujo de trabajo y usabilidad si está intentando crear nuevos tipos de nodos, el menor de los cuales es la incapacidad total para crear de forma fácil, intuitiva y eficaz. extienda el nodo personalizado con código de juego (al contrario de los nodos integrados). Un problema más apremiante es la incapacidad de crear nodos personalizados que heredan de otros nodos personalizados.

Algunos casos de uso específicos son para crear nodos de bajo nivel: tal vez una implementación de GridMap voxel basada en cubos de marcha para terreno destructible, al estilo Minecraft o cualquier otro sistema de terreno que use cubos de marcha/contorno dual; tipos de control personalizados (contenedor de menú circular, como se implementa en muchos juegos modernos, cualquier tipo de control de bajo nivel que sea lo suficientemente alto como para estar fuera de la especificación del motor); y cualquier lugar donde desee crear un complemento que registre nuevos nodos. En cada uno de estos casos, por lo general desea agregar un script personalizado para manejar el código del juego y que esté separado del código de "implementación" (escrito en GDScript/GDNative).

Creo que lo que no se comunica aquí es que el objetivo es hacer que los nodos personalizados se comporten como nodos de motor sin tener que escribir un módulo de motor y compilar contra él.

Esta mejora no está necesariamente impulsada por una característica específica (aunque hay muchas), sino más bien por la razón de que "el camino actual es atrasado, endeble y tedioso". Si se implementa por completo, este sistema permitiría un método extremadamente poderoso para extender los tipos integrados del motor desde GDScript/GDNative sin necesidad de volver a compilar el motor. Desde el punto de vista del diseño, esto es literalmente una mejora directa sobre el sistema actual.

Si desea un caso de uso particular después de todo eso: todo el ecosistema plugin/AssetLibrary .
Ese es el alcance de lo que se beneficia de este cambio.

Ok, entonces aquí hay un ejemplo explícito:

Tengo un complemento en el que estoy trabajando, godot-skills , que presenta una variedad de nuevos tipos de nodos:

Efecto: nodificación de un Functor
Targeter: similar, pero solo encuentra y recopila otros nodos
Habilidad: combina jerarquías de objetivos y efectos para encontrar nodos y aplicarles efectos a todos
SkillUser: "posee" varias Habilidades

Me gustaría que cada uno de estos nodos sea algo que los usuarios puedan crear y agregar a una escena directamente. Sin embargo, todos y cada uno de estos nodos están diseñados para servir como tipo base. No tienen mucha funcionalidad lista para usar y deben tener un script derivado colocado en cualquier nodo en el que de otro modo estarían involucrados. Para casos de uso como estos, puede ser útil crear un nodo desde el cual no desea que el usuario pueda eliminar un conjunto particular de funciones con secuencias de comandos. Por ejemplo, quiero evitar que los usuarios coloquen un script que no derive de Targeter en cualquier nodo de Targeter que agreguen a su escena. Esto se debe a que Skills obtiene una funcionalidad instantánea al tener Targeters como hijos (similar a los nodos Area2D y CollisionShape2D).

El flujo de trabajo actual requiere que los usuarios...

  1. Agregar un nodo de tipo personalizado
    2a. Elimine la secuencia de comandos adjunta y haga clic en el botón Agregar una secuencia de comandos O
    2b. Establecer la propiedad del script en el nodo
  2. Busque en la ventana de diálogo donde EditorPlugin guarda el script de tipo personalizado que desea derivar.

Este sistema le permitiría reemplazar todo esto con solo:

  1. Agregue un tipo de nodo personalizado.
  2. Agregar como script (que automáticamente comienza a derivar el script de tipo personalizado)

Los usuarios podrían agregar dinámicamente sus propios tipos personalizados que derivan de los tipos en el motor (para una usabilidad más simple). También reforzaría la seguridad de la funcionalidad del complemento al imponer la presencia de la funcionalidad del script en el nodo en cuestión. Actualmente, los usuarios pueden eliminar fácilmente el script y romper cosas (no deseable). Además, si alguien quiere "borrar" el script en el nodo, entonces ese nodo no debería perder su funcionalidad de tipo personalizado (esta es una grande). Debería volver a tener el script de tipo personalizado.

Ok, entonces una actualización. Actualmente tengo lo siguiente.

  • El ClassDB ahora puede agregar y eliminar tipos personalizados directamente.
  • El EditorPlugin tiene métodos de tipo personalizado similares que agregan y eliminan no solo el tipo personalizado, sino también otros datos relacionados con el editor, como el icono. Estos métodos están conectados a una nueva señal que se emite cada vez que EditorPlugin se activa/desactiva.
  • GDScripts ahora puede heredar correctamente directamente de los nombres de los tipos personalizados para heredar del script.
  • El panel de escena creará un icono de secuencia de comandos transparente cuando la secuencia de comandos actual coincida con la secuencia de comandos de tipo personalizado del nodo. Al hacer clic en él, se abrirá el script de tipo personalizado en el editor. Mientras está en este estado, se muestra el botón "agregar un script" en lugar de "eliminar un script". Si se selecciona, este botón rellenará automáticamente el campo "Hereda" con el nombre del script de tipo personalizado (si no es nulo).
  • Cualquier intento de eliminar una secuencia de comandos hará que la secuencia de comandos de tipo personalizado se vuelva a asignar como el valor de la secuencia de comandos. Como tal, para eliminar el script, primero debe borrar el valor del script de tipo personalizado con set_custom_script(RefPtr()); .
  • El cuadro de diálogo Crear un nodo muestra correctamente las relaciones de herencia y los nodos abstractos para los tipos personalizados.
  • El archivo project.godot se completa con todos los tipos personalizados para que los juegos ejecutados puedan configurarlos en main.cpp antes de que comience el resto del juego.

Tareas pendientes por completar...

  • Permita que los usuarios generen documentos de API de clase para tipos personalizados.
  • Solucione un error por separado que impide que los usuarios editen el campo Inherits en script_create_dialog.cpp .
  • Encuentre una manera de agregar y eliminar dinámicamente tipos personalizados del mapa/matriz global de GDScript *
  • Implementar compatibilidad con tipos personalizados en VisualScript

* De hecho, tengo algunas preguntas sobre esto.

En primer lugar, solo veo add_global_constant / _add_global en el archivo gdscript_compiler.cpp sin ninguna forma de eliminar globales de la clase GDScriptLanguage. ¿Simplemente se reinicializa por completo cada vez que se agregan o eliminan singletons? ¿Cómo se editan dinámicamente los identificadores globales? Esto sería para que los usuarios puedan hacer MyNode.static_func() sin tener que cargar primero el script en una variable.

Mientras estoy en eso, siento que el GDScript de Godot podría beneficiarse enormemente de la introducción del espacio de nombres, especialmente como parte de este cambio. Tendríamos que encontrar el delimitador correcto para marcarlos, pero podría eliminar las preocupaciones sobre las colisiones de nombres de los tipos de motores y complementos al crear sus propios scripts. Por ejemplo, suponiendo que \ es el delimitador elegido...

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

De todos modos, todo esto ^ son solo ideas que se están lanzando en este momento. Si se introdujera el espacio de nombres, incluso podría asociar secuencias de comandos automáticamente con un nombre en función de su nombre de archivo mediante la señal resource_saved en EditorNode . NO SERÍAN necesariamente tipos personalizados (en el sentido de que no puede eliminar el script del objeto), pero SÍ SERÍAN accesibles solo por su nombre, lo que sería extremadamente útil e intuitivo. Los scripts podrían incluso anular el nombre automático predeterminado ( filename.capitalize().replace(" ", "") ?) proporcionando un título con espacio de nombres en la parte superior, por ejemplo, \MyPlugin\mynode . Ahora, de repente, "\MyPlugin\mynode" es un identificador global para ese script.

Aquí hay un fragmento de mi progreso hasta ahora.

@willnationsdev por favor no elija \ , ya se usa para escape y multilínea. . , : o :: se ven mejor.

@Zylann Planeé usar el delimitador como prefijo para cualquier nodo que se agregue al proyecto también. Entonces, por ejemplo, un script en res://container.gd no querría tener colisiones con la clase real Container . Si usamos un punto (.), entonces podría verse así.

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

¿Alguien tiene objeciones a ese tipo de formato?

Editar:

Eso podría tener problemas dentro de las funciones de clase derivadas, aunque llamen al método principal dentro de ellas:

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

Hmm... ¿eso plantea un problema para constantes y/o variables? De lo contrario, podemos asumir que los paréntesis significan que es una superfunción y, de lo contrario, es un posible identificador de espacio de nombres.

Honestamente, esperaría el espacio de nombres por ahora; podría introducirse más tarde, y preferiría tener el sistema actual lo antes posible. También necesitaríamos un sistema _realmente_ bien pensado para el registro automático de nombres, que posiblemente se extienda a una reelaboración de toda la estructura organizativa adicional, lo cual es una buena cantidad de trabajo y está más allá del alcance de este número.

Personalmente, prefiero que el nombre de un script 'registrado automáticamente' sea controlado por una declaración en el archivo, es decir

register <NAME> extends <PARENT>

o una sintaxis similar basada en el prólogo actual extend <NAME> que ya está presente para GDScript.

EDITAR: También quería preguntar cómo se manejará la asignación de scripts que se derivan de un padre (digamos Spatial) a un hijo personalizado (digamos Sprite3D-> CustomType). Esto ya funciona para los tipos de motores, y restringir los scripts asignados para que se deriven del propio tipo personalizado no funcionará muy bien.

@Web-eWorks Bastante justo. Trabajaré para perfeccionar la API actual y luego abriré un nuevo problema para el espacio de nombres una vez que se envíe el PR.

Si entiendo bien lo que significa @Web-eWorks, todavía tengo esta pregunta: ¿cómo evitará el hecho de que un Object solo puede tener un único script? ¿Cómo serán... "scriptables"? Porque aparte de eso, registrarse en ClassDB no es más que un identificador global en términos de uso para programadores y diseñadores.

@Zylann Lo que hice en mi bifurcación es crear una propiedad custom_script para Object . Solo se vuelve significativo si se le asigna un valor, pero si se le asigna una secuencia de comandos, entonces sirve como una secuencia de comandos de respaldo/restricción sobre cuál puede ser la propiedad principal script . Al borrar script , se establecerá en custom_script , y si asigna un nuevo Script a script , solo se asignará correctamente si el Script La instancia custom_script . Y todo esto es administrado por Object detrás de escena, por lo que en lo que respecta al motor, Object todavía tienen solo 1 script real.

El contenido de ClassDB solo tiene un mapa secundario de tipos personalizados que se registran, asignando el script en sí y alguna otra información al nombre que le asignó. Luego proporciona ese nombre y su jerarquía de herencia con métodos de herencia relacionados ( get_class_list , is_parent_class , get_parent , etc.). Y esto se hace como un indicador de aceptación para algunos de los métodos. get_class_list ahora tomará una bandera bool donde solo incluye tipos personalizados si pasa true como segundo parámetro. Así evita romper la compatibilidad con el resto del motor.

@willnationsdev entonces, con un sistema que hace que los scripts se comporten como clases integradas, ¿qué impide que los usuarios deseen que todos sus scripts y complementos se consideren ciudadanos de primera clase como las clases integradas y abandonen la "vieja escuela"?

ah La forma en que funcionan actualmente los scripts es que puede poner un script que extends Node en un VBoxContainer y aún funciona bien. Si la implementación actual rompe ese comportamiento para los tipos personalizados, habrá algunos problemas: ¿hay alguna forma de mantener el comportamiento del script personalizado mientras se tiene un script 'normal' que se deriva directamente de un tipo de motor?

@Zylann Esa es precisamente la razón por la que quiero introducir el espacio de nombres para que las secuencias de comandos y las secuencias de comandos de los complementos se puedan integrar de manera segura a través de nombres sin colisionar con los tipos en el motor. No habría nada que impidiera que las personas usaran solo la nueva forma e ignoraran la antigua. Y de hecho creo que sería mejor en general. Es laborioso tener que usar una ruta explícita cada vez.

@Web-eWorks No estoy seguro si estoy siguiendo aquí, pero...

Los tipos personalizados funcionan específicamente como tipos en el motor para la herencia. Entonces, si se extiende desde un tipo personalizado, será como si se estuviera extendiendo desde una rama completamente diferente de la jerarquía en el motor. Ex. si creo un tipo personalizado MyNode que extienda Node , no podré poner ese script en un VBoxContainer al igual que no puedo poner un Node2D "en" un VBoxContainer . Este sería en realidad el comportamiento previsto.

Ahora, con el concepto de espacio de nombres, lo ideal sería tener scripts con nombre que NO sean tipos personalizados. Entonces, en ese caso, podría crear un script que extienda Node y ponerlo en Node , VBoxContainer Y MyNode . ¿Tiene sentido?

Entonces, lo que estoy diciendo es que si crea un tipo personalizado MyNode que hereda, por ejemplo, MeshInstance , instancia un nodo en el editor e intenta agregar un script que hereda Spatial al nodo escrito MyNode , ¿funcionará correctamente? Funciona correctamente con nodos de 'motor', y ese es el comportamiento que debemos emular.

Debe ser independiente del espacio de nombres, ya que esto es más una cuestión de asegurarse de que se llame a la secuencia de comandos del tipo personalizado independientemente del punto en la jerarquía de herencia de la secuencia de comandos de 'nivel de usuario'.

@ Web-eWorks Sí, eso funcionaría. Cada entrada de "primer nivel" en el mapa custom_types ClassDB que volver a vincularse con un tipo en el mapa classes ; de lo contrario, se producirá un error y el tipo personalizado no no creado Esto garantiza que la cadena de herencia se conserve al pasar de los tipos personalizados a los tipos de motor hasta Object .

@willnationsdev Solo para estar seguro: si agrega un método _ready en MyNode y un nodo listo en su script de usuario que se deriva de Spatial, se llamará como Spatial._ready(), MeshInstance._ready(), MyNode._ready(), script._ready() ? (O cualquier pedido en el que se envíe _ready ).

Todavía mantengo mi opinión de que esto es innecesario y confuso. Este problema debe resolverse desde la interfaz de usuario del editor, no desde el motor central.

@reduz Sin embargo, esto no es algo que se pueda resolver solo desde la interfaz de usuario del Editor. No si desea controlar la manipulación de los usuarios de la secuencia de comandos en el objeto. Me parece que esa es una característica que muchas personas quieren tener configurada.

¿Está sugiriendo que gdscript_compiler debería hacer referencia al contenido en EditorData para configurar nuevos identificadores globales para los tipos de secuencias de comandos, en lugar de rastrearlos a todos en ClassDB y permitir que ClassDB administre toda la información de herencia en el motor?

Ciertamente, hay una parte que debe resolverse desde la perspectiva de la interfaz de usuario del editor, pero también hay una parte que debe resolverse en el núcleo. Agregar tipos personalizados al motor, tipos _reales_ desde la perspectiva de ClassDB, es una característica muy poderosa y, en última instancia, necesaria. En cuanto a la confusión, sigo manteniendo que no es más confuso que el sistema actual, y muy probablemente menos.

@Web-eWorks Estoy de acuerdo. En mi opinión, hacer un seguimiento de los datos heredados en el editor sería mucho más confuso. Y daría como resultado soluciones extrañas, ya que ese tipo de información ya no existiría una vez que ejecutes el juego sin el editor (por lo que tuve que comenzar a cargar la información en project.godot para poder cargarla en ClassDB en el inicio. No EditorPlugins para agregar los tipos personalizados estaba causando que GDScripts fallara en la compilación al ejecutar la escena).

@Web-eWorks Y para responder a su pregunta anterior, sí, funciona correctamente.

En mi escenario de prueba, tengo Node.gd que se extiende GDSkillsEffect > GDSkillsAPI > Node , y los métodos _ready implementados en cada secuencia de comandos se activan en la forma adecuada orden: API, Efecto, Node.gd.

Actualmente estoy experimentando un error de bucle infinito de algún tipo, aunque cada vez que dos scripts intentan heredar de los scripts de tipo personalizado por nombre. Ex. si Node.gd tiene extends GDSkillsEffect y gdskills_effect.gd tiene extends GDSkillsAPI , intentar modificar y guardar gdskills_effect.gd o gdskills_api.gd hará que el editor infinitamente "cargar" y luego fallar. Ese es probablemente mi mayor error en este momento.

@willnationsdev Ahh, no, estoy hablando de Node.gd extendiendo Node , _no_ GDSkillsEffect . Si _eso_ funciona, entonces todo está bien.

Por ejemplo, aquí hay una representación del árbol de escena:

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

@ Web-eWorks Ah, ya veo lo que quieres decir. Bueno, DEBERÍA funcionar, pero lo acabo de probar y parece que mi lógica en Object::set_script() lo está bloqueando por algún motivo, así que es un error que tendré que corregir. XD Está fallando porque ha detectado que Node no deriva el script de tipo personalizado (lo cual es cierto, sí), pero no debería fallar en ese caso, lol.

@Web-eWorks Como mencioné, esto NO es algo que deba cambiarse en ClassDB.

Realmente no creo que esto deba resolverse en el núcleo, ya que cada lenguaje de secuencias de comandos lo maneja de manera diferente. Puede crear fácilmente una nueva clase en Mono y funcionará. Para GDScript puede ser un caso simple de exponer un archivo de secuencia de comandos como global precargado y eso es todo. Una solución única para todos, como se propone en el PR, definitivamente no es el camino a seguir.

@willnationsdev Agradezco su esfuerzo, pero esto ya se discutió sin fin y el consenso es que:

  • Agregar un tipo personalizado es diferente para cada lenguaje de script, por lo que piratear algo en ClassDB, que en realidad solo está destinado a registrar cosas de C ++, NO es el camino a seguir.
  • Antes de llegar a tales extremos, podemos mejorar la usabilidad de la interfaz de usuario para los casos en los que desea extender la secuencia de comandos de un nodo personalizado, por lo que solo crea una herencia simple.
  • En general, agregar trucos al motor central para manejar casos de esquina nunca es el camino a seguir. Core debe permanecer libre de piratería.

@willnationsdev Como referencia, el comportamiento del motor es que cualquier secuencia de comandos que extienda _algo_ igual o anterior en la jerarquía de herencia se puede agregar a un nodo. Por lo tanto, un script que extends Spatial se puede agregar a MeshInstance pero no a Control o Node , ya que ninguno de estos últimos es ni hereda de Spatial . Este es un comportamiento que debe ser replicado. (Sin presión...)

@reduz ¿Pero la creación de una nueva clase en Mono la agrega a la jerarquía de herencia del motor? ¿O el cuadro de diálogo Crear nodo del editor? Quizá sea necesario abrir un nuevo número que diga de manera concisa cuál es el propósito de esto, porque creo que aquí no estamos hablando de lo mismo.

El objetivo de las modificaciones de ClassDB es permitir registrar nuevos tipos de Nodos (o Recursos) sin necesidad de volver a compilar el motor. No agregar nuevos globales personalizados en GDScript, aunque ese es un problema tangencial en el que @willnationsdev está trabajando en la misma rama.

El objetivo de esto no es agregar hacks, sino crear un _sistema_ bien diseñado para extender los tipos del motor.

@Web-eWorks La jerarquía de herencia del motor es para C++, no para scripts. Tratar de mezclar ambos es conceptualmente incorrecto para empezar.

Tal vez el malentendido es que el cuadro de diálogo Crear nodo hace que parezca que se agregó una nueva clase, por lo que puede ser una buena idea marcar esos tipos personalizados como claramente que contienen un script.

@Web-eWorks Si está utilizando Mono, se verá transparente como si se hubiera agregado una nueva clase, porque ES una nueva clase. Para GDScript, dado que las clases son archivos de forma predeterminada, no se puede hacer de esta manera, por lo que la forma de hacerlo puede ser agregar un nuevo global con una interfaz de usuario dedicada para configurarlo (como lo hemos hecho para las cargas automáticas de singleton)... pero esto sigue siendo una clase de secuencia de comandos, no una clase de motor.

@willnationsdev Mi punto principal en esto es que creo que está mal hacer que parezca que está agregando nuevas clases reales al motor, porque no es así. Está abierto a la confusión. Es solo un nodo con una secuencia de comandos, por lo que en lugar de ocultar la secuencia de comandos, creo que lo correcto es hacerlo más visible en el cuadro de diálogo de creación.

@reduz Bueno, esa es la cosa. Node+Script es una escena. El mecanismo add_custom_type debe comportarse como Mono, registrando una 'nueva clase', incluso si técnicamente no es una 'clase' según el estándar. Si hay una manera de hacerlo sin necesidad de tocar ClassDB, soy todo oídos.

Además, @akien-mga sugirió que en la vista de árbol de escena, podríamos ocultar los scripts de los nodos personalizados, para evitar confundir a los usuarios acerca de que crearon ese script y lo editaron por error (pero aun así mostrarlo en el inspector en la parte inferior) .

En tales nodos, agregar una secuencia de comandos abrirá el cuadro de diálogo de creación en un modo de herencia, por lo que seguirá siendo bastante transparente para el flujo de trabajo del usuario, mientras que está claro que es un nodo personalizado y no parte del motor.

@willnationsdev ¿ Alguna objeción para que yo abra un problema nuevo y más conciso que detalla específicamente el alcance de la implementación?

@Web-eWorks Node + Script no es una escena, los nodos en un diseño de árbol son una escena. También puede agregar tipos de recursos personalizados, no solo nodos.

Y no, no debería comportarse como registrar una nueva clase. Debe quedar bastante claro que es una clase de C++ con un script preagregado.

@ Web-eWorks Sí, eso no es un problema para mí. Por favor, mencióname para recibir un ping si lo haces. ¿No estás seguro de si necesitamos un número separado?

Míralo desde otro punto de vista. Su argumento es hacer que el usuario vea como si estuviera ampliando los tipos de motores con nuevos tipos de motores.

Mi punto de vista es que está ampliando los tipos de motores con scripts, no con nuevos tipos de motores. Y que el usuario no es tonto y necesita saber esto.

@reduz Lo que quise decir sobre Node+Script fue que ese mecanismo ya estaba cubierto a través de la creación de instancias de Escenas.

Tal vez no estoy entendiendo bien la implementación de Mono, pero ¿las clases de Mono no son aún Scripts?

@reduz Estoy mayormente de acuerdo con usted, también cuando dijo que agregar un script a un nodo personalizado simplemente propondría heredarlo. Pero, ¿cómo espera que esto funcione con los tipos personalizados nativos de GDN?

@reduz Sin embargo, uno de nuestros objetivos es permitir que los scripts de tipo personalizado, estos scripts preasignados colocados en las clases de C++, no se puedan eliminar. Eso es algo que no se puede hacer en el contexto del editor, ya que siempre puede eliminar un script en tiempo de ejecución (a menos que desee conservar esa funcionalidad y solo proteger un script de tipo personalizado en tiempo de diseño en el editor)

Ciertamente estaría abierto a un método alternativo. De cualquier manera, la implementación más fácil es hacer que el Objeto se asigne condicionalmente secuencias de comandos (como lo hice en mi implementación) al verificar alguna clase de registro de terceros (ya sea ClassDB, ProjectSettings, EditorData, o quién sabe qué más) . Entonces se vuelve muy fácil para el propio editor verificar con ese tercero y mostrar las cosas de manera diferente (también como lo hice en mi implementación). Sin embargo, no sería demasiado trabajo, no creo que mueva el registro a otro contexto que no sea ClassDB.

^ ¿Sería aceptable ese compromiso? De lo contrario, debe microgestionar todas las ubicaciones posibles en las que Object obtiene un script asignado para verificar con el tercero. Eso sería mucho más complejo.

La implementación que he hecho ha sido muy clara hasta ahora en cuanto a qué "tipos" son scripts y cuáles no. Después de todo, aún puede ver claramente y acceder al script asociado con los tipos personalizados en el panel de escena en el video que compartí.

@willnationsdev Entiendo lo que está tratando de hacer, pero no creo que esto pueda hacerse limpiamente. Está ocultando una complejidad que no tiene por qué ocultarse, de una manera que nunca funcionará del todo como se esperaba.

@Zylann Creo que es lo mismo, pero a) el script es gdnative internal b) usa un método interno para gdnative. No estoy lo suficientemente familiarizado con él honestamente para decirlo.

@reduz ¿Está diciendo que no desea permitir ninguna forma de creación de restricciones basadas en secuencias de comandos en los objetos? Porque podría mover la lógica de verificación al Editor mismo y eso le daría una verificación de las restricciones en tiempo de diseño con la misma facilidad (la interfaz de usuario cambia, como usted dice), pero no funcionarían en tiempo de ejecución, por lo que la gente aún estaría potencialmente capaz de cambiar las cosas una vez que el juego se está ejecutando. ¿Eso funcionaría mejor para ti? Sin embargo, todavía preferiría poder verificar cosas en tiempo de ejecución ...

@willnationsdev, ¿qué tipo de restricciones basadas en secuencias de comandos desea aplicar?

Las mismas restricciones de las que se ha tratado la propiedad del script personalizado desde el principio: hacer cumplir que el script asignado deriva de algún otro script.

Recomendaría ocultar el ícono de secuencia de comandos para la secuencia de comandos extendida en la jerarquía de la escena y, en caso de que alguien haga clic en el botón "Agregar secuencia de comandos" en lugar de heredar la clase base del nodo, hereda la secuencia de comandos atacada. Es transparente y no necesita meterse con ClassDB en absoluto.

Entonces, solo revisando parte de la información en script_language.h , siento que realmente podría mover el nuevo contenido que agregué en ClassDB a la clase ScriptLanguage y crear un una especie de ScriptDB singleton que solo se crea si el lenguaje de secuencias de comandos tiene la intención de usarlo. Y debido a que object.cpp ya incluye script_language.h , podría hacer lo siguiente en set_script(const RefPtr &p_script) ...

  1. comprobar si p_script es de hecho un script
  2. comprobar a qué idioma pertenece p_script
  3. transfiera el p_script y el Object de la instancia custom_script al ScriptDB para el ScriptLanguage asociado,
  4. obtenga una respuesta del ScriptDB sobre si el p_script se puede asignar al Object dadas las restricciones implícitas por el custom_script en el Object instancia.

Esto nos permitiría mantener ambos ClassDB limpios de cualquier modificación y mantener limpios object.h (aparte de un setter/getter para custom_script ). También evita la complicación innecesaria de los lenguajes de secuencias de comandos que no necesitan depender de Godot para definir identificadores y espacios de nombres (como lo necesitarían GDScript y VisualScript, a diferencia de C #, C ++, Python, etc.).

Luego, todo lo que necesita hacer es definir ScriptServer métodos que puedan realizar comprobaciones de identificadores/espacios de nombres en todos los lenguajes de secuencias de comandos aplicables para reemplazar la funcionalidad experimental ClassDB de confirmar tipos personalizados/herencia de tipos personalizados jerarquías. Suficientemente fácil.

¿Algo de esto suena como una alternativa aceptable @reduz?

Solo agrego mi voz aquí. Acabo de empezar a trabajar con Godot y, cuando leí sobre los complementos de tipos personalizados, pensé que estaría creando un nuevo tipo base reutilizable. Por ejemplo, cuando creas un KinematicBody puedes adjuntarle un script, pero aún así haría todas sus KinematicBody cosas.

Esto se refuerza de dos maneras:

  1. Se llaman tipos. Si bien los idiomas difieren en si un tipo es extensible o no (javascript: sí, golang: no, python: sí), un tipo que defina generalmente es extensible si los tipos de idioma de primera clase son extensibles. En Godot, los tipos de primera clase son extensibles, pero los tipos personalizados no lo son (al menos no de la misma manera). Llamarlos de otra manera, como escenas prefabricadas o escenas de plantillas, ayudaría a marcarlos como diferentes.
  1. Aparecen en el mismo árbol que los nodos de primera clase en la ventana 'Crear nuevo nodo'. Esto implica que los usas de la misma manera. Tener una sección separada para 'Prefabricados' o 'Plantillas' o como quiera llamarlos los llamaría nuevamente como diferentes.

@JPTeasdale Desafortunadamente, en este punto, la mayor preocupación es la implementación, no tanto la pregunta "¿cómo define esto?". Y los tipos personalizados de Godot SON extensibles (son solo scripts). El editor todavía no tiene el soporte de código para mostrar las relaciones de herencia entre los tipos personalizados en el diálogo de creación de nodos, pero los datos están disponibles. Tampoco veo una razón para cambiarles el nombre de "tipo personalizado" a otra cosa. "Prefabricado" y "plantilla" no son términos realmente apropiados, ni son escenas en primer lugar (son solo guiones, simple y llanamente).

Creo que es mucho más simple que la solución prevista:

  1. Agregue una propiedad oculta en el inspector a la clase de Objeto llamada "custom_type_script" y asigne el script personalizado para seleccionar esta propiedad en lugar de Script
  2. Cuando intente extender el nodo, verifique si esta propiedad es nula; si no, extienda este script en lugar de la clase de nodo (escriba extend "res:/path/to/script.gd")
  3. Cambie get_script_instance para que apunte a la instancia del script personalizado si el script del nodo es nulo

@MarianoGnu Bueno, en términos de crear los cambios del editor, es más sencillo hacerlo simplemente completando automáticamente la propiedad script y evitando que se vuelva nulo en primer lugar (porque el editor solo mira el script , y no tenemos que encontrar cada vez que hace referencia a la propiedad script y modificar ese código si todo lo que hacemos es cambiar el valor de script ) .

Dicho esto, parte del objetivo de rehacer este proceso es permitir que los lenguajes de secuencias de comandos en general opten por usar identificadores en lugar de rutas de archivos para ubicar clases de secuencias de comandos. Esa es la única razón por la que el concepto $# ScriptDB ClassDB se sugirieron en primer lugar. Pero ahora veo por qué Juan se ha opuesto tanto a los cambios ClassDB , de ahí la sugerencia de almacenar la información solo en la API de secuencias de comandos. Contiene toda la información en el lenguaje de secuencias de comandos individual.

Se podría hacer una combinación, en lugar de almacenar el script invisible en el objeto, almacenarlo en ScriptDB, agregar un pase previo al lector de scripts para reemplazar "extender CustomClassName" a "extender" res:/ruta/almacenado/inScriptDB.gd " en el precompilador de GdScript, porque tener la secuencia de comandos fuera de la secuencia de comandos hereda la jerarquía es muy problemático (la jerarquía debe ser una línea recta de abajo a la raíz, tener una rama genera confusión)

porque tener la secuencia de comandos fuera de la secuencia de comandos hereda la jerarquía es muy problemático (la jerarquía debe ser una línea recta de abajo a la raíz, tener una rama genera confusión)

@MarianoGnu Tal vez algún malentendido aquí. ¿En qué punto crees que no hay una línea recta de herencia? Hasta donde he ido implementando cosas, siempre hay una jerarquía de herencia muy clara entre los scripts. No he cambiado nada sobre cómo funcionan las jerarquías de herencia. Acabo de hacer posible asignar un script dado a un StringName y buscarlo en una base de datos de algún tipo.

Y si ya estamos haciendo el trabajo de hacer eso, no hay razón para reemplazar el texto del script a una ruta en el compilador GDScript. Todo lo que hace el compilador es asignar una instancia de Script a una variable script . Si cargué el script a través del método ResourceLoader::load(path) o buscándolo con Class/ScriptDB::get_script(namespace_and/or_identifier) realmente no importa.

Solo quería mencionar que, como nuevo usuario de Godot, hice un complemento con la impresión de que mi "Nodo personalizado" del complemento actuaría como un nodo integrado. Es decir, cuando lo seleccioné de la lista de nodos, esperaba obtener un nodo sin un script, pero con la funcionalidad que había programado en el complemento ya heredada (como lo es para los nodos integrados). Solo pensé que debería dar otra opinión de alguien que acaba de entrar (aunque parece que la discusión aquí ya ha sido extensa).

Como un "nodo personalizado" es solo un script, ¿cuál es la diferencia de simplemente asignar el script a un nodo integrado? ¿Qué se supone que debe hacer la función de nodo personalizado?

@MCrafterzz Se discutió que debería existir la posibilidad de personalizar los nodos para tener la posibilidad de agregar un script sobre un nodo personalizado creado a partir de un complemento.

Actualmente, el nodo personalizado es solo un nodo creado con un script ya adjunto y el ícono y el nombre ya cambiados.

@willnationsdev ¿Qué tan lejos ha llegado al implementar esta característica?
Realmente me gustaría que esta característica estuviera aquí antes de 3.1, será una adición realmente sorprendente.
Para el complemento de Godot y el sistema de complementos.

No quiero presionar a nadie. Así que por favor no lo tomes a la manera del trabajo.

He estado implementando un nuevo backend para el sistema de tipo personalizado por completo. El nuevo permite a los usuarios hacer toda la funcionalidad original, además de hacer que el botón Agregar una secuencia de comandos agregue una nueva secuencia de comandos que amplía la secuencia de comandos personalizada de forma predeterminada (en lugar de abrir la secuencia de comandos personalizada) y hace que no puede eliminar el script personalizado (debería usar el comando del editor Cambiar tipo, como cualquier otro tipo de motor).

@swarnimarun

Además, permitirá a los usuarios registrar tipos en un global que proporciona acceso a asignaciones de nombre de tipo a ruta de archivo. GDScript podrá percibir estas asignaciones como nombres de tipos globales esencialmente simples. Además, los tipos no tienen que ser tipos personalizados para registrarse y los tipos pueden ser guiones o escenas.

Hasta ahora, he implementado el nuevo backend y he vuelto a configurar la funcionalidad de script de tipo personalizado original. Actualmente se estará trabajando en nuevas funciones. A partir de una semana a partir de ahora, probablemente. Por lo demás, estoy ocupado esta semana.

@willnationsdev No se preocupe, si llega a 3.1 estaré contento.
Y me di cuenta de que podría ser bastante trabajo.
Sigan con el buen trabajo.

Actualmente, el editor tiene la capacidad de extender fácilmente el script de cualquier nodo:

extend

El nodo en sí se ve así:

2

Y la principal preocupación de @reduz era ocultar el hecho de que ya hay un script adjunto. Por un lado, tiene sentido no ocultarlo al usuario. Pero, por otro lado, los nodos personalizados prácticamente siempre tendrán scripts adjuntos. Sin scripts, los nodos personalizados son solo nodos regulares existentes con íconos personalizados y sin funcionalidad adicional agregada.

Y aunque puede extender el script personalizado, es muy molesto que los nodos personalizados simples se vean igual que los nodos personalizados extendidos.

Entonces, aquí está mi solución simple: cuando el script de un nodo personalizado es el mismo que el script en la definición del nodo personalizado, el ícono del script debe desaparecer, así:

3

Significado:

4

Chicos, ejemplo de la vida real: si tengo muchas notas personalizadas del mismo tipo, cada script personalizado para su propia instancia, ¿qué sucede si quiero cambiar el script de nodo personalizado base? Te digo: LO PEOR, porque necesito modificarlo, Y todas las demás instancias en consecuencia, lo que genera una alta probabilidad de errores humanos y tipográficos.

¿No quieres ocultar el script? Bien, luego muestre la secuencia de comandos custom_node Y la secuencia de comandos del nodo del proyecto.

@aaronfranke En mi opinión, esta es la mejor solución. Incluso las escenas instanciadas podrían beneficiarse de esto.

@zatherz et al, ahora que se ha implementado #30697, ¿qué más se puede mejorar? ¿Hay algo más en https://github.com/godotengine/godot/issues/6067#issuecomment -238250383 que sea importante tener?

Cerrando según lo fijado por #30697. Si bien la propuesta original en el OP elaborada en https://github.com/godotengine/godot/issues/6067#issuecomment -238250383 no se ha implementado, esto no sucederá debido a las preocupaciones de @reduz en https:// github.com/godotengine/godot/issues/6067#issuecomment -239060186.

¿Fue útil esta página
0 / 5 - 0 calificaciones