using System; using UnityEngine; using UnityEngine.UI; namespace FIMSpace.Generating { [AddComponentMenu("FImpossible Creations/PGG/Minimap/PGG Minimap Handler")] public class PGG_MinimapHandler : MonoBehaviour { /// Latest initialized minimap instance public static PGG_MinimapHandler Instance { get; protected set; } public RectTransform DisplayRect; [Tooltip("How many times displayed content is smaller than the world scale.\n\nIf you want to zoom in-out view dynamically, add 'Minimap Display Controller' component to this object.")] public float InitialZoomOut = 20f; public Vector3 InitialWorldCenterPosition = Vector3.zero; /// Calculated multiplication on start using 'BaseZoomOut' public float DisplayRatio { get; private set; } [HideInInspector] public Sprite DefaultMaskSprite; protected RectTransform container_BGLayer; protected RectTransform container_MiddleLayer; void Reset() { DisplayRect = transform as RectTransform; } void Awake() { Instance = this; DisplayRatio = 100f / InitialZoomOut; if (DisplayRect == null) DisplayRect = transform as RectTransform; if (InitialWorldCenterPosition != Vector3.zero) DisplayRect.anchoredPosition = DisplayRect.anchoredPosition + GetUIPosition(InitialWorldCenterPosition); #region Prepare Minimap-Layer Containers // Generate background layer for minimap display container_BGLayer = new GameObject("BG Layer").AddComponent(); ResetContainer(container_BGLayer); container_MiddleLayer = new GameObject("Mid Layer").AddComponent(); ResetContainer(container_MiddleLayer); container_MiddleLayer.SetAsFirstSibling(); container_BGLayer.SetAsFirstSibling(); #endregion } /// Apply UI parameters to handle minimap positioning correctly public void PrepareRectTransformForMinimap(RectTransform element) { element.anchorMin = DisplayRect.anchorMin; element.anchorMax = DisplayRect.anchorMax; } public void PrepareRectTransformForMinimap(RectTransform element, Vector3 setWorldPosition) { PrepareRectTransformForMinimap(element); SetUIPosition(element, setWorldPosition); } /// /// Clamping world position for follow to provided units offsets /// /// World Space bounds of the volume to clamp position with /// Object World Position /// SET BOTH X and Y positive values. Left / Right border padding values. /// SET BOTH X and Y positive values. Down / Upper border padding values. /// public virtual Vector3 ClampFollowWorldPosition(Bounds worldBounds, Vector3 followPosition, Vector2 firstAxis, Vector2 secondaryAxis) { Vector2 xMargins = new Vector2(); xMargins.x = worldBounds.center.x - worldBounds.extents.x; xMargins.x += firstAxis.x; xMargins.y = worldBounds.center.x + worldBounds.extents.x; xMargins.y -= firstAxis.y; Vector2 yMargins = new Vector2(); yMargins.x = worldBounds.center.z - worldBounds.extents.z; yMargins.x += secondaryAxis.x; yMargins.y = worldBounds.center.z + worldBounds.extents.z; yMargins.y -= secondaryAxis.y; followPosition.x = Mathf.Clamp(followPosition.x, xMargins.x, xMargins.y); followPosition.z = Mathf.Clamp(followPosition.z, yMargins.x, yMargins.y); return followPosition; } public void SetUIPosition(RectTransform r, Vector3 worldPosition) { r.anchoredPosition = GetUIPosition(worldPosition); r.localPosition = new Vector3(r.localPosition.x, r.localPosition.y, 0f); } public virtual Vector2 GetUIPosition(Vector3 worldPosition) { return new Vector2(worldPosition.x * DisplayRatio, worldPosition.z * DisplayRatio); } public Quaternion GetUIRotation(Transform worldTransform) { return GetUIRotation(worldTransform.eulerAngles.y); } public Quaternion GetUIRotation(float yAngle) { return Quaternion.Euler(0f, 0f, -yAngle); } #region Layer Containers /// Putting UI object in minimap target container public void PutToLayer(RectTransform ui, EMinimapLayer layer) { switch (layer) { case EMinimapLayer.Background: PutToBackLayer(ui); return; case EMinimapLayer.Middle: PutToMidLayer(ui); return; case EMinimapLayer.Front: PutToDefaultLayer(ui); return; } } /// Putting UI object in minimap background container public void PutToBackLayer(RectTransform ui) { ui.transform.SetParent(container_BGLayer, false); } /// Putting UI object in minimap background container public void PutToMidLayer(RectTransform ui) { ui.transform.SetParent(container_MiddleLayer, false); } /// Putting UI object in minimap front view container public void PutToDefaultLayer(RectTransform ui) { ui.transform.SetParent(DisplayRect, false); } protected virtual void ResetContainer(RectTransform container) { container.SetParent(DisplayRect, true); container.pivot = DisplayRect.anchorMin; PrepareRectTransformForMinimap(container); container.anchoredPosition = Vector2.zero; container.localScale = Vector3.one; container.localPosition = new Vector3(container.localPosition.x, container.localPosition.y, 0f); container.localRotation = Quaternion.identity; } #endregion } #region Editor Class #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(PGG_MinimapHandler))] public class PGG_PixelMapHandlerEditor : UnityEditor.Editor { public PGG_MinimapHandler Get { get { if (_get == null) _get = (PGG_MinimapHandler)target; return _get; } } private PGG_MinimapHandler _get; readonly string[] ignore = new string[] { "m_Script" }; readonly string[] ignorePlaymode = new string[] { "m_Script", "InitialZoomOut", "InitialWorldCenterPosition" }; UnityEditor.SerializedProperty sp_DisplayRect; private void OnEnable() { sp_DisplayRect = serializedObject.FindProperty("DisplayRect"); } public override void OnInspectorGUI() { //if (Get.DisplayRect == null) //{ // serializedObject.Update(); // UnityEditor.EditorGUILayout.PropertyField(sp_DisplayRect); // UnityEditor.EditorGUILayout.HelpBox("This component requires Unity UI RectTransform for DisplayRect!", UnityEditor.MessageType.Error); // serializedObject.ApplyModifiedProperties(); // return; //} GUILayout.Space(4); serializedObject.Update(); DrawPropertiesExcluding(serializedObject, Application.isPlaying ? ignorePlaymode : ignore); serializedObject.ApplyModifiedProperties(); GUILayout.Space(4f); UnityEditor.EditorGUILayout.HelpBox("Handling world-to-minimap scale display, draw order and draw position correctness.", UnityEditor.MessageType.None); if (Application.isPlaying == false) { UnityEditor.EditorGUILayout.HelpBox("Inside Display Rect Position (0,0) is reflection of world position (0,0,0)", UnityEditor.MessageType.None); if (Get.GetComponent() == false) { UnityEditor.EditorGUILayout.BeginVertical(UnityEditor.EditorStyles.helpBox); UnityEditor.EditorGUILayout.HelpBox("Add 'Minimap Display Controller' component for Minimap Follow Target and Minimap Zoom features.", UnityEditor.MessageType.None); GUI.backgroundColor = new Color(0.85f, 0.85f, 1f, 1f); if (GUILayout.Button("Add 'Minimap Display Controller'", UnityEditor.EditorStyles.miniButton, GUILayout.Height(15), GUILayout.MaxWidth(220))) { PGG_MinimapDisplayController dcontr = Get.gameObject.AddComponent(); dcontr.Handler = Get; } GUI.backgroundColor = Color.white; UnityEditor.EditorGUILayout.EndVertical(); } bool askForMask = false; if (Get.transform.childCount == 0) askForMask = true; else if (Get.transform.GetChild(0).childCount == 0) askForMask = true; if (Get.transform.GetComponentInChildren()) askForMask = false; if (Get.transform.GetComponentInChildren() == null) askForMask = false; if (askForMask) { UnityEditor.EditorGUILayout.HelpBox("Not detected mask display component in the hierarchy.", UnityEditor.MessageType.Info); if (GUILayout.Button("Add Image mask and Display Rect")) { RectTransform getRect = Get.transform as RectTransform; GameObject mask = new GameObject("Minimap-Mask"); RectTransform r = mask.AddComponent(); r.SetParent(Get.transform, true); r.pivot = new Vector2(0, 1); r.anchoredPosition = Vector2.zero; r.localScale = Vector3.one; r.localRotation = Quaternion.identity; r.anchorMin = new Vector2(0, 0); r.anchorMax = new Vector2(1, 1); r.offsetMin = Vector2.zero; r.offsetMax = Vector2.zero; Image maskImg = mask.AddComponent(); maskImg.sprite = Get.DefaultMaskSprite; mask.AddComponent().showMaskGraphic = false; GameObject display = new GameObject("Minimap-Display"); Get.DisplayRect = display.AddComponent(); display.transform.SetParent(r, true); Get.DisplayRect.sizeDelta = new Vector2(100, 100); Get.DisplayRect.anchoredPosition = Vector2.zero; Get.DisplayRect.localScale = Vector3.one; Get.DisplayRect.localRotation = Quaternion.identity; Get.DisplayRect.pivot = new Vector2(0, 1); Get.DisplayRect.anchorMin = new Vector2(0, 1); Get.DisplayRect.anchorMax = new Vector2(0, 1); UnityEditor.EditorUtility.SetDirty(Get); } } } } } #endif #endregion }