En este momento estás viendo Serializar objetos polimórficos anidados en Unity

 – Unity

Serializar objetos polimórficos anidados en Unity – Unity

Serializar objetos polimórficos anidados en Unity

– UnityAssets3Free

buenas , por aqui josel luis y hoy os traigo
esta pregunta

Hola amigos desarrolladores de juegos, estoy trabajando en un proyecto de Unity que permite al diseñador de niveles editar instrucciones para los elementos de la escena sobre cómo deben actuar en los eventos.

captura de pantalla del editor de comandos en unity inspector

Pude expresar todas las Unityes de declaraciones ejecutables (expresiones, declaraciones, bloques de control) con una clase base abstracta común Command. Viene así:

[Serializable]
abstract class Command 
    public abstract object Execute();
    public abstract void Inspect(/* ... */);

class CommandCarrier : MonoBehaviour 
    public Command command;

/*
    There are several carrier classes in the real project,
    this one is only for illustrating the problem.
    Command.Inspect() would be called by a CustomEditor of CommandCarrier.
*/

Dónde Execute() es ejecutar el comando en tiempo de ejecución, y Inspect() es dibujar las GUI del inspector.

Cada tipo sólido de comando sería una clase derivada de Commandpor ejemplo, un bloque if-else se vería así:

[Serializable]
class Conditional : Command 
    public Command condition, trueBranch, falseBranch;
    public override object Execute() 
        if((bool)condition.Execute()) trueBranch.Execute();
        else falseBranch.Execute();
        return null;
    
    public override void Inspect(/* ... */)  /* ... */ 

Una expresión constante no contendría subcomandos:

[Serializable]
class Constant<T> : Command 
    public T value = default(T);
    public override object Execute() => value;
    public override void Inspect(/* ... */)  /* ... */ 

Aquí viene el problema: todos los comandos que escribí en el panel de inspección se perderían mientras se activa una reserialización (como cuando el código ha cambiado y, por lo tanto, se vuelve a compilar). Esto probablemente se deba a que Unity no pudo serializar una instancia de subclase almacenada en un campo de clase base; toda la información de tipo y los datos contenidos se pierden durante la reserialización. Lo peor es que estas instancias polimórficas incluso están anidadas.

Traté de resolver el caso y fallé: dado un campo de clase base, aparentemente es imposible «actualizar» una instancia a una subclase llamando a cualquier método que pertenezca a esa instancia; esto debe hacerse externamente, asignando al campo una instancia de subclase creada en otro lugar. Pero, de nuevo, todas las subclases tienen sus propios campos, y no he descubierto de dónde recuperar estos datos.

¿Alguien podría ayudar?

1 respuesta 1

Ahora que ha arreglado su código aquí, se lo señalaría serialización de guiones y en particular la sección

Sin soporte para polimorfismo

Si tienes uno public Animal[] animals y pones una instancia de un Doguna Cat es un Giraffedespués de la serialización tiene tres instancias de Animal.

Una forma de lidiar con esta limitación es darse cuenta de que solo se aplica a las clases personalizadas, que se serializan en línea. referencias a otros UnityEngine.Objects se serializan como referencias reales y para ellos el polimorfismo realmente funciona. harías un ScriptableObject clase derivada u otra MonoBehaviour clase derivada y hacer referencia a ella. La desventaja de esto es que tienes que almacenar este Monobehaviour o un objeto de secuencia de comandos en algún lugar, y que no puede serializarlo en línea de manera eficiente.

La razón de estas limitaciones es que una de las bases principales del sistema de serialización es que el diseño del flujo de datos de un objeto se conoce de antemano; depende de los tipos de campos en la clase, no de lo que se almacene dentro de los campos.

Entonces, en tu caso, solo usaría ScriptableObject y hacer

abstract class Command : ScriptableObject

    public abstract object Execute();
    public abstract void Inspect(/* ... */);

y

[CreateAssetMenu]
public class Conditional : Command 

    public Command condition, trueBranch, falseBranch;
    public override object Execute() 
        if((bool)condition.Execute()) trueBranch.Execute();
        else falseBranch.Execute();
        return null;
    
    public override void Inspect(/* ... */)  /* ... */ 

y

public abstract class Constant<T> : Command 

    public T value = default(T);
    public override object Execute() => value;
    public override void Inspect(/* ... */)  /* ... */ 

y por ejemplo

[CreateAssetMenu]
public class IntConstant : Constant<int>


cada uno en sus propios archivos de script con el nombre correspondiente (esta parte es muy importante para el serializador).

Y luego crearía una instancia de estos a través de Activos -> clic derecho -> Crear -> «Condicional» por ejemplo y referenciarlo en las ranuras correspondientes.

También tenga en cuenta que ahora son reutilizables y simplemente puede hacer referencia al mismo elemento en varios lugares, algo que no era posible si usaba una clase serializable normal debido a

¿Cuándo puede el serializador comportarse de forma inesperada?

Las clases personalizadas se comportan como estructuras.

Con clases personalizadas que no se derivan de UnityEngine.Object Unity las serializa en línea por valor, de forma similar a como serializa estructuras. Si almacena una referencia a una instancia de una clase personalizada en varios campos diferentes, se convertirán en objetos separados cuando se serialicen. Entonces, cuando Unity deserializa los campos, contienen diferentes objetos distintos con datos idénticos.

Cuando necesite serializar un gráfico de objeto complejo con referencias, no permita que Unity serialice automáticamente los objetos. en su lugar usa ISerializationCallbackReceiver para serializarlos manualmente. Esto evita que Unity cree varios objetos a partir de referencias a objetos. Para obtener más información, consulte la documentación en ISerializationCallbackReceiver.

Esto solo es cierto para las clases personalizadas. Unity serializa clases personalizadas «en línea» porque sus datos se convierten en parte de los datos de serialización completos para el MonoBehaviour o ScriptableObject son usados. Cuando los campos se refieren a algo que es un UnityEngine.Object-clase derivada, como public Camera myCameraUnity serializa una referencia real a la cámara UnityEngine.Object. Lo mismo es cierto para las instancias de script si se derivan de MonoBehaviour o ScriptableObjectambos derivados de UnityEngine.Object.

nota: si aun no se resuelve tu pregunta por favor dejar un comentario y pronto lo podremos de nuevo , muchas gracias

sin mas,espero que te halla servido

Deja una respuesta