2
\$\begingroup\$

I have a class named Item, I am storing instances of this class in list. List is created before game starts, everything works fine in that moment but when I am playing, items still are in list but components Dictionary in each seems to be reset because it haven't got any elements, before game it has.

This is my Item class:

[Serializable]
public class Item
{
    public string Name { get; }

    private Dictionary<Type, ItemComponent> components = new Dictionary<Type, ItemComponent>(); 

    public comp GetItemComponent<comp>() where comp : ItemComponent
    {
        Debug.Log(components == null); //in game shows true

        return
             components.Values.OfType<comp>().FirstOrDefault();
    }

    public Item AddItemComponent(ItemComponent component)
    {
        components.Add(component.GetType(), component);
        return this;
    }

    public Item(string name, string imagePath)
    {
        //components = new Dictionary<Type, ItemComponent>();

        Name = name;
        ImagePath = imagePath;
    }

}

I am not reset or changing items during game.

What could be the problem? Is it connected with Unity serialization limitations?

\$\endgroup\$
1
  • \$\begingroup\$ I've done what you've shown in the past with no issues (though your use of the dictionary looks odd here — iterating over the values instead of doing a dictionary lookup on the type key — is that intentional?) Are you doing anything to trigger a serialize-deserialize pass during play? (eg. editing a script's code & recompiling) Private variables won't be cached and re-loaded through one of these by default, or carried between edit & play modes. \$\endgroup\$
    – DMGregory
    Commented Jul 27, 2017 at 0:23

2 Answers 2

2
\$\begingroup\$

In Unity, Dictionaries are not serialized out of the box, so if they were populated in the Editor, they become cleared when the game starts.

You will want to run your AddItemComponent method at runtime as necessary to repopulate your Dictionary.

There might be plugins around to help make Dictionaries serializable (or at least classes similar to Dictionary), but you'd have to look around. Check this thread too.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for the response. I will use way from the link when nothing else will work. So If I will initialize dictionary before game start it will be cleaned? But can I initialize it normally from code during game? \$\endgroup\$
    – TKK
    Commented Jul 27, 2017 at 0:27
  • \$\begingroup\$ If you populate your Dictionaries within Awake or Start before other classes try to access them, should be fine. And to help avoid race conditions, set your Script Execution Order as needed. \$\endgroup\$ Commented Jul 27, 2017 at 0:32
  • \$\begingroup\$ I am creating new components during play now, and at the start everything works, but I have a problem, after some time, dictionary is set to null, items are not destroyed, only components. I am not setting it to null, only adding and getting components, don't know what possibly is causing that... \$\endgroup\$
    – TKK
    Commented Jul 27, 2017 at 12:17
0
\$\begingroup\$

You may be able to make the dictionary static in order to prevent it from being cleared!

I spent a day and a half looking for a fix to this, and found tons of unresolved issues, and no definitive answer online or from a few AIs. Still not sure why the dictionary gets cleared (I created mine in Start()) so if anyone knows more about this, please share!

My dictionary that was magically cleared the frame after being created in a MonoBehaviour:

void ReadTilemapToDict()
{
    foreach (Vector3Int pos in 
    StructureTilemap.cellBounds.allPositionsWithin)
    {
        if (StructureTilemap.HasTile(pos))
        {
            var tileInMap = StructureTilemap.GetTile(pos);
            if (tileInMap is RuleTileWithData ruleTileWithData)
            {
                // Add the tile's data to the dictionary
                _TileStatsDict.Add(pos, new TileStats 
                { 
                    tile = tileInMap, 
                    gridPos = pos, 
                    maxHealth = ruleTileWithData.health,
                    health = ruleTileWithData.health,
                    structure = ruleTileWithData.structure,
                    corpsePrefab = ruleTileWithData.corpsePrefab,
                    hitEffects = ruleTileWithData.hitEffects
                });
            }
        }
    }
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .