How can I make a variable editable in exactly one place in the inspector such that other scripts can read but not change that value?
I'm relatively new to all this, and while I feel like I'm grasping some of the concepts, I need to know the best practices.
I have three scripts, all dedicated to randomly generating asteroids and then destroying them when they're out of range. They all have a variable for the radius around the player and a variable for the number of asteroids within that sphere, called density. I kept needing to change the variables in all three places, which was messy. I needed to be able to change all the variables at once in the inspector.
One thing I tried was (and again, this seemed like bad practice) was creating a parent class and making those three scripts extensions of that class. I declared the variables inside the parent class, and made them public so the children could see them. Any form of private or protected made them invisible. I then assigned the parent script to an empty game object so I could see it in the inspector, but then, since the variables were public, the other scripts had them in the inspector too. So then I still had to change the values everywhere.
I tried to make them private, but then use that [Serialize Field] thing, but then I couldn't get the other scripts to read the variables. I tried to set up some sort of get function, but then the other scripts could still change the values in the inspector, so maybe I just botched that entirely.
I didn't try any GetComponent stuff because the Unity tutorials said that it should only be used in a Start() function, since it's taxing at run time. But maybe I misunderstood and that's the way to go. Even so, I don't know the syntax for what I want to do, or if it would fall into the same trap.
I'm moving in a different direction for making asteroids anyway, for other reasons. But there must be some way to do this, and my ignorance is killing me, and everything I've tried seems so messy.
So again: How can I make a variable editable in exactly one place in the inspector such that other scripts can read but not change that value?
Answer by NoseKills · Sep 16, 2015 at 11:20 PM
First, to answer your main question, there's really no magic trick to help you do it via a singe simple editor script or such. You have to for example make one "Tuner" GameObject to hold the data/values you want to tweak and give the other GameObjects another kind of script that gets the values from the Tuner object when they Awake(). Or make a the values you want to adjust static
and make a Tuner object that sets the values of those static variables in its Awake().
One thing I tried was (and again, this seemed like bad practice) was creating a parent class and making those three scripts extensions of that class.
It seems to be a common misconception for people who are starting to learn about inheritance to think that it's a way to share data among all objects that derive from that parent class. In reality it's just a way to save yourself the trouble of declaring the same variables and methods over and over again when making a bunch of classes that have a lot in common.
If you make a class Animal and a classes Dog and Cat that extend it, and if Animal class has variables called int NumberOfLegs
, bool SaysMeow
and bool ClimbsTrees
, it doesn't mean that setting those variables in somewhere will make all Dogs meow and climb trees. Each instance of Animal (i.e. each Cat and Dog) still has their own values for those variables (as long as they are not static). But now when you want to make a new Animal e.g. Cow, you only need to write the Cow : Animal
bit instead of having an empty class where you'd have to declare all 3 variables again.
I tried following your advice, but I think I butchered it.
Firstly, I took out all the inheritance stuff. They all just extend $$anonymous$$onoBehavior. I made a public class called AsteroidTuner : ScriptableObject that had public variables radius and density. Then in each of the other scripts, I declared private AsteroidTuner aT
and a private int radius
at the top. In the Awake() function of each, I made aT = ScriptableOject.CreateInstance ("AsteroidTuner") as AsteroidTuner
and then said r = aT.radius
so I could just use r the rest of the time.
I did the scriptable object thing because I got an error message when it extended $$anonymous$$onoBehavior and it told me to. And I don't even know what "casting" is, but whenever I get that error, tacking on as WhateverIWasJustTryingTo$$anonymous$$ake
works well.
It worked. $$anonymous$$ind of. Radius and density appeared in the inspector for AsteroidTuner and nothing else, but it turns out it just ignored the inspector and I still had to set them in the script.
So what have I done wrong this time?
And just to be clear with your inheritance example, are you saying that somewhere in the Cow : Animal
class I would need to say it has 4 legs, can't meow, and can't climb trees? If the variables in Animal
are public, are you saying that changing it in Cow
has no affect on Animal
? And if they're private, that would be a variable belonging to Animal
but none of its children?
(Thanks, by the way)
I think your mistake is that you have an instance of AsteroidTuner somewhere and you change the values in it, but then each of your other scripts creates their own instance of AsteroidTuner with SpcriptableObject.CreateInstance(), and those instances have default values in the fields you are using. You should just make a public AsteroidTuner tuner
field in your other script and drag the Tuner to that field for all the objects in the scene that need to use the values from the Tuner. This way you will be getting the values from the Tuner instance that you have modified, not some random new one.
And oh, I might have made a mistake telling you to use Awake(). Start() is safer when dealing with Inspector assigned values.
Based on this and your inheritance question, it seems like you don't have a firm grasp of instances vs. classes etc. but hey, that's what the help room is for :)
If the variables in Animal are public, are you saying that changing it in Cow has no affect on Animal?
Animal and Cow are classes. They are just text files on your HD. You can declare fields in them and assign default values to those variables. But when you run your code (press play in Unity), you will create instances
of those classes. You have only 1 Cow class, but you can create a 100 instances of it (100 cows in your game) and they can each have different number of legs etc. Cow inheriting Animal means that "all Cows are Animals", all Cow instances have all the properties of an Animal. You can take one of your Cows and change Says$$anonymous$$eow
to true for it. This won't change the Cats or Dogs or other Cows in you game in any way. Them inheriting Animal class just means they automatically have a variable called Says$$anonymous$$eow
.
And yes, because this is a hastily made up example, you could even make an instance of just "Animal" class and fiddle with it, but the same applies, changing one instance of a class doesn't affect other instances of it regardless of inheritance.
are you saying that somewhere in the Cow : Animal class I would need to say it has 4 legs, can't meow, and can't climb trees?
yes pretty much, but that's what you would need to do even without inheritance: somewhere you need to set the values for your variables. The only thing inheritance changes (in this simple case) is that you don't have to declare (write) the 3 variables again and again when you want to write a Camel class and a Penguin class etc... To "automatically" assign different values for different subclasses still requires you to write more code (e.g. override the constructor or Awake() methods of subclasses).
You already use inheritance in Unity almost all the time so you do have a reference to how things work. You can access e.g. transform.position
in your scripts only because that property is declared in $$anonymous$$onoBehaviour class and you inherit from it. Still changing any of the properties of one GameObject doesn't affect the others.
Your answer
Follow this Question
Related Questions
Is it possible to stop Unity from showing public Variables in the Inspector? 2 Answers
Setting value in inspector does not update script. 0 Answers
2nd class in same file is "inactive" ? 1 Answer
Inspector assigned variables not assigning in build 0 Answers
Unity 4.1.5 is not showing certain public variables in the inspector 1 Answer