Inheritance and public/protected var

hey,

lets say you have a class called BaseEnemy which looks like this

class BaseEnemy : MonoBehaviour
{
public health;
}
class Snake : BaseEnemy
{

}

I want to see the public health variable in the editor. How can I do this ?
(If i put the snake script on)

Do i need to apply both scripts ?

erm its kind of not complete, but no, you dont have to put both scripts on, since Snake extends BaseEnemy it will retain all the variables from the BaseEnemy.

Lets complete the code so it will make more sense:

// BaseEnemy.js
var health : int = 100;
var maxHealth : int = 100;

function Damage(amount : int){
	health = Mathf.Clamp(health - amount, 0, var maxHealth);
}

function Heal(amount : int){
	Damage(-amount);
}

//Snake.js
class Snake : BaseEnemy{
	function Start(){
		health = 50;
		maxHealth = 50;
	}
}

Now, since I didnt use class in the BaseEnemy, Unity now assumes that BaseEnemy is a Component which can be added to a game object. Snake extends BaseEnemy, so it also is a Component.

If you Damaged a snake, it would still retain the Damage(amount) function from BaseEnemy and maintain all of the health as if it were a BaseEnemy.

On the other side, now GameObject.GetComponent(BaseEnemy) will return the Snake, but only give you access to things that are in the BaseEnemy script. So if you wanted to heal all BaseEnemies around you, you could just get that component and Heal(amount) to each one. It would still heal the snake, but it would not see anything that makes the snake Unique.

class BaseEnemy : MonoBehaviour

uhm sry :x
maybe i explained my problem not very well.

What i want :
Appy the snake script on an object.=> I want to see the health variable in the editor.

Create both scripts as I have them, and attach the Snake script to an object. :wink: You will see health.

hm okay maybe its in c# different ?

This is correct, but…

… you should set the type of the “health” variable. The code you typed/pasted won’t build in c#.

class BaseEnemy : MonoBehaviour
{
    public int health;
}

Well, usually you don’t want have health be publicly accessed and set it protected

public class BaseEnemy : MonoBehaviour {
    [SerializeField]    // This attribute will make it visible in the editor and it will be serialized (=saved), even though it wouldn't normally due to it's access level
    protected int health;
}

thanks, that is what I needed to know. <3

You can find a list of all related Unity3D Runtime attributes at http://unity3d.com/support/documentation/ScriptReference/20_class_hierarchy.Attributes.html

You have got to be kidding me… I like neat and tidy coding and am just now making the move from JS to C# and now you are telling me this?!

I have a base class containing the bare minimum/ essential functions and a heck load of fields. Loads of fields! Are you saying I have to add [SerializeField] in front of EVERY single field for it to show up in the inspector? Seriously!? :open_mouth: That is gonna look super ugly!

I also had this problem in past and found that if I do this:

public class A : MonoBehaviour  {
	public class B {
		[System.Serializable]
		public int var1;
	}
	B Something;
}

Then var1 appears in the inspector. But if I do this:

public class B {
	[System.Serializable]
	public int var1;
}
public class A : MonoBehaviour  {
	B Something;
}

Then it does not. For some of other reason, a public class has to be declared within another public class for it’s fields to be visible in the inspector. I am wondering if [System.Serializable] and [SerializeField] works differently. Will go check that out now, but my question is still this:
Do I honestly have to ugly up my code from this:

	protected GUISkin Skin;
	protected GUIStyle RequiredText;
	protected string website = "http://localhost";
	protected Texture ImgLogin;
	protected Texture ImgNew;
	protected Texture ImgPassReset;	
	protected Rect ChoiceArea	 = new Rect(0, 0, 400f, 400f);
	protected Rect LoginArea	 = new Rect(0, 0, 400f, 400f);
	protected Rect CreateArea	 = new Rect(0, 0, 400f, 400f);
	protected Rect DetailsArea	 = new Rect(0, 0, 400f, 400f);
	protected Rect WaitingArea	 = new Rect(0, 0, 150f, 060f);
	etc...

to this:

	[SerializeField]
	protected GUISkin Skin;
	[SerializeField]
	protected GUIStyle RequiredText;
	[SerializeField]
	protected string website = "http://localhost";
	[SerializeField]
	protected Texture ImgLogin;
	[SerializeField]
	protected Texture ImgNew;
	[SerializeField]
	protected Texture ImgPassReset;	
	[SerializeField]
	protected Rect ChoiceArea	 = new Rect(0, 0, 400f, 400f);
	[SerializeField]
	protected Rect LoginArea	 = new Rect(0, 0, 400f, 400f);
	[SerializeField]
	protected Rect CreateArea	 = new Rect(0, 0, 400f, 400f);
	[SerializeField]
	protected Rect DetailsArea	 = new Rect(0, 0, 400f, 400f);
	[SerializeField]
	protected Rect WaitingArea	 = new Rect(0, 0, 150f, 060f);
	etc...

…throughout all my base classes ? Is there no way … less ugly… to do this?

And while we are on this subject, the reason I moved over to C# is because when I do this in JS:

class A extends Object {
protected var field1 : String;
protected function Func1() {}
}

class B extends A {}
class C extends B {
	function ThisWillNotCompile() {
		Func1();
	}
}

I get a compile time error that the Func1 function is not known. Why is that? Why can I subclass a JavaScript function to a maximum level of 1 before the base fields and functions are no longer visible. What am I doing wrong?

In C#, I have better luck with the following:

[Serializable]
public class BaseClass
{
    public int health;
    // ... etc ...
}

[Serializable]
public class DerivedClass : BaseClass
{
    // ... Implementation details ...
}

For an instance of a class (say, defined as a public field) to be visible in the editor, the class definition must be serializable.

Both base and derived class has to be marked as serializable? That is interesting. Didn’t try that! :open_mouth: Thanks for the tip. Will give that a go next time.

Maybe you should go back and learn the basics about programming first before complaining?

protected fields are only visible and accessible from with in the same class or the classes who derive from it. That being said, the inspector can’t see the protected fields because the inspector is not derived from the class in question. Everything is working as intended.

So in order to make the fields visible you have to add Meta data in form of fields. Or declare them public, which is not desired in many cases.

Yes, but only when the Class do not derive from UnityEngine.Object or UnityEngine.Component. The Unity objects are serialized by default, normal classes aren’t.

Also the serializable attribute works different based on the implementation. i.e. BinarySerializer will also serialize private and protected fields by default, while a XmlSerializer will only serialize public fields and private/protected fields must be declared manually.

If you read the documents you find out that you only need to use the SerializeField attribute when you want to show(in the editor) private/protected members of the class. You don’t need to apply the SerializeField attribute to every member of your class, only to private/protected members. Also, the System.Serializable attribute should be used when you have a class that does not inherit from UnityEngine.Object(directly or indirectly).

//this class needs the System.Serializable attribute because it does not inherit from UnityEngine.Object
//that will cause all public variables that are serializable to be displayed in the editor
[System.Serializable]
public class SomeClass
{
   //this will be displayed
   public int var1;
   //this will not be displayed
   private string someVal;
   //this will not be displayed
   protected bool var2;
   
   //this will be displayed, because the SerializeField attribute
   //forces Unity to display it.
   [SerializeField]
   private float var3;
   
   //this will not be serialized because SomeOtherClass cannot be serialized
   [SerializeField]
   protected SomeOtherClass var4;
}

//this will not be serialized
public class SomeOtherClass
{
   public int SomeValue;
}

@Atin Skrita:
Thanks for the info. Much appreciated. I guess I forgot to mention in my earlier post that I have a LOAD of fields and that I want ALL of them to appear in the inspector. I just don’t like prefixing every line of code with another line of code… it just looks ugly. I was hoping for a way around that like just serializing the entire class and Bob’s your uncle… but it didn’t seem to work that way so I asked…

Like I said, I made the move from JS from C# so I guess I should know not to ask questions until 5 years from now. Only experienced coders who know everything can have questions… Why do people have to be so darn hostile? Sheesh! Basically, Tseng, you were spot on correct… but did you have to be so hostile in order to be right? Sheesh!

I’m still getting used to the whole public/private/protected thing. On the surface it seems easy enough and I’ve not had many issues with it since I started. Again, it sounds easy enough. This is how I got it figured:

  • If it’s private, then only the class can use it and it doesn’t show up in the inspector.
  • If it is public then it shows up in the inspector.
  • Private fields you wanna use in derived classes you need to declare as protected instead of private
  • Serialized fields are public/private/protected fields you want to use in derived classes AND have show up in the inspector

Simple enough…

But using that logic I found that none of my serialized fields show up unless I also place my entire class within the class that tries to create variables of that type. Simply marking the class AND each field as serialized didn’t do the trick! It did NOT show up in the inspector! I had to place that entire class inside my main class before it showed up in the inspector!

This was a tad confusing but since I tend to create classes for use as structs, it doesn’t really matter that they have to be declared within the main class so all was well with the world. Then tonight I tried to actually create a proper base class that would have derived classes and was unable to get any of the fields to show up in the inspector.

My AccountBase class is derived from MonoBehaviour and then my AccountCode class is derived from AccountBase and yet none of my protected fields showed up in the inspector and I couldn’t figure out why. Marking them as serialized, each, one by one, seemed like serious overkill and just looked ugly… My opinion is that when code looks ugly, you are doing it wrong…

This was when I had to come ask for guidance (and get told I’m a complete noob that has to go learn the basics of programming for daring to seek guidance in a language I am new to). From what I read here you are saying that I could have just used “public” for my needs and come to think of it… I actually feel stupid for asking the question in the first place… this truly is a darn facepalm moment for me! :smile: Doh! Protected fields are meant to be PRIVATE fields that are accessible to derived classes. I wanted them to be public fields so my mistake was in declaring them as protected, not public…! Stupid, Stupid, Stupid! N00b, even! :stuck_out_tongue: LOL

So to answer my own question about “Is there no way … less ugly… to do this?” the answer is " Yes, use ‘public’ " … again, “Doh!” :smile: But at least in asking this stupid question I did learn how to solve the other inheritance issue I had so for that I thank you! :smile: Much appreciated! :smile:

Now, if you could answer my JS related issue, I would be most grateful. That one has had me stumped for a while now. I tried asking a dev buddy if mine who is a lot more clever than I but he just says: “It’s JS. Who cares!?” so I still have no idea about that one…
Why is it that fields and functions can be seen in a derived class, but not in a class derived FROM the derived class? Is this a case of me declaring it wrong or what?

Nested classes are not necessary.

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Example : MonoBehaviour {
	protected int intField;
	
	public DerivedClass derived;
}

[System.Serializable]
public class BaseClass {
}

[System.Serializable]
public class DerivedClass : BaseClass {
	protected int otherIntField;
	public int publicField;
}

This code works flawlessly and in the inspector you’ll see

Derived
|-Public Field: 0

and base class is not nested within the MonoBehaviour. The protected don’t show, which is actually intended, as they are protected and not meant to be changed directly. In UnityScript it works the same way, protected fields won’t be show there neither, so I really don’t really understand your complain in the first place.

My guess is, you are having this code in UnityScript:

//ExampleJs.js
#pragma strict

public var mono : MonoJsClass;

// this does derives from System.Object too, read it's a normal class not a monobehaviour class. 
class MonoJsClass {
	public var monoInt : int;
}

And you converted this code into

// Example.cs
using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour {
	public MonoClass mono;

}

public class MonoClass : MonoBehaviour {
	public int monoInt;
}

But this is not correct. The MonoJsClass complies into a normal class, when it’s nested within a *.js file, under one condition: The filename != class name.

This code

// NonNestedJsClass.js notice that it has the same name as the class defined in it
#pragma strict
var someInt : int;
var nonNested : NonNestedJsClass;

class NonNestedJsClass {
	var blah;
	
	function Update() {
	}
}

Inspecting the same code in ILSpy, the result (in C# since ILSpy can’t convert to UnityScript)

using System;
[Serializable]
public class NonNestedJsClass
{
	public object blah;
	public int someInt;
	public NonNestedJsClass nonNested;
	public override void Update()
	{
	}
	public override void Main()
	{
	}
}

as you can see, the code is pretty bogus, as the UnityScript parser/compiler looks if the filename (NonNestedJsClass.js) and the class name match. If they do, the class won’t be derived from MonoBehaviour!

now let’s do a small change:

//NonNestedJsClass.js
#pragma strict
var someInt : int;
var nonNested : NonNestedJsClass;

// Notice that the class name now has a B attached to it, so filename != class name
class NonNestedJsClassB {
	var blah;
	
	function Update() {
	}
}

This produce the following code, which displayed in C# with ILSpy looks like this:

using System;
using UnityEngine;
[Serializable]
public class NonNestedJsClass : MonoBehaviour
{
	public int someInt;
	public NonNestedJsClass nonNested;
	public override void Main()
	{
	}
}

using System;
[Serializable]
public class NonNestedJsClassB
{
	public object blah;
	public override void Update()
	{
	}
}

As you can see, now you have to classes. The NonNestedJsClass which derives from MonoBehaviour and a normal class NonNestedJsClassB. As you can see, the unity compiler marks this class Serializable automatically.

So the error you probably did was that you defined a class inside the same *.js file as your script, but when converted it in C# you made MonoBehaviour out of it. This forces the Inspector not to serialize this class and instead show an inspector assignment field (where you can drag and drop objects into.

Neither they do when you do it in UnityScript unless you mark them manually. If you really want them show in the inspector you must declare them as that. It’s not ugly, it’s necessary. Good code doesn’t equal short code. Good code is code which is easy to read and understand.

Maybe I should question your reading comprehension this time? I already noted it’s not suitable in all cases, in all others you have to add the attribute to give the Inspector the necessary hints on how to process this field.

Does this code looks ugly for you just cause it uses attributes???

    public class Movie {
        public int ID { get; set; }
        [Required(ErrorMessage = "Title is required")]
        public string Title { get; set; }
        [Required(ErrorMessage = "Date is required")]
        [DataType(DataType.Date)] 
        public DateTime ReleaseDate { get; set; }
        [Required(ErrorMessage = "Genre must be specified")]
        public string Genre { get; set; }
        [Required(ErrorMessage = "Price Required")]
        [Range(1, 100, ErrorMessage = "Value must be between 1 and 100")]
        [DataType(DataType.Currency)] 
        public decimal Price { get; set; }
        [StringLength(5)]
        public string Rating { get; set; }
    }

It’s simply required to add the necessary field validation

Maybe post an example of your class, so it’s more obviously what you’re doing wrong?

My guess from above is that you declared the class as “MonoBehaviour” where it wasn’t one in in your UnityScript version, as described above. MonoBehaviours can’t be serialized [in the inspector] like a normal classes can, MonoBehaviours can only be assigned

edit
Also on a side note: Wanting all protected fields visible in the inspector can be a sign of wrong usage of them. They are usually not meant to be set externally as it’s often insecure to change them (i.e. they can be set to invalid values without a proper check, which leads to ambiguous results or crashes.

But this is where units has a major flaw in Unity, because it doesn’t serialize properties, which is the correct way on handling this issue.

Oi… again with the hostility…

Which part of “I didn’t know to serialize both classes” didn’t you understand? I know what I did wrong now, now I can fix it! Which part of “I tried it but it doesn’t work until I do this” gives you the right to say “yes it does” when there are three of us here who all saw it doesn’t? I did it wrong, I was shown what I did wrong and now i know how to do it right, so if you “really don’t really understand your complain” then “too bad”.

You did go through all that trouble to explain stuff, so to show my appreciation, allow me to explain to you vey simply what my mistake was:

[System.Serializable]
public class BaseClass {
} 

[System.Serializable] // I didn't add this line
public class DerivedClass : BaseClass {
    protected int otherIntField;
    public int publicField;
}

That simple. Didn’t know I needed to serialize the derived class also. Easy answer.

True that! And in the case of this exact example that I posted about, making the fields public was the solution I was asking for. Granted this is not the answer for every possible conceivable eventuality for all times between now and kingdom come, but it was the right choice in THIS example.

Really? You can’t just be civilized because I stated something you are not happy with? You seem to have missed the part where I said “I have a LOAD of fields and that I want ALL of them to appear in the inspector”. This is the requirement in this project so this is what I need to do. So why exactly insult me because this project requires all it’s fields to be public? Makes you feel important, does it? I bow down to your holy god-ness and worship your feet! I am not worthy! Are you happy now? Can you continue through life without acting like a holy asshole now?

Amazing. You question my reading comprehension and yet there is an entire post up above dedicated to an example and yet you say I should “post an example”. How many examples would I need to post before you notice it?

OMG! Seriously!? Thank you captain obvious! Someone give this man a prize! “can be a sign”, “usually not meant” , “OFTEN insecure”… in this case, it is fine. The only reason I have a base class is because I am creating a number of prefabs, each doing certain functions on the same database. They do different things so they have different classes. Each class goes on their own prefab to make their use as simple as drag and drop per behavior. They do different things but they use the same database back end and thus have the same variables and they share half of the functions… So I am placing the variables and the shared functions in the base class and creating derived classes that each only have their additional functionality added.

So, in this instance, the only reason for creating the base class at all is so that I don’t duplicate the code. The alternative would be to add all functionality to one super script and have them toggle between functionality. Back to design choice: create an enum, add in a drop down box and throw in a couple of condionals to navigate each state that each functionality goes through … or … create a base class with the shared functionality and keep each separate functionality contained inside it’s own class.

That was the question and I chose the latter for simplicity of reading and modification. All fields from the base class should be visible in the derived classes and show up in the inspector. Mine didn’t show up, I wanted to ask why. Not get insulted for not knowing every little thing there is to know about programming and have my intelligence brought under scrutiny for having the willingness to ask a question when I don’t know something.

I have to say that I went from using the forum on a daily basis to using it maybe 3 times in 6 months and people like you who have a God-complex just give me more reason to not use this forum and rather do my chatting else where. You really soil this place I used to love, with your better-than-though attitude. Perhaps you feel it is a good thing that I no longer chat and share knowledge over here because , after all, who needs me here when they have the benefit of your all-knowingness… Is that about the size of it?

I came on here because I had a problem. The answers were: “Yeah, you made those fields protected when you wanted them public. SIlly! :smile:” and “you need to serialize the derived class also”. Simple. why in the world did you have to go and insult my intelligence on numerous occasions?

Well I tell you what… insult away. I have way too much work to do to be concerned with your insecurities. I am doing this conversion as a favor to a stranger. It’s my good good for the day and doesn’t need to be topped off with your shitty attitude. So, again, feel free to insult away as you are now added to me ignore list.

Now that mister “better than though”'s posts will never again grace my screen, allow me to move on.

Regarding the JS issue, after nearly a decade of JS only coding, I am making the move from JS to C# and doubt I will use JS often and seriously doubt wether I will ever again make anything complex enough to warrant multiple levels of subclassing so I don’t really need an answer to this question, I am only asking because it is something I’ve never been able to figure out. I tend to create workarounds for this problem and it has never been a high-priority matter, but I must say I am rather curious…

So if you feel like having a go at it, just create yourself any JS class in any way you feel like it, create a subclass and then subclass the subclass. See if you can access any protected fields / functions in the original class from the second level subclass. If you can, I would love to hear how you declared the classes!

Thanks
(again, no rush. Just curious)