Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

How to access a monobehaviour-derived classes' variables in a scriptable object?

Discussion in 'Scripting' started by ron-a, Aug 9, 2018.

  1. ron-a

    ron-a

    Joined:
    Mar 13, 2018
    Posts:
    1
    So here is my issue - say I have a public class PlaneController with a variable speed or whatever defined in it. In that class I can make a method to access the variable object ("if speed == 200 then do blah blah") of course, all very elementary.

    So next I want to make a Scriptable Object that can also affect this same speed variable - in fact I can tell PlaneController to look at this SO's speed value and use that instead. All very easy stuff, i have this all uner control so far.

    So now the issue is - I want to only declare this speed variable a single time, only in the PlaneController class. In fact I want this Scriptable Object to simply look at ALL the variables in this class, and have fields that can let me overwrite them all - but I don't want to do into the Scriptable Object and have to declare them separately in there. I want it to just know/inherit/whatever from the initial PlaneController class, such that if I add in more variables to PlaneController later, the Scriptable Object will automatically know to add whatever other values I've added to PlaneController.

    Talking to people, it looks like I need to do something along the lines of a Custom Property Drawer and then some fancy reflection to get such an effect - with my as-yet limited knowledge of such things, I can already see that Custom Property Drawers don't seem to work with Monobehavior-derived classes however.

    What I DON"T want to do is make a separate serialized class which is accessed by both the main component, and by the scriptable object - this solution DOES work, but it still adds extra steps anytime some method tries to refer to those variables (I don't want to have to use a serialized class prefix in front of however many variables I am using in the local methods, or if being called from elsewhere as well).

    Let me know if you can help - thanks!
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    What are your motivations behind this part? I don't really know how you expect the ScriptableObject to just magically transform values in a coherent manner that it barely knows exists.

    Barring a bunch of very slow reflection, and even then without knowing the specifics you can't really manipulate those values in meaningful way because they don't have meaningful attributes associated with them (you'd just be blindly multiplying all floats for example).

    Your best bet is to create some sort of generic Observer ScriptableObject and then bind it to a context in Awake().

    Code (csharp):
    1.  
    2. public abstract class Observer<T> : ScriptableObject where T : MonoBehaviour
    3. {
    4.    protected T context;
    5.  
    6.    public void Bind(T context)
    7.    {
    8.        this.context = text;
    9.  
    10.        OnBind();
    11.    }
    12.  
    13.    protected abstract void OnBind();
    14. }
    15.  
    16. public class PlaneObserver : Observer<PlaneController>
    17. {
    18.    public float speedBoost = 2.0f;
    19.  
    20.    protected override void OnBind()
    21.    {
    22.        context.speed *= speedBoost;
    23.    }
    24. }
    25.  
    26. public class PlaneController : MonoBehaviour
    27. {
    28.    [SerializeField] private PlaneObserver observer;
    29.  
    30.    private void Awake()
    31.    {
    32.        observer.Bind(this);
    33.    }
    34. }
    35.  
    If you need each ScriptableObject to maintain its own internal state, you can Instantiate a clone of the original in Awake too.