using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.PlayerLoop; namespace MoreMountains.Tools { /// /// This class lets you define an axis on which to flip a "two sided" UI element (made of two separate and usually aligned objects, effectively turning each side on/off everytime the container's scale goes above/below a certain threshold /// [ExecuteAlways] public class MMTwoSidedUI : MonoBehaviour { /// the possible axis on which to flip the double object public enum Axis { x, y, z } [Header("Bindings")] /// the object to consider as the "front" of the two sided element. Will be visible if the scale is above the threshold public GameObject Front; /// the object to consider as the "back" of the two sided element. Will be visible if the scale is below the threshold public GameObject Back; [Header("Axis")] /// the axis on which to flip this object public Axis FlipAxis; /// the scale threshold at which the flip should occur public float ScaleThreshold = 0f; [Header("Events")] /// an event to invoke on flip public UnityEvent OnFlip; [Header("Debug")] /// whether or not we're in debug mode public bool DebugMode; /// the value to apply to the scale when in debug mode [Range(-1f, 1f)] public float ScaleValue; /// whether or not our object is flipped right now [MMReadOnly] public bool BackVisible = false; protected RectTransform _rectTransform; protected bool _initialized = false; /// /// On Start we initialize our object /// protected virtual void Start() { Initialization(); } /// /// On init we grab our rect transform and initialize visibility /// protected virtual void Initialization() { _rectTransform = this.gameObject.GetComponent(); _initialized = true; float axis = GetScaleValue(); BackVisible = (axis < ScaleThreshold); Front.SetActive(!BackVisible); Back.SetActive(BackVisible); } /// /// On Update we update visibility if needed /// protected virtual void Update() { #if UNITY_EDITOR IfEditor(); #endif float axis = GetScaleValue(); if ((axis < ScaleThreshold) != BackVisible) { Front.SetActive(BackVisible); Back.SetActive(!BackVisible); OnFlip?.Invoke(); } BackVisible = (axis < ScaleThreshold); } /// /// If in editor, we initialize if needed, and apply the debug scale value if needed /// protected virtual void IfEditor() { if (!_initialized) { Initialization(); } if (DebugMode) { switch (FlipAxis) { case Axis.x: _rectTransform.localScale = new Vector3(ScaleValue, _rectTransform.localScale.y, _rectTransform.localScale.z); break; case Axis.y: _rectTransform.localScale = new Vector3(_rectTransform.localScale.x, ScaleValue, _rectTransform.localScale.z); break; case Axis.z: _rectTransform.localScale = new Vector3(_rectTransform.localScale.x, _rectTransform.localScale.y, ScaleValue); break; } } } /// /// Returns the scale of the selected axis /// /// protected virtual float GetScaleValue() { switch (FlipAxis) { case Axis.x: return _rectTransform.localScale.x; case Axis.y: return _rectTransform.localScale.y; case Axis.z: return _rectTransform.localScale.z; } return 0f; } } }