• 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
1
Question by stbn0 · Oct 27, 2016 at 08:32 PM · c#scriptingbasicsinheritanceoopmonobehavior

Attach a non Monobehavior class to a GameObject

T$$anonymous$$s is my issue:

I want to assign a script that inherits from an abstract class to a GameObject. I used to create MonoBehaviour scripts like "BirdScript" or "CarScript" but I want use proper classes and be able to control the gameobject the class is attached to.

Let me show you an example:

I have to following classes

 public abstract class Shape : MonoBehaviour {

    private int weight;
    private string color;

    protected int Weight
    {
        get { return weight; }
        set { weight = value; }
    }

    protected string Color
    {
        get { return color; }
        set { color = value; }
    }

    //Example abstract method
    public abstract void calculateVolume();
 }


 public class Cube : Shape {

    public void Move()
    {
        Vector3 pos = transform.position;
        pos.x = 2;
        transform.position = pos;
    }

    public override void calculateVolume()
    {
       //Just print a string
       MonoBehaviour.print("Cube volume");
    }
 }

I also have a prefab GameObject called MyCube w$$anonymous$$ch has the Cube class attached

Now I want to create an instance of MyCube from another GameObject w$$anonymous$$ch has the following script attached

 public class ShapeManager : MonoBehaviour
 {
    [SerializeField]
    public GameObject cube;

    // Use t$$anonymous$$s for initialization
    void Start()
    {
        GameObject c = Instantiate(cube);
        c.GetComponent<Cube>().calculateVolume();
        c.GetComponent<Cube>().Move();
    }

    // Update is called once per frame
    void Update() {}
 }

The GameObject cube has the MyCube prefab attached using the Inspector.

My questions are:

What if Cube wouldn't inherit a Monobehavior class ?

Is t$$anonymous$$s approach correct ?

Does it violate OOP ?

The way ShapeManager controls the cube is right ?

 GameObject c = Instantiate(cube);
 c.GetComponent<Cube>().calculateVolume();
 c.GetComponent<Cube>().Move();


My apologies for t$$anonymous$$s long post :)

Comment
Add comment · Show 5
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 Sergio7888 · Oct 27, 2016 at 09:50 PM 0
Share

You can only attach MonoBehaviour to a GameObject.
You don't need put [SerializeField] in public fields.
The way ShapeManager controls the cube is correct but I recommend check if you have get the cube. You can use Shape class in ShapeManager.


GameObject c = Instantiate(cube);
Shape s=c.GetComponent<Shape>();
if(s){// chack if Shape exists
    s.calculateVolume();
    if(s is Cube){
        s.Move();
    }
}
Edit: @stbn0 Unity engine is divided 2 part the C++( or C) internal engine and a C# scripts, any MonoBehaviour can be passed between the 2 parts, any script that is not a MonoBehaviour can only interact with the C# scripts part.
Only MonoBehaviour can be added to a object because internally a GameObject have a array/collection of Component, and MonoBehaviour extend Component class.
You need extend MonoBehaviour and can't extend Component directly because C# code in unity is treated as MonoScript and the C++ part of unity will only understand a MonoScript with a MonoBehaviour or a ScriptableObject.
avatar image stbn0 Sergio7888 · Oct 27, 2016 at 09:59 PM 0
Share

thank you for your answer @Sergio7888

Why should I get Shape and check if I get Cube ?

Wouldn't this be a one line solution ? Cube c = Instantiate(cube).GetComponent();

avatar image Sergio7888 stbn0 · Oct 27, 2016 at 11:43 PM 0
Share

this way you can use any other Shape class derived object Like a Circle or Triangle or other shape you created in the same method and only call move if its is a cube because only cube has Move method.

avatar image hexagonius · Oct 27, 2016 at 09:53 PM 0
Share

What if Cube wouldn't inherit a Monobehavior class ?
Then the script would not work because only MonoBehaviour derived classes are allowed able to exist on a GameObject.

Is this approach correct ?
No, cause it does not work :)

Does it violate OOP ?
I would say it's legal to have an abstract class based on MonoBehaviour. It's rather violating the "composition over inheritance" principle Unity's whole concept is based on

avatar image stbn0 hexagonius · Oct 27, 2016 at 10:06 PM 0
Share

thank you for your answer @hexagonius

I have this code working, why do you say it doesn't work ? Maybe I did not explain the full issue.

If shape wasn't an abstract class, would it still be an ilegal implementation ?

1 Reply

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

Answer by Glurth · Oct 27, 2016 at 10:08 PM

If neither shape nor cube actually use any of the features of a MonoBehavior, like say... defining Update(), serializing data to be saved/loaded, or just accessing the gameObject member, then I would say you can certainly choose to NOT inherit from monobehavior.

However, the cube's move function, DOES access "transform", a property of the monobehavior.

Still, if not actually overriding Monobehavior functions, it's always possible to store a reference to a game object in the class itself (specified as a parameter to the constructor of the class), rather than derive from Monobehvior.

Is it correct? Well, as long as it works, it's just a mater of opinion. Using a reference to an object, rather than deriving from an unnecessary class- does not violate OOP.

I'm not quite sure what shape manager is supposed to do, but it looks like it will create a new object, and if that object has a cube compoent (that is derived from monobehavior), it will call move on it. If the object does not have a cube component it will generate a null exception. If cube is not derived from monobehavior, use of GetComponent will fail, or possibly not even compile.

Update/Edit: Here is an example of how I would do it using both classes derived from monobehavior, and a class NOT derived from monobehavior.

 abstract public class Candy : MonoBehaviour
 {
     public int pointValue;
     public float speed;
 
     abstract public void Move();
     abstract public bool MoveCondition();
 
     void Start() { }
     void Update() { if (MoveCondition()) Move(); }
 }
 public class LemonDrop : Candy
 {
     override public void Move() { /* manipulate member variable "transform" to drop down candy*/ }
     override public bool MoveCondition() { /* use gameObject to check for certain collisions */ }
 }
 public class CottonCandy : Candy
 {
     override public void Move() { /* manipulate member variable "transform" to float around*/ }
     override public bool MoveCondition() { return true; }
 }
 
 //usage
 
 static class CandyManager
 {
     public static List<Candy> allCandy=null; //note that t$$anonymous$$s is "effectively" a list of gameobjects, that all have a candy component
 
     //dont let the <Tparam> throw you off, just t$$anonymous$$nk of it as a parameter that takes a "type"
     static void CreateCandy<Tparam>(Vector3 position) where Tparam : Candy
     {
         //create gameobject & add component (or load prefab with component)
         GameObject g = new GameObject("candy");
         g.transform.position = position;
         Candy c=null;
         c=g.AddComponent<Tparam>();
 
         //add it to allCandy List
         if (allCandy == null)
             allCandy = new List<Candy>();
         allCandy.Add(c);
     }
 
     static void InitLevel()
     {
         CreateCandy<LemonDrop>(Vector3.up);
         CreateCandy<LemonDrop>(Vector3.up+ Vector3.right);
         CreateCandy<CottonCandy>(Vector3.right);
         CreateCandy<CottonCandy>(Vector3.forward);
     }
 }

Comment
Add comment · Show 11 · 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 stbn0 · Oct 27, 2016 at 10:28 PM 0
Share

thank you for your answer @Glurth

Maybe the Shape/Cube was not the best example I should have use for my question.

Suppose I have these classes

 public class Animal {
 }
 
 public class Dog : Animal {
     public void Walk(){}
 }

I want to attach the Dog class to a Dog GameObject.

If Animal does not inherit from MonoBehaviour it wouldn't be possible to attach the Dog class to the Dog GameObject.

In the Shape/Cube example, this is the reason why Shape inherits from MonoBehaviour.

avatar image Sergio7888 stbn0 · Oct 27, 2016 at 11:48 PM 0
Share

As I said you cant attach non MonoBehaviour classes, you still can use these classes as field in a MonoBehaviour class if these classes are [Serializable], and if are not serializable still can be used in your code but can't be sarialized(saved) by the engine.

avatar image Glurth stbn0 · Oct 28, 2016 at 12:39 AM 1
Share

Lets start by defining what exactly you mean by attach: If you mean "attach" in the same way that a component is attached, then yes, you will need to derive from monobehavior.

However, if the only reason you are attaching to the object, is to get a reference to the object, I would suggest that you do not need to actually "attach" to the object. Rather, one simply stores a reference to the game object in ones class. Edit: while the does not violate Object oriented programing, it might be considered as violating the "component based model" used so heavily by unity,

Here is an uncomplied example, pretty sure I messed up the exact syntax a bit...but should give you the idea.

 public class Animal
 {
   public GameObject referencedSceneObject;
   public Animal(GameObject refObj)
    {
       referencedSceneObject=refObj;
    }
 }
 class Dog:Animal
 {
    public void walk()
    {
       referencedSceneObject.transform.x+=1;
    }
 
 }

usage...

 GameObject c=Instantiate(Cube);
 Dog d= new Dog(c);
avatar image Sergio7888 Glurth · Oct 28, 2016 at 01:34 AM 0
Share

@Glurth You said: "However, if the only reason you are attaching to the object, is to get a reference to the object", but get a reference is not the only reason, save the values of the object is a reason, in you example you used a Animal with a GameObject reference, but the other possible field values will not be serialized(saved) without a custom code to serialize it or without putting the animal as a field in a MonoBehaviour or ScriptableObject.
For a question of praticity if you need keep the value data you have as option:

  • use a MonoBehaviour and put it in a object.

  • use a ScriptableObject and create a asset (readonly at runtime).

  • use a [Serializable] and use a custom code to serialize.

  • use a [Serializable] and use in a field of a MonoBehaviour or ScriptableObject.

Show more comments
Show more comments

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

7 People are following this question.

avatar image 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

Does Unity support multiple Inheritance? 3 Answers

C# Conception - Hide inherited members and functions 1 Answer

FPS weapons class structure 1 Answer

Multiple Cars not working 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