Search Unity

List of List or Array of Lists for easy drag-and-drop in Inspector panel

Discussion in 'Scripting' started by Shnayke, Dec 23, 2013.

  1. Shnayke

    Shnayke

    Joined:
    Mar 29, 2013
    Posts:
    11
    So I'm building my own simple script to handle sprite animations. I'm basing it off of redditor mikembley's code here which is fundamentally quite simple.

    There's one modification that I'd like to make - that current bit of code can only handle one "animation" at a time. I have modified it to allow for a List<List<Sprites>>, so I can thus have a single Animator that holds every single animation that that object needs - each animation being a single List<Sprites>.

    The problem is that declaring public List<List<Sprites>> animation_list; does not result in a slot appearing in the inspector panel for me to drag-and-drop anything into. If I declare just List<Sprites>, then I get something to appear, and I can just drag a batch of sprites over and it fills in nicely. But apparently the Inspector panel can't handle of List of Lists.
    Does anyone have a way to remedy this, or a way around it?
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It will work if you make a custom class that's set to System.Serializable. I did this for SpriteTile, where I have, for example:

    Code (csharp):
    1. [System.Serializable]
    2. public class ColliderPath {
    3.     public Vector2[] path;
    4.    
    5.     public ColliderPath (Vector2[] path) {
    6.         this.path = path;
    7.     }
    8. }
    for being able to have List<Vector2[]> in the inspector, by using List<ColliderPath> instead. The same principle would apply to having List<List<Sprite>> (which I also did, with some modifications; it's actually more like List<List<List<Sprite>>>). It seems rather unnecessary to be forced to do this since Unity is obviously coded to handle nested arrays in the inspector, but it works fine.

    --Eric
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Just occured to me, since I actually never tried that before... Unity doesn't support serialization of nested list. (List<List<object>>)

    Maybe you know... What's actually supported in its serialization?

    Code (csharp):
    1.  
    2.     public int[] arrayInt = new int[0]; // Work
    3.     public int[,] doubleArrayInt = new int[0,0]; // Inspector doesn't show it (Serialization?)
    4.     public int[][] nestedArrayInt = new int[0][]; // Inspector doesn't show it (Serialization?)
    5.     public List<int> listInt = new List<int>(); // Work
    6.     public List<List<int>> listListInt = new List<List<int>>(); // Doesn't work (no Serialization)
    7.     public List<int[]> listArrayInt = new List<int[]>(); // Doesn't work (no Serialization)
    8.     public List<int>[] arrayListInt = new List<int>[0]; // Inspector doesn't show it (Serialization?)
    9.  
     
    Last edited: Dec 23, 2013
  4. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    -
    See here for the documentation, though it's fairly old and not explicit about nested lists:

    http://docs.unity3d.com/Documentation/ScriptReference/SerializeField.html
     
  5. Shnayke

    Shnayke

    Joined:
    Mar 29, 2013
    Posts:
    11
    Thanks for the responses guys! I wound up going with this:

    using System;
    using System.Collections.Generic;
    using UnityEngine;

    [Serializable]
    public class SpriteList // helper class to ensure we can edit the nested lists inside the unity editor
    {
    public string animName;
    public bool looping = true;
    public bool nonLoopingDone = false;
    public List<Sprite> Frames;
    }

    [RequireComponent(typeof(SpriteRenderer))]
    public class AnimationDriver : MonoBehaviour
    {
    public List<SpriteList> Animations;

    public float timeBetweenFrames = (1/30);
    public float speed = 1;

    public int currentAnim = 0;
    public int currentFrame = 0;
    public bool animEnding = false;
    private float _timer;

    private SpriteRenderer _spriteRenderer;

    void Start()
    {
    _spriteRenderer = GetComponent<SpriteRenderer>(); // ensure we get the component once, not every frame
    }

    void Update()
    {
    if (speed > 0) {
    _timer += Time.deltaTime; // deltaTime tells time between update calls.

    if (_timer >= timeBetweenFrames)
    {
    _timer -= timeBetweenFrames; // timer won't be EXACT, take away playSpeed to ensure no "skipped frames" over time.

    if (currentFrame++ == Animations[currentAnim].Frames.Count - 1) {
    if (Animations[currentAnim].looping) {
    currentFrame = 0;
    } else {
    currentFrame = Animations[currentAnim].Frames.Count - 1;
    Animations[currentAnim].nonLoopingDone = true;
    }
    animEnding = true;
    }


    _spriteRenderer.sprite = Animations[currentAnim].Frames[currentFrame];
    }
    }
    }
    }

    It works great