Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
12
Question by Peter G · Jun 15, 2011 at 04:11 PM · editorcustom-inspectorpolymorphism

Custom Editor (lack of) Polymorphism

I'm creating a custom editor for some scripts and I want to add some common functionality across all of them. Something like:

 public abstract class Animal : MonoBehaviour { }
 
 public class Dog : Animal {}
 public class Cat : Animal {}

Let's say I want to add an inspector button for each animal. I created a custom editor for the base class, but it won't inspect the children.

 [CustomEditor(typeof(Animal))]
 public class AnimalInspector : Editor {
      public override void OnInspectorGUI () {
            //Draw some buttons or something.
      }
 }

The problem is that Unity doesn't use the custom inspector if I inspect a derived class such as Dog, and I don't want to create copies of the same editor script just to add the same feature to two different classes.

Any Suggestions, Peter G

Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bunny83 · Jun 15, 2011 at 04:37 PM 0
Share

Well, you could derive two new custom editors that inherit from your "base" AnimalInspector class.

I think the problem is that Unity would have trouble to find the "right" custom editor for a class. I guess Unity just uses typeof() to get the type of the inspected class and searches for a class with the CustomEditor attribute that matches the type.

If you would derive your class from more than one source (some interfaces) which inspector should Unity pick when (theoretically) all interfaces provide a custom inspector.

avatar image Peter G · Jun 16, 2011 at 03:25 AM 1
Share

Thanks, I'm not sure then if its a .Net problem or a Unity thing. I'm poking around the msdn to see what I can find:

Attribute parameters are restricted to constant (const) values of the following types:

System.Type

so that shouldn't be a problem. Now onto the const part:

A constant expression must yield a value of the target type, or of a type that can be implicitly >converted to the target type.

Derived class to base class fits that bill as well. Note this next bit returns true as it should

 typeof(Animal).IsAssignableFrom(typeof(Dog));
avatar image ckfinite · Jun 16, 2011 at 04:10 AM 1
Share

I think the problem is it doesn't use IsAssignableFrom. What Unity does is just use typeof, and not support inheritance in any way. This is a Unity problem, not a .Net thing.

avatar image save · Jun 16, 2011 at 06:42 AM 0
Share
  • for interesting question!

6 Replies

· Add your reply
  • Sort: 
avatar image
21
Best Answer

Answer by NickWalker12 · Jul 06, 2013 at 09:50 PM

 [CustomEditor(typeof(Animal), true)]

Not sure if this feature existed when you asked the question, but to include children, you use the overloaded CustomEditor(inspectedType : System.Type, editorForChildClasses : boolean).

http://docs.unity3d.com/Documentation/ScriptReference/CustomEditor.CustomEditor.html

Comment
Add comment · Show 8 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Peter G · Jul 21, 2013 at 11:57 PM 0
Share

Thank you, and that's a fairly new feature. Introduced after I asked the question. :)

avatar image Paulius-Liekis · Aug 13, 2013 at 01:42 PM 0
Share

This should be accept as correct answer.

avatar image Paulius-Liekis · Sep 13, 2013 at 02:35 PM 0
Share

Still, it is correct answer now, i.e. anyone who finds this question now will agree that this answer is more valuable than the one marked as correct.

avatar image Peter G · Sep 13, 2013 at 03:23 PM 0
Share

Okay I changed it.

avatar image SugoiDev · May 07, 2014 at 08:10 PM 0
Share

What a nice feature that is! I just created a derived class from 2DT$$anonymous$$ and it made me sad to realize that all of the editor niceness was no longer available. Now, with a simple boolean, everything went back to being nice again!

Show more comments
avatar image
9

Answer by jonas-echterhoff · Jun 16, 2011 at 07:29 AM

Looking at the code, it appears that Unity indeed compares the exact type, thus not supporting Polymorphism for CustomEditors. You could file a bug on it, it's probably a simple change, but also probably not the most demanded feature.

For now, it seems you'll have to create a separate Editor class for each derived class - though you should not need to duplicate your scripts, why not have all the Editors derive from one base Editor class?

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Peter G · Jun 17, 2011 at 03:47 AM 0
Share

This seems to be the easiest solution for the time being. Thanks.

avatar image
4

Answer by SteveFSP · Jun 16, 2011 at 09:46 PM

Here is a pattern that is suitable for many use cases, and isn't too difficult to maintain:

Continuing with your example: When you create your base custom editor, move all of its GUI draw code to a static method. Something like:

 [CustomEditor(typeof(Animal))]
 public class AnimalInspector : Editor {
 
     public override void OnInspectorGUI () {
     
         DrawInspectorGUI((Animal)target);
     
     }
 
     public static bool DrawInspectorGUI (Animal targ) {
 
        // Draw some buttons or something.
        // Use the return value to indicate that the editor was updated.
 
     }
 
 }

When you extend the base MonoBehaviour, you can implement it's custom editor as follows:

 [CustomEditor(typeof(Dog))]
 public class DogInspector : Editor {
 
     public override void OnInspectorGUI () {
 
         Animal.DrawInspectorGUI((Animal)target);
 
         // Place Dog specific GUI elements here.
 
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image justinl · Aug 08, 2013 at 05:23 PM 0
Share

This works beautifully

avatar image
2

Answer by ckfinite · Jun 16, 2011 at 03:30 PM

Another thing you could do (in addition to jonas's answer) is to use generics and reflection to add the subclasses CustomEditor attribute. What you would need to do is redefine AnimalInspector to look like this:

 public abstract class AnimalInspector<T> : Editor, where T : AnimalInspector<T>
 {
      //do generic Animal stuff
 }

And a client class would look like this:

 public class DogInspector : AnimalInspector<Dog>
 {
      //Do doggy stuff
 }

Then, you would in a post build script reflect all classes that extend AnimalInspector, get typeof(T), then add the CustomEditor attribute there.

It is a bit roundabout, but I think it would work.

Another way you could do it is to recursively iterate over all subclasses in reflection. Then, when you found a subclass, add a CustomEditor attribute to the superclass. Again, annoying, but I think it could work.

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Peter G · Jun 16, 2011 at 05:14 PM 0
Share

Now its just deciding on the lesser of two workarounds. :) Its probably just going to come down to how many classes I want to custom inspect.

avatar image Peter G · Jun 17, 2011 at 03:46 AM 0
Share

Very interesting. I'm probably going to start with Jonas's answer until the project gets too big for me to manually add new editor scripts. And a quick check to make sure I'm understanding you, I believe that you want DogInspector to inherit from AnimalInspector<DogInspector> If not, then I think I'm missing your pattern some.

avatar image Bunny83 · Jun 17, 2011 at 04:08 AM 0
Share

Shouldn't the constraint be of type Animal? Since you implement the DogInspector with Dog and Dog is not an AnimalInspector.

$$anonymous$$aybe you wanted to implement it like this:

 public class DogInspector : AnimalInspector<DogInspector>

But I'm not sure it that works in C#. C++ templates should work that way ;)

edit Just tried it and it works ;) but i think it's pretty useless to use generics here. A normal base class and derived class should be enough.

avatar image Bunny83 · Jun 17, 2011 at 04:19 AM 0
Share

Now i get why you want to use generics, but i don't think that would work. Reflection is a runtime feature (not compile-time). Unity checks the attributes after compilation so changing/adding them later won't work, i guess.

But i like the idea ;)

avatar image ckfinite · Jun 20, 2011 at 02:10 PM 1
Share

I did actually mean it to be

 public class DogInspector : AnimalInspector<DogInspector>

but, as I thought about it, the implementation example is correct, so it really should be

 public class DogInspector : AnimalInspector<Dog>

And it is it surprising with the constraint that it doesn't throw a compiler error.

The reason why generics are needed here is so that the postprocessor could generate the correct attribute for Unity. This can work at compile time, if the reflection script can be attached to a post-build event. if unity doesn't have that, then this won't work.

avatar image
1

Answer by LightStriker · Sep 13, 2013 at 02:04 PM

I know it's an old question, but the newest version (4+) of Unity offer an alternative:

 [CustomEditor(typeof(MyBaseClass), true)]

The second parameter is listed as "Editor For Child Classes".

However, it only works for direct hierarchy and interface implementation is not supported. (bleh)

Also, using typeof(UnityEngine.Object) as base class is also not supported, assuming you would like your editor to show up on any kind of object.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image kblood · Jan 28, 2018 at 02:47 PM 0
Share

Yeah, I ran into the same thing. I have tried with both Object and Component. All the component types inherit from the component class, but using the new "editor for child classes" does not seem to work on the component, so that you can actually add custom fields for all components. A bit annoying.

Its mainly because I want to make it possible to select and copy multiple components so they can be copied to another game object.

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

15 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Empty space at the top of a custom property drawer layout? 2 Answers

How should I serialize data that is also editable in the Inspector? 2 Answers

Custom inspector for AnimatorStateTransition 0 Answers

Custom Editor for Monobehavior with custom property not retaining Gameobject references 0 Answers

Custom Inspector: Using SeralizedProperty changes the prefab values! 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges