0
\$\begingroup\$

Background:

My app is a sandbox with a large number of parameters that I want to be able to easily add / selectively expose to the user, edit during runtime through the game UI or from the Unity editor, and set through the editor pre-runtime and have the values persist into runtime.

With some help (months ago, still remembering how it all works) here and here I managed to get a working class that stores the variable as a reference so it can be modified from more than one place in the code, and send events when things are changed.

Now I have quite a clean way to add parameters in one central place:

public class CentralParams : MonoBehaviour
{
    private bool UIChanged;
    public delegate void UIChangedDelegate();
    public event UIChangedDelegate OnUiChange = delegate { };

    public BoolEventProperty spawnActiveEp;
    public BoolEventProperty autoMassEp;
    public BoolEventProperty drawFloorEp;
    public BoolEventProperty drawDebugEp;
    
    public IntEventProperty maxSecondInstancesEp;
    
    public FloatEventProperty secondSizeEp;
    public FloatEventProperty minuteSizeEp;
    public FloatEventProperty hourSizeEp;

The EventProperty instances can easily be linked to from the gui and will show up in the editor.

New question:


Now I want to be able to save the settings to disk. Ideally, a human readable json or similar format with just the property names and the value.

I tried having each EventProperty instance add itself to a static arrayList on instantiation so I can loop through and access the value, but that way I don't know the name of the property. I know could have the name explicitly passed to a string like:

public FloatEventProperty hourSizeEp ("hourSizeEp");

I'd prefer to keep it clean and not have to double up on the name like that. Is there a way the class can know the name of the variable it's being assigned to when it instantiates? Or some other way of iterating through all the EventProperties the class contains?

As it's a monobehaviour it can't be deserialized if I try to just serialize the whole class, although serializing to json does create a nice readable file with all the values. It's a monobehaviour because I want to attach it to a gameobject so the properties show up in the editor.

I'm a c# novice and quite probably my whole approach is backwards, any help appreciated. For reference the code for the EventProperty is below.

using System.Collections;
// using System.Windows.Markup;
using UnityEngine;
// using UnityEngine.PlayerLoop;

public static class EventPropertyList
{
    public static ArrayList allEventProperties = new ArrayList();
}

[System.Serializable]
public class EventProperty<T> where T : struct
{
    private static ArrayList EventPropertiesOfThisType = new ArrayList();
    public delegate void ValueChange(T value);
    public event ValueChange OnChanged = delegate { };

    //might not show in inspector, but would from a concrete child class, see below
    [SerializeField] private T value;
    public EventProperty()
    {
        value = default(T);
        init();
    }
    public EventProperty(T value)
    {
        this.value = value;
        init();
    }
  
    private void init()
    {
        EventPropertiesOfThisType.Add(this);
        EventPropertyList.allEventProperties.Add(this);

    }

    public static void allUpdate()
    {
        foreach (EventProperty<T> i in EventPropertiesOfThisType)
        {
            i.Update();
        }
    }

    public T Value
    {
        get => value;
        set
        {
            this.value = value;
            OnChanged?.Invoke(value);
        }
    }

    public void Update()
    {
        OnChanged?.Invoke(value);
    }
}


[System.Serializable]
public class FloatEventProperty : EventProperty<float>
{
}

[System.Serializable]
public class IntEventProperty : EventProperty<int>
{
}

[System.Serializable]
public class BoolEventProperty : EventProperty<bool>
{
}

[System.Serializable]
public class ColorEventProperty : EventProperty<Color>
{
}
\$\endgroup\$
5
  • \$\begingroup\$ Sounds like you might want to poke around in System.Reflection, which is all about giving code ways of getting information about the code itself - like walking over the list of fields on an object. \$\endgroup\$
    – DMGregory
    Nov 25 at 19:57
  • \$\begingroup\$ ok so I got a list of the fields with List<object> listValues = _centralParams.GetType().GetFields().Select(field => field.GetValue(_centralParams)).Where(value => value != null).ToList(); I can get the name of the EventProperty stored in the field but how can I also access a method on it to get the stored data? \$\endgroup\$ Nov 26 at 20:55
  • \$\begingroup\$ You can use FieldInfo.GetValue to get the object assigned to the field on a particular object, then cast the returned object reference to your type and call the method you want from that instance. \$\endgroup\$
    – DMGregory
    Nov 26 at 20:59
  • \$\begingroup\$ Is it possible to dynamically cast it based on the type of the object returned by FieldInfo.GetValue? Or do I need to handle each possible type separately? \$\endgroup\$ Nov 26 at 21:22
  • \$\begingroup\$ This is sounding like a general programming question about how to use the Reflection API, something you can tackle on StackOverflow. \$\endgroup\$
    – DMGregory
    Nov 26 at 21:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.