- Home /
Object Instance Data Declaration without Constructors
Hey, cheers for reading. I've got two questions, one leading on from the other:
Question One) Do you know of an elegant way to declare object instance data without using constructors? Unity doesn't like constructors. If you have five enemies for example, and you want to set their stats individually (Name, speed, power etc.), with constructors you'd simply declare them as arguments. In Unity, the inspector allows you to do this with pre-existing objects, to bypass the constructor arguments approach, but it's not clean. Why? Because some variables that control the behavior of the object should not be public!
Question Two) Why does the inspector only allow the editing of public members by default? I realize that it is to do with serialization, and the fact that the serializer only serializes public members unless explicitly told otherwise, but why approach it like this? Why is the inspector tied into serialization? I'm assuming its entirely to do with the technical problems involved, which is fair enough, but it would be nice.
The reason it is a problem is because the scope of my member variables has nothing to do with how I want to declare them. Another example: I have a float that should be hidden, that denotes how often the object should spawn. It is only ever used by other scripts inside an accessor function, which uses it inside an equation. With the Inspector, whenever I look at the class, I see this variable that shouldn't be there!
Cheers for the help, question one is more important to me. Curious to see how you structure your code.
Use @HideInInspector to hide public variables in the inspector.
Answer by dannyskim · Oct 24, 2012 at 03:29 PM
Question One:
Unity recommends not using the Constructor when your object / class is inheriting from Monobehaviour. Reason being is that your de-serialized data may be overwritten, and it may be overwritten in a very unpredictable way, leading to very odd behavior that is going to be hard to debug and track down. Awake() and Start() were made to replace the constructor, and the best place that you could initialize your values is going to be Awake(), as in relevance it is the closest to the constructor call in terms of call ordering.
I still use the constructor plenty in classes that have absolutely no need to inherit from Monobehavior, and I have no problems whatsoever. You may also want to consider looking into ScriptableObjects, as they are used for objects that do not need to inherit from Monobehavior, but can also be serialized by Unity without extra work from you.
Question Two:
In terms of design, I don't see why they wouldn't make any other choice than what is currently implemented in Unity. Being able to edit non public variables in the inspector from an architecture stand point for a software engineer is very poor. If you're needing to edit non-public variables in a visual IDE way, then you're doing something wrong in terms of your design. Even so, if you have public variables that need to be visible by other classes when being instantiated, you can simply set the System.nonserializable flag above the public member so Unity doesn't serialize it and messes up your initialized values through code.
In terms of seeing what you need to, and not seeing what you don't, I personally think everything works out fine in Unity as long as you know certain attribute flags to use when appropriate, as well as knowing the Unity way of structuring your code and when to do what with what Unity provides, such as the ScriptableObject feature.
During development, it's also simple as going to the upper right corner of the inspector winder and changing it's status to Debug instead of Normal to see all the variables that you can't normally, makes life simple. From a design standpoint, the inspector really is there in terms for a software engineer to DEBUG. I typically will only design my public variables to be there for use by Designers, not mainly myself.
And in terms of structuring code, you'll have to be a little more specific. Do you mean design patterns?
Cheers for your reply; Similarly to you, I also use the constructor for scripts that do not derive from $$anonymous$$onoBehaviour, and I realize that Awake() and Start() are the alternatives provided. I just think they lack the one vital bit of functionality that makes constructors useful in the first place; which is the ability to create variations of a class simply through its variables. Name, power and damage are three attributes of a GameObject that could be changed per instance. You obviously don’t need a new class for GameObjects called Jim. I’m sorry; my question may have been misleading.
What I am asking is; do you know of an elegant solution to the problem of declaring variations of an object? NOT declaring defaults or editing its private fields (which as you said, is terrible practice), but giving identical objects different names, for example?
As we know, Awake() does not accept arguments, and you can’t edit the GameObject.Instantiate() function to include arguments either. How do you elegantly get around this problem? $$anonymous$$aybe you make a custom constructor (basically just an override function with arguments) that sets the variables? $$anonymous$$aybe use the inspector and so you can have two copies, one called Jim, and the other Bob.
Unfortunately, ScriptableObjects are not very useful in this situation.
The main reason I want to be able to declare private fields using the inspector is because it is one solution to the above problem: I can give each prefab a name, set its attributes/skills and drag ‘n’ drop materials onto it; something that I would normally do in the constructor argument, as such;
Orc orc = new Orc(“Bill”, 5.3, 20, m_Skill[5], m_Skill[7], m_Skill[21], m_Texture[3], m_Animation[7]);
I’m simply looking for a way to replace this with $$anonymous$$onobehaviour scripts, so that I can have constructors again. I have methods of doing it, I’m just asking if people have similar/better methods… which lead me to a rant about the Inspector, which can be summarized if you look at my example code above; Do I really want to be able to see all the fields (Name, damage, health, skill 1-3, texture and animation) when I look at the Orc class? $$anonymous$$aybe, but it’s bad practice to force it to be true, which is what the inspector does.
Ahh, I see now.
If that's the case, here's a good link I had bookmarked that should be what you're looking for, which uses the factory method pattern:
http://answers.unity3d.com/questions/160610/passing-values-into-base-constructor-with-monobeha.html
I'm thinking that's probably what you're wanting, and it should take care of being able to pass in parameters in a "constructor" like way.
YOU SAVED $$anonymous$$Y LIFE dannyskim! i was just searching for this solution!! thanx!!
Your answer
Follow this Question
Related Questions
Activator can't create array and string? 1 Answer
Compare if object is assigned specific Material 1 Answer
Change material inside instanced prefab, gameobject.renderer is NULL 1 Answer
Why do Inspector headers with comma-separated variable declarations cause redundant headers? 1 Answer
[SOLVED]How to use attributes from array of custom class instances? 1 Answer