Skip to content

Instantly share code, notes, and snippets.

@TheLouisHong
Forked from Lazersquid/Reference.cs
Created May 20, 2018 14:14
Show Gist options
  • Save TheLouisHong/ba27e2921c01e7b92fdc457e6613b20f to your computer and use it in GitHub Desktop.
Save TheLouisHong/ba27e2921c01e7b92fdc457e6613b20f to your computer and use it in GitHub Desktop.
Unity generic scriptable object variable reference pattern
using System;
/// <summary>
/// Reference Class.
/// </summary>
[Serializable]
public abstract class Reference
{
}
/// <summary>
/// Reference Class.
/// </summary>
[Serializable]
public class Reference<T, G> : Reference where G : Variable<T>
{
public bool UseConstant = true;
public T ConstantValue;
public G Variable;
public Reference() { }
public Reference(T value)
{
UseConstant = true;
ConstantValue = value;
}
public T Value
{
get { return UseConstant ? ConstantValue : Variable.Value; }
}
public static implicit operator T(Reference<T, G> Reference)
{
return Reference.Value;
}
public static implicit operator Reference<T, G>(T Value)
{
return new Reference<T, G>(Value);
}
}
using UnityEditor;
using UnityEngine;
/// <summary>
/// ReferenceDrawer Class.
/// </summary>
[CustomPropertyDrawer(typeof(Reference), true)]
public class ReferenceDrawer : PropertyDrawer
{
/// <summary>
/// Options to display in the popup to select constant or variable.
/// </summary>
private readonly string[] _PopupOption = { "Use Constant", "Use Variable" };
/// <summary> Cached style to use to draw the popup button. </summary>
private GUIStyle _PopupStyle;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (_PopupStyle == null)
{
_PopupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions"));
_PopupStyle.imagePosition = ImagePosition.ImageOnly;
}
label = EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position, label);
EditorGUI.BeginChangeCheck();
// Get properties
SerializedProperty useConstant = property.FindPropertyRelative("UseConstant");
SerializedProperty constantValue = property.FindPropertyRelative("ConstantValue");
SerializedProperty variable = property.FindPropertyRelative("Variable");
// Calculate rect for configuration button
Rect buttonRect = new Rect(position);
buttonRect.yMin += _PopupStyle.margin.top;
buttonRect.width = _PopupStyle.fixedWidth + _PopupStyle.margin.right;
position.xMin = buttonRect.xMax;
// Store old indent level and set it to 0, the PrefixLabel takes care of it
int indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
int result = EditorGUI.Popup(buttonRect, useConstant.boolValue ? 0 : 1, _PopupOption, _PopupStyle);
useConstant.boolValue = result == 0;
EditorGUI.PropertyField(position, useConstant.boolValue ? constantValue : variable, GUIContent.none);
if (EditorGUI.EndChangeCheck())
property.serializedObject.ApplyModifiedProperties();
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
using System;
using UnityEngine;
/// <summary>
/// StringReference Class.
/// </summary>
[Serializable]
public class StringReference : Reference<string, StringVariable>
{
public StringReference(string Value) : base(Value) { }
public StringReference() { }
}
/// <summary>
/// StringVariable Class.
/// </summary>
[CreateAssetMenu]
public class StringVariable : Variable<string> { }
using UnityEngine;
/// <summary>
/// Variable Class.
/// </summary>
public class Variable<T> : ScriptableObject
{
public T Value;
public void SetValue(T value)
{
Value = value;
}
public void SetValue(Variable<T> value)
{
Value = value.Value;
}
}
using System;
using UnityEngine;
/// <summary>
/// Vector3Reference Class.
/// </summary>
[Serializable]
public class Vector3Reference : Reference<Vector3, Vector3Variable>
{
public Vector3Reference(Vector3 Value) : base(Value) { }
public Vector3Reference() { }
}
/// <summary>
/// Vector3Variable Class.
/// </summary>
[CreateAssetMenu]
public class Vector3Variable : Variable<Vector3> { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment