Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

440
Views
Unity Scriptable Object cambia el tipo de campo a un nuevo tipo basado en otro valor de campo

¿Es posible que un objeto programable tenga un campo de un tipo específico y que ese tipo se determine en función del tipo de otro campo? Por ejemplo:

 public class ItemObject : ScriptableObject { public ItemType type; public Item data = new Item(); }

ItemType es una enumeración

 public enum ItemType { Physical, Magical }

Item es una clase básica, con otras 2 clases heredadas de ella, MagicalItem y PhysicalItem.

 [System.Serializable] public class MagicalItem : Item { public string passive; public MagicalItem() { passive = ""; } } ect.

Me gustaría que ItemObject pudiera elegir en el editor entre cualquiera de estas opciones, o muchas más, a medida que agrego nuevos tipos de elementos a mi juego. No he podido encontrar una solución, pero mi idea es establecer el tipo de datos en Awake() según el tipo, pero no he podido hacer que funcione. IE algo como esto:

 private void Awake() { if(type == ItemType.Magical) { data = new MagicalItem(); } else { data = new PhysicalItem(); } }

¿Hay una mejor manera de resolver este problema?

¡Gracias!

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Me divertí resolviendo este.

El truco que encontré para esto es en realidad algo nuevo, [SerializeReference] , que hace algunas cosas, una de las cuales te permite hacer serialización polimórfica, que requiere esta pregunta.

Los principales pasos para resolver esto:

  • Agregue [SerializeReference] al campo de data .
  • Agregue un método estático que cree una nueva instancia según el tipo deseado
  • Agregue un editor personalizado que verifique si hay cambios en el campo de type y, si cambia, cree una nueva instancia con el método anterior y asígnela al campo de data

En total, esto le da este tipo de resultado:

gif de uso de ejemplo

 [CreateAssetMenu(fileName = "Data", menuName = "Inventory/Item", order = 1)] public class ItemObject : ScriptableObject { [CustomEditor(typeof(ItemObject))] public class ItemObjectInspector : Editor { SerializedProperty m_type; SerializedProperty m_data; private void OnEnable() { m_type = serializedObject.FindProperty("type"); m_data = serializedObject.FindProperty("data"); } public override void OnInspectorGUI() { serializedObject.Update(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_type); if (EditorGUI.EndChangeCheck()) { m_data.managedReferenceValue = ItemObject.CreateBlankData((ItemType)m_type.intValue); } // avoid drawing type a second time // avoid drawing annoying Script field DrawPropertiesExcluding(serializedObject, new string[] { "type", "m_Script" }); serializedObject.ApplyModifiedProperties(); } } [System.Serializable] public enum ItemType { Physical, Magical } // Determines how to create an Item from each ItemType public static Item CreateBlankData(ItemType type) { switch (type) { default: case ItemType.Physical: return new PhysicalItem(); case ItemType.Magical: return new MagicalItem(); } } [System.Serializable] public class Item { [SerializeField] public string typeDescription; } [System.Serializable] public class MagicalItem : Item { [SerializeField] string elementName; public MagicalItem() { typeDescription = "Magical"; elementName = "fire"; } } [System.Serializable] public class PhysicalItem : Item { [SerializeField] float materialHardness; public PhysicalItem() { typeDescription = "Physical"; materialHardness = 1f; } } public ItemType type; [SerializeReference] public Item data; }

Nota: todas las clases anteriores son solo clases internas en aras de la brevedad. Pueden ser clases separadas o clases internas sin problemas.

over 4 years ago · Santiago Trujillo Report

0

Solo como una adición a la buena respuesta de Ruzihm .

Para este tipo de cosas, podría omitir la sobrecarga de implementar un editor personalizado y simplemente usar OnValidate

Esta función se llama cuando se carga el script o se cambia un valor en el Inspector (solo se llama en el editor).

Así que simplemente por ejemplo

 private void OnValidate() { switch(type) { case ItemType.Magical: // To avoid losing already filled in data // simply check if the current data already has the correct type if(data != null && data.GetType != typeof(MagicalItem)) { data = new MagicalItem(); } break; case ItemType.Physical: default: if(data != null && data.GetType != typeof(PhysicalItem)) { data = new PhysicalItem(); } break; } }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!