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

Attach a non Monobehavior class to a GameObject

This 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 which has the Cube class attached

Now I want to create an instance of MyCube from another GameObject which has the following script attached

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

    // Use this 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 this 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 this 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 $$anonymous$$onoBehaviour to a GameObject.
You don't need put [SerializeField] in public fields.
The way Shape$$anonymous$$anager controls the cube is correct but I recommend check if you have get the cube. You can use Shape class in Shape$$anonymous$$anager.


GameObject c = Instantiate(cube);
Shape s=c.GetComponent<Shape>();
if(s){// chack if Shape exists
    s.calculateVolume();
    if(s is Cube){
        s.$$anonymous$$ove();
    }
}
Edit: @stbn0 Unity engine is divided 2 part the C++( or C) internal engine and a C# scripts, any $$anonymous$$onoBehaviour can be passed between the 2 parts, any script that is not a $$anonymous$$onoBehaviour can only interact with the C# scripts part.
Only $$anonymous$$onoBehaviour can be added to a object because internally a GameObject have a array/collection of Component, and $$anonymous$$onoBehaviour extend Component class.
You need extend $$anonymous$$onoBehaviour and can't extend Component directly because C# code in unity is treated as $$anonymous$$onoScript and the C++ part of unity will only understand a $$anonymous$$onoScript with a $$anonymous$$onoBehaviour 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 $$anonymous$$ove method.

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

What if Cube wouldn't inherit a $$anonymous$$onobehavior class ?
Then the script would not work because only $$anonymous$$onoBehaviour 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 $$anonymous$$onoBehaviour. 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 ? $$anonymous$$aybe 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 this is "effectively" a list of gameobjects, that all have a candy component
 
     //dont let the <Tparam> throw you off, just think 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

$$anonymous$$aybe 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 $$anonymous$$onoBehaviour 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 $$anonymous$$onoBehaviour.

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

As I said you cant attach non $$anonymous$$onoBehaviour classes, you still can use these classes as field in a $$anonymous$$onoBehaviour 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 progra$$anonymous$$g, 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 $$anonymous$$onoBehaviour or ScriptableObject.
For a question of praticity if you need keep the value data you have as option:

  • use a $$anonymous$$onoBehaviour 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 $$anonymous$$onoBehaviour 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.

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

FPS weapons class structure 1 Answer

c# How do I search by virtual Type variable in parent classes? (inheritance) 1 Answer

Can someone explain calling other scripts in C#? 2 Answers

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