Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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
0
Question by makaka · Oct 21, 2011 at 01:48 AM · inheritanceinterfacecomponentsdesignoop

OO Design | Specific example

Hey, I started a small prototype to get a grip on OOP in Unity. I like how my system works so far but I'm not happy with some parts of the design.

Here's a simplified version of the code:

 interface IPerson { IWeapon ActiveWeapon; }
 
 class Bandit : Monobehaviour, IPerson { IWeapon ActiveWeapon;}
 
 
 interface IWeapon { Attack(); }
 
 class Revolver : Monobehaviour, IWeapon { Attack(); }
     
     
 public class Controller : MonoBehaviour {
     
 IPerson thisPerson;
     
     void Start () {
         thisPerson = (IPerson) GetComponent(typeof(IPerson));
     }
     
     void Update () {
         thisPerson.ActiveWeapon.Attack();
     }
 }

It works just fine but...

1, I have to use non-generic way to obtain IPerson and I can't define [RequireComponent (typeof (IPerson))] as IPerson doesn't (can't) inherit from MonoBehaviour

2, I can't assign values in the editor. It would be very convenient to have public IWeapon currentWeapon; and assign different components to this but I can't as IWeapon (or IPerson) can't inherit from MonoBehaviour.

Could you please provide some feedback how to go around this? Thank you a lot for any input you might have.

I really want to use more structured way than my usual get this component, get that component ... and force some methods using interfaces. Is it possible in Unity?

Comment
Add comment · Show 2
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 syclamoth · Oct 21, 2011 at 02:40 AM 0
Share

It all works internally, but you'll have to do some pretty hacky things to get it working nicely with the inspector. The way I did it was to have my components inherit from both $$anonymous$$onoBehaviour, and the interface I wanted to use for them. Then, I could drag them around in the inspector, but I would then have to manually check what they actually were before using them with any of the interface-specific bits.

avatar image makaka · Oct 21, 2011 at 10:33 AM 0
Share

Thank you for the comment, it makes some things more clear

2 Replies

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

Answer by gruhm · Oct 21, 2011 at 03:17 AM

If I understand your questions correctly, I don't think interfaces are really what you want. An interface is simple going to enforce that all classes that implement it conform. You can accomplish most of what you are after using simple inheritance:

 public class BasePerson: MonoBehaviour
 {
     public BaseWeapon ActiveWeapon;
 
     void Start()
     {
         //do whatever start up is common to all derived classes
         AddToStart();
     }
     
     //called by derived classes for implementation specific startup
     public virtual void AddToStart()
     {
 
     }
 }
 
 public class BaseWeapon: MonoBehaviour
 {
     public virtual void Attack()
     {}
 }
 
 public class Revolver: BaseWeapon
 {
     public override void Attack()
     {
         //instance specific attack
     }    
 }
 
 public class Bandit: BasePerson
 {
     public override void AddToStart()
     {
         ActiveWeapon = new Revolver();
     }
     
     void update()
     {
         ActiveWeapon.Attack();
     }
     
 }

This should get you most of the way there. If I'm not mistaken, if you want to set the 'Revolver" variable via the inspector, you're still going to need a public GameObject variable and then use GetComponent to access the actual class. I see no need for your Controller class as you can simple add the derived "Person" class to your character. Hope this helps.

Comment
Add comment · Show 3 · 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 makaka · Oct 21, 2011 at 10:32 AM 0
Share

Seems to be working fine, I will test but thank you a lot. It help a lot

avatar image Bunny83 · Oct 21, 2011 at 11:47 AM 0
Share

Sure you can use just a base class, the only difference is that inheritance is a little bit slower (due to checking the inheritance chain) and the biggest disadvantage is that you can only inherit from one base class since C# doesn't support multiple inheritance. The best way to archieve something similar is to use interfaces since a class can implement as much interfaces as you want.

Unfortunately like syclamoth already mentioned Unity provides only limited support for interfaces due to parameter restrictions. The generic GetComponent version have a constraint to UnityEngine.Component which makes it impossible to use it with interfaces. Even worse is FindObjectOfType which checks internally the Type-object you provide and refuses operation when the supplied type is not derived from UnityEngine.Object.

You can also implement your own custom GetComponent function (e.g. GetInterface()). That's how Unity's generic version is implemented:

 public T GetComponent<T>() where T : Component
 {
     return this.GetComponent(typeof(T)) as T;
 }

Just create you own extention method and remove the constraint ;)

 public static T GetInterface<T>(this GameObject aGO) 
 {
     return aGO.GetComponent(typeof(T)) as T;
 }
 public static T GetInterface<T>(this Component aComponent) 
 {
     return aComponent.GetComponent(typeof(T)) as T;
 }
avatar image makaka · Oct 21, 2011 at 12:57 PM 0
Share

Amazing, thank you. That's exactly what I had in $$anonymous$$d. Unfortunately with interfaces you still can't assign values in the inspector which renders them useless in my case as they can't be used in Prefabs. Of course I can always hack it around with some switches and enums but I really don't want to do that.

avatar image
0

Answer by Romonaga · Oct 24, 2011 at 05:21 PM

A few thoughts on this chain. The advice provided by gruhm from a professional and from a design standard is the correct answer and solution to this question. The advice being provided by Bunny83 is not a good design and will lead to performance issues due to the reliance on reflection. Let us be clear reflection is a huge performance cost and should be used with that in mind. Using reflection will always be slower than walking the inheritance chain.

If you follow what gruhm posted, it should be clear that a public GameObject property that gets and returns the actual class will allow you to assign values in the inspector, this can be done without the use of switches and or enums.

The comment that C# does not support multiple inheritance is correct yet also at the same time incorrect. It is true you can only do one inheritance per class, however if you design your classes the way gruhm suggested it should be clear that this limitation is not a limitation at all and actually can lead to better code design.

Allot of developers tend to use interfaces as a solution to the perceived notion that C# does not support multiple inheritance, in my opinion this is bad info and a bad reason to use an interface. An interface should never be used to implement multiple inheritance. An interface is implemented not inherited, it seems many people forget this fact.

Comment
Add comment · 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

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

6 People are following this question.

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

Related Questions

An OS design issue: File types associated with their appropriate programs 1 Answer

C# inheritance advice 2 Answers

Using the Delegate Object design pattern in Unity 1 Answer

Need to inherit from EventArgs AND ScriptableObject 1 Answer

How to make a List that can store anything that implements an interface? 4 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