Search Unity

How can I change values from second class in a script in the inspector?

Discussion in 'Scripting' started by solarflame5, Jun 18, 2019.

  1. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Specifically, I'm using a second class in a script, but I want that class to use specific objects which would be ordinarily changable from the inspector. However, this isn't happening for me (I believe because I'm using two classes in the same script). Code:
    Code (CSharp):
    1. public class thingProperties{
    2. //Want to see this in the unity inspector.
    3. public Sprite portrait;
    4. //This too.
    5. public Sprite one,two,three;
    6. ...
    7. }
    8. public class mainThing : MonoBehavior{
    9. ...
    10. }
     
  2. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    To clarify, I can see public objects from the inspector from the mainThing class.
     
  3. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    To be editable in inspector you want to put SerializableAttribute on your class. And perhaps you want to move it to separate file or nest within MonoBehaviour script.
     
    solarflame5 likes this.
  4. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Can you give me an example of what that might look like?
     
  5. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    Code (csharp):
    1. public class MyScript : MonoBehaviour
    2. {
    3.     [System.Serializable]
    4.     public class MyOtherClass {} // whatever you want in there
    5.  
    6.     public MyOtherClass myObject; // this is an instance variable of MyScript, so you will see it in MyScript's inspector
    7. }
    There are some major pitfalls to using custom classes, though. Be very careful because Unity's serialization may make this do things you aren't expecting. In particular, Unity's serializer does not support null custom class, and it does not support polymorphism. If you have a null object, it will be serialized as a non-null object with everything default/zero.
    https://docs.unity3d.com/Manual/script-Serialization.html
     
    Joe-Censored and solarflame5 like this.
  6. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
  7. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    Did you include an instance of the inner class as a variable of the outer class, as per the example above?
     
  8. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Similar except it looked like:
    Code (CSharp):
    1. private MyOtherClass myObject1,myObject2, myObject3;
     
  9. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    Ah, you have to serialize that.
    [SerializeField] private MyOtherClass myObject1,myObject3;

    I haven't checked if you can apply a single attribute on a list of variables like this, if they don't all show up then you may need to declare them on different lines with an attribute each.
     
  10. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Code (CSharp):
    1. [SerializeField] private ButtonProperties slot1Prop;
    2. [SerializeField] private ButtonProperties slot2Prop;
    3. [SerializeField] private ButtonProperties slot3Prop;
    I tried that, but I'm still not seeing anything in the inspector.
     
  11. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Can you please post the full code for both classes.
     
  12. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Sorry for the messiness of this code. It's possible I left some parts of it out when I was changing it to post it, but I think it's all there:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class ShopPropertiesScript : MonoBehaviour
    7. {
    8.     [System.Serializable]
    9.     public class ButtonProperties
    10.     {
    11.         public int type;
    12.         public int cost;
    13.         public Sprite portrait;
    14.         //[PROBLEM HERE]
    15.         //I want to be able to view these in the inspector in order to set them equal to the sprites I have. There is one sprite per sellable item.
    16.         public Sprite wares1, wares2, wares3, sold;
    17.  
    18.         //Presently unused constructor (might change this later).
    19.         public ButtonProperties()
    20.         {
    21.             Debug.Log("Properties Created");
    22.         }
    23.         //This changes the object's values according to the parameter of this method.
    24.         public void updateProperties(int typ)
    25.         {
    26.             type = typ;
    27.             switch (type)
    28.             {
    29.                 case 1:
    30.                     cost = 10;
    31.                     portrait = wares1;
    32.                     break;
    33.                 case 2:
    34.                     cost = 20;
    35.                     portrait = wares2;
    36.                     break;
    37.                 case 3:
    38.                     cost = 40;
    39.                     portrait = wares3;
    40.                     break;
    41.                 case 4:
    42.                     //Because type = 4, this button will be unselectable to the user.
    43.                     cost = 0;
    44.                     portrait = sold;
    45.                     break;
    46.             }
    47.         }
    48.     }
    49.     //private ButtonProperties slot1Prop, slot2Prop, slot3Prop;
    50.     [SerializeField] private ButtonProperties slot1Prop;
    51.     [SerializeField] private ButtonProperties slot2Prop;
    52.     [SerializeField] private ButtonProperties slot3Prop;
    53.     //These are the names of the different purchasable wares.
    54.     private string[] selPref = new string[] { "Wares1", "Wares2", "Wares3", "Sold" };
    55.     //These do show up in the inspector. Slot 1 represents the first "slot" for a purchasable item. Slot 2 represents the second, and slot 3 represents the third.
    56.     public Button slot1, slot2, slot3, purchase, endTurn;
    57.     private int selSlot = 0;
    58.     public int currencyCount;
    59.     // Use this for initialization
    60.     void Start()
    61.     {
    62.         //At the start, slots should be "sold."
    63.         slot1Prop.updateProperties(4);
    64.         slot2Prop.updateProperties(4);
    65.         slot3Prop.updateProperties(4);
    66.         //Button Listeners
    67.         slot1.onClick.AddListener(select1);
    68.         slot2.onClick.AddListener(select2);
    69.         slot3.onClick.AddListener(select3);
    70.         purchase.onClick.AddListener(purchaseItem);
    71.         endTurn.onClick.AddListener(newTurn);
    72.         //Starting Currency Amount
    73.         currencyCount = 50;
    74.         //Slots are visually updated
    75.         updateSlots();
    76.     }
    77.     //This makes it so that if the user doesn't have enough of the currency to purchase the item or the slot is empty (sold), then the slot's button is made uninteractable.
    78.     private void Update()
    79.     {
    80.         //If the cost is too high or item is sold.
    81.         if (slot1Prop.cost > currencyCount || slot1Prop.type == 4)
    82.         {
    83.             slot1.interactable = false;
    84.         }
    85.         if (slot2Prop.cost > currencyCount || slot2Prop.type == 4)
    86.         {
    87.             slot2.interactable = false;
    88.         }
    89.         if (slot3Prop.cost > currencyCount || slot3Prop.type == 4)
    90.         {
    91.             slot3.interactable = false;
    92.         }
    93.         //If somehow, a slot is already selected, but can't be purchased, then the purchase button is instead made uninteractable.
    94.         if (selSlot == 1 && (slot1Prop.cost > currencyCount || slot1Prop.type == 4))
    95.         {
    96.             purchase.interactable = false;
    97.         }
    98.         else if (selSlot == 2 && (slot2Prop.cost > currencyCount || slot2Prop.type == 4))
    99.         {
    100.             purchase.interactable = false;
    101.         }
    102.         else if (selSlot == 3 && (slot3Prop.cost > currencyCount || slot3Prop.type == 4))
    103.         {
    104.             purchase.interactable = false;
    105.         }
    106.         else if (selSlot == 0)
    107.         {
    108.             purchase.interactable = false;
    109.         }
    110.     }
    111.     //This method updates the button to visually show the correct values/image.
    112.     void updateSlots()
    113.     {
    114.         slot1.GetComponentInChildren<Text>().text = slot1Prop.cost.ToString();
    115.         slot1.GetComponentInChildren<Image>().sprite = slot1Prop.portrait;
    116.         slot2.GetComponentInChildren<Text>().text = slot2Prop.cost.ToString();
    117.         slot2.GetComponentInChildren<Image>().sprite = slot2Prop.portrait;
    118.         slot3.GetComponentInChildren<Text>().text = slot3Prop.cost.ToString();
    119.         slot3.GetComponentInChildren<Image>().sprite = slot3Prop.portrait;
    120.     }
    121.     //This method updates the slot's properties.
    122.     void fillSlots(int type, int slot)
    123.     {
    124.         if (slot == 1)
    125.         {
    126.             slot1Prop.updateProperties(type);
    127.         }
    128.         else if (slot == 2)
    129.         {
    130.             slot2Prop.updateProperties(type);
    131.         }
    132.         else if (slot == 3)
    133.         {
    134.             slot3Prop.updateProperties(type);
    135.         }
    136.         else if (slot == 0)
    137.         {
    138.             //Nothing; this is an exception where nothing will happen.
    139.         }
    140.         else
    141.         {
    142.             //Error Message
    143.             Debug.Log("Invaid slot number used in fillSlots in Shop Properties script.");
    144.         }
    145.         updateSlots();
    146.     }
    147.  
    148.     //These methods update which slot is selected (will be changed later to add a visual effect).
    149.     void select1()
    150.     {
    151.         selSlot = 1;
    152.     }
    153.     void select2()
    154.     {
    155.         selSlot = 2;
    156.     }
    157.     void select3()
    158.     {
    159.         selSlot = 3;
    160.     }
    161.     //This purchases the item
    162.     void purchaseItem()
    163.     {
    164.         Debug.Log("Item Purchased.");
    165.         fillSlots(12, selSlot);
    166.         updateSlots();
    167.     }
    168.     //The items are randomized, currency count is incremented, and slots are visually updated.
    169.     void newTurn()
    170.     {
    171.         Random random = new Random();
    172.         fillSlots(Random.Range(1, 3), 1);
    173.         fillSlots(Random.Range(1, 3), 2);
    174.         fillSlots(Random.Range(1, 3), 3);
    175.         currencyCount += 20;
    176.         updateSlots();
    177.     }
    178. }
    179.  
     
  13. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Let me know if I should shorten it or clarify anything, but the important lines are: 16 and 50-52.
     
  14. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    This is what I see on the inspector:
    InspectorWithGivenCode.PNG
     
  15. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,444
    This declares that there may be three named variables with references to instances of that class. It does not create instances, so there's nothing for the inspector to show except three null fields.
     
  16. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Oh thank you. Is this correct?
    Code (CSharp):
    1. [SerializeField] private ButtonProperties slot1Prop = new ButtonProperties();
     
  17. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,444
    That will create an instance. Now it's up to the editor/inspector drawer script to manipulate it.
     
  18. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    So, add that script to a game object and then look at the added component. You should be able to edit them there.
     
  19. solarflame5

    solarflame5

    Joined:
    Sep 22, 2018
    Posts:
    11
    Thank you all! This seems to work!