The click blocking functionality was duplicated across multiple UI components (ActiveQuestUI, TeamOverviewController, etc.), leading to code duplication and maintenance overhead.
Instead of inheritance (which caused compilation issues with Unity's build order), we use composition with a helper class pattern.
Create Assets/Scripts/UI/Common/ClickBlockingHelper.cs:
using UnityEngine;
using System.Collections;
public static class ClickBlockingHelper
{
public static void RegisterWithClickManager(IClickBlocker blocker)
{
ClickManager.Instance?.RegisterClickBlocker(blocker);
}
public static void UnregisterWithClickManager(IClickBlocker blocker)
{
ClickManager.Instance?.UnregisterClickBlocker(blocker);
}
public static void SetClickFlag(string componentName, MonoBehaviour coroutineStarter, System.Action<bool> flagSetter)
{
flagSetter(true);
Debug.Log($"🚫 {componentName}: Click flag SET - blocking map clicks");
coroutineStarter.StopAllCoroutines();
coroutineStarter.StartCoroutine(ResetClickFlagCoroutine(componentName, flagSetter));
}
private static IEnumerator ResetClickFlagCoroutine(string componentName, System.Action<bool> flagSetter)
{
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForSeconds(0.1f);
flagSetter(false);
Debug.Log($"🔓 {componentName}: Click flag reset - map clicks allowed again");
}
}
For each UI component that implements IClickBlocker, replace the duplicated methods:
// OLD - Duplicated code in each component
private bool recentlyHandledClick = false;
void OnEnable() => ClickManager.Instance?.RegisterClickBlocker(this);
void OnDisable() => ClickManager.Instance?.UnregisterClickBlocker(this);
private void SetClickFlag()
{
recentlyHandledClick = true;
Debug.Log("🚫 ComponentName: Click flag SET - blocking map clicks");
StopAllCoroutines();
StartCoroutine(ResetClickFlag());
}
private IEnumerator ResetClickFlag()
{
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForSeconds(0.1f);
recentlyHandledClick = false;
Debug.Log("🔓 ComponentName: Click flag reset - map clicks allowed again");
}
public bool IsBlockingClick(Vector2 screenPosition)
{
if (recentlyHandledClick)
{
Debug.Log("🚫 ComponentName: Blocking click due to recent UI interaction");
return true;
}
// ... rest of method
}
// NEW - Using helper for common functionality
private bool recentlyHandledClick = false;
void OnEnable() => ClickBlockingHelper.RegisterWithClickManager(this);
void OnDisable() => ClickBlockingHelper.UnregisterWithClickManager(this);
private void SetClickFlag()
{
ClickBlockingHelper.SetClickFlag(GetType().Name, this, (flag) => recentlyHandledClick = flag);
}
public bool IsBlockingClick(Vector2 screenPosition)
{
if (recentlyHandledClick)
{
Debug.Log($"🚫 {GetType().Name}: Blocking click due to recent UI interaction");
return true;
}
// ... rest of method unchanged
}
Apply this pattern to:
ActiveQuestUI.cs (already done)TeamOverviewController.cs (needs refactoring)TravelUI.cs (if it has the same pattern)CombatEventPopupUXML.cs (if it has the same pattern)In your UI event handlers, simply call:
someElement.RegisterCallback<MouseDownEvent>(evt =>
{
SetClickFlag(); // Now uses the helper internally
evt.StopPropagation();
});
The helper handles all the coroutine management and timing automatically.