[Solved] MonoBehaviour "templates" / SharedMonoBehaviours

I want to make a MonoBehaviour much like a ScriptableObject: I edit it once, apply the changed settings, and all prefabs that have that MonoBehaviour will reflect the changes from the original MonoBehaviour. Is this possible?

Example:
I have Prefab X, that houses all shared components. Let’s call one of those housed component “Component X”.
Now let’s say I create 2 new prefabs: Boss Prefab and Minion Prefab.
I want Boss Prefab and Minion Prefab to each have Component X, acquired from Prefab X.
Also, if I make changes to Component X on Prefab X, I want all prefabs that contain Component X to reflect the changes (so Boss Prefab’s and Minion Prefab’s own Component X would be updated to match Prefab X’s Component X).

All at Editor time, btw.

Should do that by default if you only make changes int the prefab and not the instanced game objects. If that wont suffice just have the MonoBehaviours take a ScriptableObject as a field and get all your data from the ScriptableObject

Well let’s say I have Prefab X, that houses all shared components. Let’s call one of those housed component “Component X”.
Now let’s say I create 2 new prefabs: Boss Prefab and Minion Prefab.
I want Boss Prefab and Minion Prefab to each have Component X, acquired from Prefab X.
Also, if I make changes to Component X on Prefab X, I want all prefabs that contain Component X to reflect the changes (so Boss Prefab’s and Minion Prefab’s own Component X would be updated to match Prefab X’s Component X).

All at Editor time, btw.

Bump. Any other ways apart from ScriptableObjects?

That’s an interesting question, as I was kinda disappointed when I started Unity and realized there is no way to update one prefab and have the change reflected on other prefabs.

However, thinking about it, perhaps there is one solution worth trying. I haven’t tested it out.

Idea is to create components on prefab items, add all values, etc.

Once you done that, add this script to enable copying components:

public static class ComponentExtensions
{
        public static T CopyComponent<T>(this T original, GameObject destination) where T : Component
    {
        System.Type type = original.GetType();
        Component copy = destination.AddComponent(type);
        System.Reflection.FieldInfo[] fields = type.GetFields();
        foreach (System.Reflection.FieldInfo field in fields)
        {
            field.SetValue(copy, field.GetValue(original));
        }
        return copy as T;
    }
}

Then, on your Boss Prefab, add the following component:

public class ProxyComponent : MonoBehaviour
{
     public MonoBehaviour linkedComponent;

     void Awake()
     {
          linkedComponent.CopyComponent( gameObject );

          Destroy( this );
     }
    
}

So, once you hit play, during Awake() your ProxyComponent will copy exact values from the linkedComponent and remove itself after that. Just be sure to link components via inspector.

Let me know if it helped, I’m eager to hear the results. :slight_smile:

1 Like

That’s a nice way. But doesn’t Instantiate do the same thing as your CopyComponent function?
After some thought, I was thinking something like this: Not sure show well it will work.
(Freehanded)

public class CommonClass : ScriptableObject{
    public int x;
}

public class SharedMonoBehaviour<T> : MonoBehaviour where T : ScriptableObject {

    public T shared;

    public static implicit operator T (SharedMonoBehaviour<T> s) {
    return s.shared;
}

}

public class CommonAbility : SharedMonoBehaviour<Ability> {

}

Only one way to find out :slight_smile:

This snippet could work, but it would require you to explicitly derive your classes it from SharedMonoBehaviour.

That could prove quite limiting in case you would use external scripts if I’m not mistaken. Using either CopyComponent or Instantiate() as you pointed would work for any script :slight_smile:

1 Like

Just checked: Unity - Scripting API: Object.Instantiate

Apparently Instantiate() will clone the script and whole GameObject hierarchy.

I guess if you want only the script without hierarchy, CopyComponent is the way to go.

Is CopyComponent a deep clone method? (Sorry don’t use reflection much :P)

I think it’s not deep copying. I will make a test however just to be sure.

So I made a quick test, here is the “ProxyComponent”:

using UnityEngine;
using System.Collections;

public class TestComponent1 : MonoBehaviour
{
    public MonoBehaviour linkedBehaviour;

    // Use this for initialization
    void Start ()
    {
        linkedBehaviour.CopyComponent(gameObject);
    }

}

and here is a random component we want to copy:

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

public class TestComponent2 : MonoBehaviour
{
    public int[] array = new int[]{1,4,5,35,12,3};
    public List<int> list = new List<int>(){1,2,5,4,4};
    public string value = "aValue";
    public bool beginCountdown = false;

    public InternalTimer timer = new InternalTimer(4f);

    // Use this for initialization
    void Start ()
    {

    }

    void Update()
    {
        if (!beginCountdown)
            return;

        if (timer.Tick()) //<--- basically collects deltaTime, when reaches 4f it triggers bool = true
        {
            Destroy(this);
        }
    }
}

int[ ] and string variables were copied deep, where changing values on TestComponent2 wouldn’t be reflected on the copied script.

However, List variable was not copied deep, and changing values on first script reflected on the copied one.

As expected, when the original script was destroyed, List remained intact on copied script since it increased his reference count.

Hope this helps :slight_smile:

1 Like