Skip to content

Instantly share code, notes, and snippets.

@krummja
Last active October 20, 2021 14:47
Show Gist options
  • Save krummja/a869e5d5cfbe65fa8f971870c1e13421 to your computer and use it in GitHub Desktop.
Save krummja/a869e5d5cfbe65fa8f971870c1e13421 to your computer and use it in GitHub Desktop.
using System;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// <summary>
/// A base class to add to objects that contain Button objects.
/// For each UI screen that has interactive buttons, add an implementation
/// to the root GameObject with children bearing Button components.
///
/// In the implementation, make methods with the pattern
/// <c>ContainingObjectName_ButtonName<c>. These will automatically be
/// registered in in the component's button registry as a delegate that
/// will map the buttons to their methods based on their names in the
/// object hierarchy.
/// </summary>
/// <example>
///
/// Unity object hierarchy:
///
/// MenuRoot [has MenuRootScreen component]
/// ├── Menu
/// | ├── GroupA
/// | | ├── ButtonA
/// | | ├── ButtonB
/// | | └── ButtonC
///
/// <code>
/// public class MenuRootScreen : BaseScreen
/// {
/// public void GroupA_ButtonA()
/// {
/// // Code to execute when Button A is pressed.
/// }
/// }
/// </code>
/// </example>
public abstract class BaseScreen : MonoBehaviour
{
public List<GameObject> ButtonGroupObjects = new List<GameObject>();
private List<ButtonGroup> _buttonGroups = new List<ButtonGroup>();
private Dictionary<string, Dictionary<string, Delegate>> _cache =
new Dictionary<string, Dictionary<string, Delegate>>();
private void RegisterGroup(GameObject element)
{
ButtonGroup _group = new ButtonGroup(element);
_buttonGroups.Add(_group);
foreach ( ButtonGroup group in _buttonGroups )
{
foreach ( KeyValuePair<string, Button> button in group.Buttons )
{
button.Value.onClick.AddListener(
ConfigureButtonDelegate<UnityAction>(group.GroupName, button.Key, DoNothing)
);
}
}
}
private T ConfigureButtonDelegate<T>(string groupName, string methodRoot, T Default) where T : class
{
Dictionary<string, Delegate> lookup;
if ( !_cache.TryGetValue(groupName, out lookup) )
{
_cache[groupName] = lookup = new Dictionary<string, Delegate>();
}
Delegate returnValue;
if ( !lookup.TryGetValue(methodRoot, out returnValue) )
{
MethodInfo mtd = GetType().GetMethod(
name: groupName + "_" + methodRoot,
bindingAttr: BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.InvokeMethod
);
if ( mtd != null )
{
returnValue = Delegate.CreateDelegate(typeof(T), this, mtd);
}
else
{
returnValue = Default as Delegate;
}
}
return returnValue as T;
}
private void DoNothing()
{
throw new NotImplementedException("Button has no matching function.");
}
private void Start()
{
foreach ( GameObject groupObj in ButtonGroupObjects )
{
RegisterGroup(groupObj);
}
}
}
public struct ButtonGroup
{
public string GroupName;
public GameObject GroupObject;
public Dictionary<string, Button> Buttons;
public ButtonGroup(GameObject groupObject)
{
GroupName = groupObject.name;
GroupObject = groupObject;
Buttons = new Dictionary<string, Button>();
MapButtons(groupObject.transform);
}
private void MapButtons(Transform groupTransform)
{
foreach ( Transform child in groupTransform )
{
if ( child.GetComponent<Button>() )
{
Buttons.Add(child.gameObject.name, child.GetComponent<Button>());
if ( child.childCount != 0 ) MapButtons(child);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment