Template for component construction in Unity with C#

1.6k views Asked by At

Programming in C# in Unity requires tremendous amounts of boiler-plate. This is partly due to C#, but also due to design decisions in the engine itself.

The fact that I cannot construct MonoBehaviours myself means I need to write code as the following to enforce correct initialization:

using System;
using System.Collections.Generic;
using UnityEngine;


public class MyClass : MonoBehaviour
{
    private int a;
    private float b;
    private string c;
    private List<int> lst;

    public static MyClass Construct (int a, float b, string c,List<int> lst)
    {
        //Boiler-plate stuff
        var go = new GameObject ();
        var mc = go.AddComponent<MyClass> ();

        /*
         * This part is fugly. The static method is setting
         * fields on the object. The responsibility to be
         * fully initialized after construction should
         * lie on the object. 
         * I could easily forget to set fields from the
         * outside.
         */
        mc.a = a;
        mc.b = b;
        mc.c = c;
        mc.lst = lst;

        return mc;
    }

    //Same as above, but this time without constructing a new GameObject.
    public static MyClass AddTo (GameObject go,int a, float b, string c,List<int> lst)
    {
        var mc = go.AddComponent<MyClass> ();

        mc.a = a;
        mc.b = b;
        mc.c = c;
        mc.lst = lst;

        return mc;
    }

}

Is there a way to create a code-snippet for this in Xamarin studio to reduce boiler-plate, or any other fancy tricks to automate the process of writing these functions?

My unfinished attempt currently looks like this with Xamarin editor-templates:

public static $classname$ Construct(){
}

Where $classname$ calls a function to get the name of current class. I don't think it's actually possible to list the identifiers of the class in the function header.

Just to pre-empt people: I know it is possible to create classes that don't derive from MonoBehaviour, but let's assume that this class actually needs the functionality of a GameObject.

1

There are 1 answers

4
Heisenbug On

I guess what you are looking for some factory pattern.

Depending on the context, I have 3 suggestions:

1 Prefabs

Avoid boiler plate code, that's why is so common to use prefabs and instantiate them. It's the prototype pattern. Declare a set of serialized properties and instantiate a clone of the current prototype (that's what you are trying to do by code).

2 Initialize in Awake

If your objects are always initialized with a defined set of value, initialize them in Awake rather than in constructors. If they're not , well every component should in any case provide the relevant constructors overloads(as init method, since you cannot rely on constructor), or be wrapped inside a factory.

3 Use lambda

If you still prefer, or for some reasons need to, to stick with a procedural object creation, you can avoid declare methods for every class and simply pass an responsible for initializing the object. Something like:

public class Test : MonoBehaviour {
    public int foobar;
}

public static T CreateAndAttach<T>(Action<T> init)
     where T : MonoBehaviour
{
    GameObject go = new GameObject();
    T t = go.AddComponent<T>();

    init(t);
    return t;
}

//usage
CreateAndAttach<Test>(t => { t.foobar = 10; });   

The fact that I cannot construct MonoBehaviours myself means I need to write code as the following to enforce correct initialization

The fact is that MonoBehaviours are C# wrappers for component that resides in the C++ side of the engine, and it's the engine that owns their life time. They are de facto resources you ask for and possibly release (like other resources such as textures, meshes,..).