Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Making a copy from an object of a list and add it to another list

Discussion in 'Scripting' started by NotMyUsernameAgain, Aug 26, 2018.

  1. NotMyUsernameAgain

    NotMyUsernameAgain

    Joined:
    Sep 28, 2017
    Posts:
    126
    Hi everyone,

    I have two lists.
    One is a list which hold all items available in game. (weaponList)
    And another one which holds items that you actually have in your inventory. (weaponInPossession)

    I now want to add a specific object from weaponList to weaponInPossession, which I do with the following code:
    Code (CSharp):
    1. WeaponList.weaponInPossession.Add(WeaponList.weaponList[weaponID]);
    However, what I have noticed is that, if I add the same object several times to the list, the objects are all linked, meaning if I change a value of one object, all the others change to.
    I suppose it's only a reference, instead of a new object.

    Unfortunately I can't just write "new" in front of it, so is there a way to solve this?
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    struct
    s pass by value,
    class
    es are passed by reference. So the question is, what do these lists contain - Unity objects (GameObjects, MonoBehaviours, prefabs), standard C# classes or standard C# structs?

    That depends on what the lists contains.

    Yes; a few potential options include :- copy constructors, cloning, Unity's
    Instantiate()
    . It all depends on what's in the lists. :)
     
  3. Stefan-Laubenberger

    Stefan-Laubenberger

    Joined:
    May 25, 2014
    Posts:
    1,956
    As you said, all your list entries reference the same object.

    To create a copy (aka clone), create an extension method:
    Code (CSharp):
    1. /// <summary>
    2. /// Perform a deep Copy of the object.
    3. /// </summary>
    4. /// <typeparam name="T">The type of object being copied.</typeparam>
    5. /// <param name="source">The object instance to copy.</param>
    6. /// <returns>The copied object.</returns>
    7. public static T Clone<T>(this T source)
    8. {
    9.     if (!typeof(T).IsSerializable)
    10.     {
    11.         throw new ArgumentException("The type must be serializable.", "source");
    12.     }
    13.  
    14.     // Don't serialize a null object, simply return the default for that object
    15.     if (Object.ReferenceEquals(source, null))
    16.     {
    17.         return default(T);
    18.     }
    19.  
    20.     IFormatter formatter = new BinaryFormatter();
    21.     Stream stream = new MemoryStream();
    22.     using (stream)
    23.     {
    24.         formatter.Serialize(stream, source);
    25.         stream.Seek(0, SeekOrigin.Begin);
    26.         return (T)formatter.Deserialize(stream);
    27.     }
    28. }
    Usage:
    Code (CSharp):
    1. WeaponList.weaponInPossession.Add(WeaponList.weaponList[weaponID].Clone());
     
    Last edited: Aug 27, 2018
  4. NotMyUsernameAgain

    NotMyUsernameAgain

    Joined:
    Sep 28, 2017
    Posts:
    126
    The list contains a class which contains ints, floats, strings, bools, Sprites.

    @Stefan-Laubenberger
    It gives me the error message Unity.Sprite is not marked as Serializable.
    However, I have my complete class marked as serializable:
    Code (CSharp):
    1. [System.Serializable]
    2. public class weaponListClass
    3. {
    4.     public string name { get; set; }
    5.     public Sprite itemSp { get; set; }
    6.     public int minAtk { get; set; }
    7.     public int maxAtk { get; set; }
    8.     public float acc { get; set; }
    9.     public float cost { get; set; }
    10.     public int weight { get; set; }
    11.     public int itemSpace { get; set; }
    12.     public Sprite type1 { get; set; }
    13.     public Sprite type2 { get; set; }
    14.     public bool equipped { get; set; }
    15.     public int itemType { get; set; } //0 weapon, 1 item, 2 equip, 3 ring
    16.     public string itemDescription { get; set; }
    17.     public float usingCost { get; set; }
    18.     public int ml { get; set; }
    19. }
     
  5. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    You'll need some form of cloning. I couldn't get the serialisation cloning method to work with the Sprite. I did find this serialisation solution but don't know anything about it to actually recommend it.

    You could just implement a Clone() method directly in weaponListClass that copies all internals with the exception of the Sprite that can just reuse the same reference.