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 :slight_smile:

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);
    }
}