Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 /
This post has been wikified, any user with enough reputation can edit it.
avatar image
2
Question by lhk · Dec 24, 2012 at 12:18 PM · c#interfacecomponentsarchitecturecommunication

Using interfaces in C#

In my project there is a robot. It has two important components:

  • An AI that chooses an enemy object and moves towards it.

  • A weapon that automatically shoots at the chosen enemy object.

These two components are independent and only need one piece of communication. After the movement AI has chosen a target it needs to inform the weapon system of its decision. Unfortunately I can't just call GetComponent() since there are difference weapon systems. I need an abstraction layer. Its the typical case for an interface that contains jsut that one method setTarget. I've added the interface to my project and implemented it in my weapon script. Now I thought it would be possible to access it with GetComponent(). But a component must be a MonoBehaviour, so my interface doesn't work.

How do I abstract over the different weapon systems? I want to have one movement AI work with all possible weapons.

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

4 Replies

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

Answer by MaGuSware™ · Dec 24, 2012 at 01:02 PM

you have said the key word yourself, "abstract"

abstract public class AbsClass : InheritedObject {

  //functions here
  abstract returntype FunctionName();

}

public class Class : AbsClass {

  override returntype FunctionName()
  {
       //do stuff
  }

}

Comment
Add comment · Show 6 · 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 mouurusai · Dec 24, 2012 at 01:27 PM 1
Share

"C# doesn't support multiple inheritance" But support chain, Inhere AbsClass from $$anonymous$$onoBehaviour and You class from AbsClass.

avatar image lhk · Dec 24, 2012 at 01:32 PM 0
Share

Hm, that sounds great. +1 for this comment. I'll test this idea when I'm back home.

avatar image lhk · Dec 24, 2012 at 01:40 PM 0
Share

works perfectly. Thanks for the answer and the comment.

avatar image MaGuSware™ · Dec 24, 2012 at 01:49 PM 0
Share

No worries, good luck with your project.

avatar image HeavyStorm · Mar 09, 2016 at 07:12 PM 0
Share

The answer below is much more object oriented, which should make C# practitioners happier.

avatar image Bunny83 HeavyStorm · Mar 09, 2016 at 10:06 PM 0
Share

"$$anonymous$$uch more" isn't really appropriate here. Yes, interfaces are more flexible, however abstract baseclasses are as appropriate as interfaces in this case. Interfaces aren't "more OO" than abstract base classes as it depends on the usecase. Since both answers are valid answers and it's the OP's decision which one he accepts so we won't change anything here. Just because an answer has more upvotes doesn't mean it "has to" be the accepted one. We (the moderators) only revoke the accepted state if the accepted answer contains wrong information or doesn't answer the question which isn't the case here.

Feel free to upvote the answer that you like best. $$anonymous$$eep in $$anonymous$$d that downvoting should only be used for wrong / misleading information and that it costs you some karma. Read the FAQs especially the section "be honest". Don't forget this is not a competition. Unityanswers is just a collection of information. What's useful and what's not is indicated by the votes an answer receives. The accepted answer is a personal thing that belongs to the OP. The OP asked the question and the accepted answer is a way to reward one of the answers that he personally picked as the answer that answered his question.

avatar image
14

Answer by mouurusai · Dec 24, 2012 at 12:57 PM

Key point is: ITest test = (ITest)GetComponent(typeof(ITest));

 public class Test:MonoBehaviour
 {
     void Start()
     {
         ITest test = (ITest)GetComponent(typeof(ITest));
         if (test != null)
             test.Test();
     }
 }
 
 //Car.cs
 public class Car : MonoBehaviour, ITest
 {
     public void Test()
     {
         Debug.Log("car");
     }
 }
 
 //Robot.cs
 public class Robot : MonoBehaviour, ITest
 {
     public void Test()
     {
         Debug.Log("robot");
     }
 }
 
 //ITest.cs
 public interface ITest
 {
     void Test();
 }

P.S. In Unity 3.x interface must be in separate file.

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 lhk · Dec 24, 2012 at 01:09 PM 1
Share

I will try that as soon as possible. But I doubt that it will work. It's basically the same setup that I tried: Calling GetComponent with the type of the interface. $$anonymous$$y result was an error message that GetComponent only works with Component types. I guess that means that only classes that extend $$anonymous$$onobehaviour can be used as components. Nevertheless, I'll try it.

avatar image lhk · Dec 24, 2012 at 01:52 PM 1
Share

This works, too. I'll upvote it, but sadly I can only accept one answer. Since I tested the other answer first, I already accepted it. Thank you for your efforts

avatar image MartinLyne · May 21, 2013 at 08:15 PM 0
Share

thanks very much

avatar image luky1971 · Jan 07, 2015 at 02:44 AM 0
Share

Thank you, this is exactly what I needed!

avatar image MapuHoB · Feb 25, 2015 at 03:11 AM 0
Share

Good example!

avatar image
0

Answer by Dave-Carlile · Dec 24, 2012 at 12:58 PM

In your component script, add a reference to the weapon system interface...

 public IWeaponSystem WeaponSystem;

Call GetComponent to get the script component, then use the WeaponSystem property to access the weapon system.

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 lhk · Dec 24, 2012 at 01:14 PM 0
Share

Sorry but I don't understand this. You mean that I just add the two scripts to my GameObject and assign the weapon script to a variable of my movement script ? That would probably work, but it doesn't answer my question. So far that was the content of the first two lines of your response, I got it. But in the final line you advise me to use "GetComponent to get the script component". That's not possible. I said so in my question. $$anonymous$$oreover it doesn't make sense in combination with the first part of your answer. It's either assignment in the editor or GetComponent in the script, not both

avatar image Dave-Carlile · Dec 24, 2012 at 01:22 PM 0
Share

You were stating that you couldn't call GetComponent because it couldn't deal with the interface. Just move the interface reference to a property on some script component, assign the reference however you need to, then when you need to get access to the interface, call GetComponent() and you'll have a reference to the interface on that script.

avatar image lhk · Dec 24, 2012 at 01:29 PM 0
Share

Thank you for your efforts, but I really don't understand this. You want me to add a public variable of type $$anonymous$$yInterface in my movement-ai class and assign the weapon-ai component to this variable in the unity editor, right ? That should work fine, I'll test it when I'm back at my desk. But why do I need GetComponent after that ? You said "then when you need to get access to the interface, call GetComponent() and you'll have a reference to the interface on that script." That's just not possible. GetComponent won't work with the interface. $$anonymous$$oreover the call to GetComponent wouldn't be necessary after I got the interface assigned to my public variable ? Could you show me some code, please ? How do you intend to call GetComponent() ?

avatar image
0

Answer by jankymidget · Jul 22, 2017 at 09:50 PM

Interface for your robot to the weapon system and some proxy function to shoot.

 public interface IRobot {
   IWeaponSystem WeaponSystem { get; set; }
   void ShootTarget();
 }

Interface for your weapon system and some undefined way to settarget and shoot.

 public interface IWeaponSystem {
   void SetTarget();
   void Shoot();
 }

Base class for the Robot that extends MonoBehaviour, and uses the IRobot interface.

 public class Robot : MonoBehaviour, IRobot {
   private IWeaponSystem weaponSystem;
   /// <summary>
   /// Can be set to some initial weapon system in UI
   /// or set programmatically from code.
   /// </summary>
   public IWeaponSystem WeaponSystem {
     // assumes some sort of IWeaponSystem is attached
     get { return weaponSystem; }
     set { weaponSystem = value; }
   }
   void Update() {
     WeaponSystem.SetTarget(); // if there is one
     ShootTarget(); // same as above, but the weapon system still handles it
   }
   public void ShootTarget() {
     WeaponSystem.Shoot();
   }
 }

Base astract class for WeaponSystem. Can't be instantiated i.e. abstract, extend this for all weapon systems.

 public abstract class WeaponSystem : MonoBehaviour, IWeaponSystem {
   void IWeaponSystem.SetTarget() {
     /*do set target ai logic at this level*/
   }
   void IWeaponSystem.Shoot() { /*do nothing abstract base*/ }
 }

Subclass for some turret weapon system.

 public class TurretWeaponSystem : WeaponSystem {
   // re-define shoot here
   public void Shoot() {
     // do TurretWeaponSystem specific Shoot() behavior
   }
 }

Most of your logic will take place elsewhere, but here is a rough example of the indirect interactions.

 void exampleUsage() {
   Robot myRobot = new Robot();
   WeaponSystem genericWeaponSystem = new TurretWeaponSystem();
   // noting that myRobot.WeaponSystem is of IWeaponSystem type
   myRobot.WeaponSystem = genericWeaponSystem;
   myRobot.ShootTarget();
 }

This isn't exactly how I would do it, but based on what I read, I tried to keep the interfaces in there. With interfaces, if performance is a concern, you'll want to avoid boxing and unboxing of the real types the interfaces point to as often as possible. Once it gets pass and set to to a variable, it should be fine, but constant marshaling will amount to some level of performance hit across the whole system if you use the pattern a lot.

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

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

Restrict access to components on same object 1 Answer

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

How to choose base class to make Inherit C# 2 Answers

Need help with a script that is supposed to get components 1 Answer


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