Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Inherited class object added to list as Base Class

Discussion in 'Scripting' started by dawickedeye, Jan 12, 2018.

  1. dawickedeye

    dawickedeye

    Joined:
    Nov 26, 2017
    Posts:
    6
    Hey guys.
    I'm currently working on a Visual novel Node Editor.
    Each node can have multiple actions assigned to it that would fire at the same time. Those actions are all Subclasses of GameAction ( CharacterAction / MusicAction and such )
    When setting up a tree in the editor you'd press a button to apply it to the game manager.
    So far that seems to work fine.
    The problem is, to fire those actions I have to check their types and weirdly enough, I noticed that all the actions are passed to the game manager as GameAction instead of their derived type which means casting won't work on them ( something like
    Code (CSharp):
    1.    PlayMusicClip(((MusicAction)ga).clip);
    )

    After further looking into the problem I found out that the problem occurs when applying the nodes to the game manager

    inside the loop that does so, a Debug.Log to show the type of the actions returns the correct value but after being added to list in the game manager they all revert to GameAction

    Here's the part the applies the nodes:
    Code (CSharp):
    1.    
    2.   foreach (Node n in canvasCache.nodeCanvas.nodes)
    3.             {
    4.                 GameEvent g = n.thisEvent;
    5.  
    6.                 if (n.thisEvent.actions.Count > 0 && n.thisEvent.actions[0].GetType() == typeof(GameStartAction) && n.thisEvent.nextEvent != null)
    7.                     startLinked = true; // the type is correct here
    8.  
    9.                 int ne = NodeId(g.nextEvent);
    10.                 int le = NodeId(g.lastEvent);
    11.  
    12.                 g.nextEventId = ne;
    13.                 g.lastEventId = le;
    14.  
    15.                 manager.events.Add(g);
    16.             }
    manager is the game manager and events is a generic list of GameEvent which itself has a generic list of GameAction


    These are the GameEvent, GameAction and an example of a derived class from it

    Code (CSharp):
    1.  
    2. [System.Serializable]
    3. public class GameEvent
    4. {
    5.     public List<GameAction> actions = new List<GameAction>();
    6.  
    7.     public GameEvent nextEvent;
    8.     public int nextEventId=-1;
    9.  
    10.     public GameEvent lastEvent;
    11.     public int lastEventId=-1;
    12.  
    13.     public EventTransition transition = new EventTransition();
    14.  
    15. }
    16.  
    17. [System.Serializable]
    18. public class GameAction
    19. {
    20. }
    21. [System.Serializable]
    22. public class TextAction : GameAction
    23. {
    24.     public string text;
    25.     public string speaker;
    26.     public enum Event { print, clear};
    27.     public Event textEvent;
    28. }
    29.  
    30.  
    31.  
    Any idea what would've caused this??
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    5,660
    Are these getting serialized using Unity's serializer (I notice the Serializable attribute), such as by being members of a MonoBehaviour or ScriptableObject?

    If so, unity does not support this sort of serializing.

    The unity serializer determines the type of the object based on the field's type, not the actual objects type. So if the field is typed 'GameAction', it will deserialize as 'GameAction', even if you set it to 'TextAction'.
     
    Lysander likes this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    5,660
    Note, also, unity's serializer does not support references. So if your field 'nextEvent' that is of type GameEvent on your class GameEvent. That will cause a recursive infinite serialized chain. You shouldn't do this if you intend to have unity support serializing it.
     
  4. dawickedeye

    dawickedeye

    Joined:
    Nov 26, 2017
    Posts:
    6
    Thanks for the reply

    Well yes nextEvent is of type GameEvent.
    First time I tried it all the references got lost and that only made sence that why I added nextEventId which is the index of the next event in the list then as the game starts I iterate through the list to link the events to each other.

    Code (CSharp):
    1.  
    2.     public void RelinkEvents()
    3.     {
    4.  
    5.         for (int i = 0; i < events.Count; i++)
    6.         {
    7.             var n = events[i].nextEventId;
    8.             var l = events[i].lastEventId;
    9.  
    10.  
    11.             if (n >= 0)
    12.                 events[i].nextEvent = events[n];
    13.             if (l >= 0)
    14.                 events[i].lastEvent = events[l];
    15.  
    16.  
    17.         }
    18.  
    19.     }
    As for the Serialization problem, I ended adding all the variables to the base class and simply used a string variable to differantiate between the actions like this:

    Code (CSharp):
    1. public class GameAction
    2. {
    3.     public string t = "";
    4.  
    5.     //TEXT
    6.     public string text;
    7.     public string speaker;
    8.     public enum TextEvent { print, clear };
    9.     public TextEvent textEvent;
    10.     //CHAPTER
    11.     public string name = "New Chapter";
    12.     public enum ChapterEvent { print, clear };
    13.     public ChapterEvent chapterEvent;
    14.     //BACKGROUND
    15.     public Texture2D background;
    16.     public enum BackgroundEvent { change };
    17.     public BackgroundEvent backgroundEvent;
    18.     //MUSIC
    19.     public AudioClip clip;
    20.     public enum MusicEvent { play, pause, stop, resume, volume };
    21.     public MusicEvent musicEvent;
    22.     public float volume = 1;
    23.     //CHARACTER
    24.     public Character character;
    25.     public enum CharacterEvent { appear, walkin, disappear, walkout, move, shake, talk };
    26.     public CharacterEvent characterEvent;
    27.  
    28. }
    29.  
    30. public class TextAction : GameAction
    31. {
    32.     public TextAction()
    33.     {
    34.         t = "Text";
    35.     }
    36. }
    37.  
    I used to work with an ordered list of events and simply go from an event to another by incrementing the counter but this method worked better for me specially when I switched to a node editor ( as added nodes won't always be created in a chronological order. I know it wouldn't be hard to sort them though )

    In the end, the whole thing is now working perfectly :D