#if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; namespace FIMSpace.Generating { [DefaultExecutionOrder(100)] [AddComponentMenu("FImpossible Creations/PGG/Minimap/PGG Minimap Display Controller")] public class PGG_MinimapDisplayController : MonoBehaviour { public PGG_MinimapHandler Handler; [Tooltip("Required to define center of view when following target object")] public RectTransform MapMaskedView; [Space(6)] public Transform ToFollow; [Tooltip("Offset following position in world units")] public Vector3 FollowOffset = Vector3.zero; [Tooltip("World Space Units to clamp-limit minimap movement to.\nWhen this value is greater than zero, you will see gizmos box on the scene in scale of provided world bounds below.")] public float ClampBorder = 0f; public Bounds BoundsForClamp; [Space(6)] [Range(0f, 1f)] public float FollowSpeed = 1f; [Space(1)] [Range(0f, 1f)] public float ZoomAnimateSpeed = 1f; [Space(1)] [Range(0f, 1f)] public float RotateAnimateSpeed = 1f; [Space(6)] [Tooltip("Apply debug input: Mouse scroll to controll zoom and 'Q' and 'E' keys for map rotation")] public bool TestInputForDebugging = true; /// You can change this variable for custom zoom clamp ranges [System.NonSerialized] public Vector2 ClampZoom = new Vector2(0.25f, 2f); Vector2 _sd_Follow = Vector2.zero; public Vector2 _Follow { get; private set; } float _sd_Zoom = 0f; float _TargetZoom = 1f; float _sd_Rotate = 0f; float _TargetRotation = 0f; float _CurrentZoom = 1f; float _CurrentRotation = 0f; float GetSmoothDampDuration(float speed) { return Mathf.InverseLerp(1f, 0.001f, speed); } void LateUpdate() { // Apply Zoom and rotation #region Support animating zoom / rotation smoothly if (ZoomAnimateSpeed > 0f) { if (ZoomAnimateSpeed < 1f) _CurrentZoom = Mathf.SmoothDamp(_CurrentZoom, _TargetZoom, ref _sd_Zoom, GetSmoothDampDuration(ZoomAnimateSpeed) * 0.5f, float.MaxValue, Time.deltaTime); else _CurrentZoom = _TargetZoom; } if (RotateAnimateSpeed > 0f) { if (RotateAnimateSpeed < 1f) _CurrentRotation = Mathf.SmoothDampAngle(_CurrentRotation, _TargetRotation, ref _sd_Rotate, GetSmoothDampDuration(RotateAnimateSpeed) * 0.3f, float.MaxValue, Time.deltaTime); else _CurrentRotation = _TargetRotation; } #endregion Handler.DisplayRect.localScale = new Vector3(_CurrentZoom, _CurrentZoom, 1f); Handler.DisplayRect.localRotation = Quaternion.Euler(0f, 0f, _CurrentRotation); if (FollowSpeed > 0f) if (ToFollow != null) { // Prepare world position to follow Vector3 followWorldPosition = ToFollow.position; if (ClampBorder > 0f) followWorldPosition = Handler.ClampFollowWorldPosition(BoundsForClamp, followWorldPosition, new Vector2(ClampBorder, ClampBorder), new Vector2(ClampBorder, ClampBorder)); followWorldPosition += FollowOffset; // Transform world position to UI display //float displayRatio = GetTextureToDisplayRatio(); Vector2 mapSpacePos = Handler.GetUIPosition(followWorldPosition); if (FollowSpeed >= 1f) _Follow = mapSpacePos; else _Follow = Vector2.SmoothDamp(_Follow, mapSpacePos, ref _sd_Follow, GetSmoothDampDuration(FollowSpeed), float.MaxValue, Time.deltaTime); // Apply zoom / rotation if using Vector2 finalFollowPos = _Follow; finalFollowPos *= _CurrentZoom; if (_CurrentRotation != 0f) finalFollowPos = Quaternion.Euler(0f, 0f, _CurrentRotation) * finalFollowPos; // Calculate and apply final UI position Vector2 viewCenterOffset = new Vector2(); viewCenterOffset.x = (MapMaskedView.rect.width * 0.5f); viewCenterOffset.y = (MapMaskedView.rect.height * -0.5f); //viewCenterOffset = Handler.GetUIPosition(viewCenterOffset); Vector2 targetMapPos = -finalFollowPos + viewCenterOffset; Handler.DisplayRect.anchoredPosition = targetMapPos; } if (TestInputForDebugging) { if (ZoomAnimateSpeed > 0f) { if (Input.mouseScrollDelta.y > 0.1f) ZoomInBy(0.1f); else if (Input.mouseScrollDelta.y < -0.1f) ZoomInBy(-0.1f); } if (RotateAnimateSpeed > 0f) { if (Input.GetKey(KeyCode.Q)) { RotateBy(-150f * Time.deltaTime); } if (Input.GetKey(KeyCode.E)) { RotateBy(150f * Time.deltaTime); } } } } public void ApplyZoom(float targetZoom = 1f) { _TargetZoom = Mathf.Clamp(targetZoom, ClampZoom.x, ClampZoom.y); } public void ZoomInBy(float zoomBy = 0.1f) { ApplyZoom(_TargetZoom + zoomBy * _TargetZoom); } public void RotateBy(float rotate) { ApplyMapRotate(_TargetRotation + rotate); } public void ApplyMapRotate(float targetRotation = 0f) { _TargetRotation = targetRotation; } #region Editor Code #if UNITY_EDITOR void OnDrawGizmosSelected() { if (ClampBorder <= 0f) return; Vector3 MapWorldCenter = BoundsForClamp.center; Vector3 MapWorldSize = BoundsForClamp.size; Gizmos.color = new Color(0.25f, 1f, 0.25f, 0.25f); Gizmos.DrawWireSphere(MapWorldCenter, 0.1f); Gizmos.DrawRay(MapWorldCenter - Vector3.right * 3f, Vector3.right * 6f); Gizmos.DrawRay(MapWorldCenter - Vector3.forward * 3f, Vector3.forward * 6f); Gizmos.DrawRay(MapWorldCenter - Vector3.up * 3f, Vector3.up * 6f); Gizmos.DrawWireCube(MapWorldCenter, MapWorldSize); Gizmos.color = new Color(0.25f, 1f, 0.25f, 0.05f); Gizmos.DrawCube(MapWorldCenter, MapWorldSize); Gizmos.color = new Color(1f, 0.4f, 0.1f, 0.3f); float tY = MapWorldCenter.y + 1f; Vector3 c1 = BoundsForClamp.max; c1.y = tY; Vector3 c2 = BoundsForClamp.max; c2.y = tY; Vector3 rf = -new Vector3(ClampBorder, 0f, ClampBorder ); Vector3 rb = -new Vector3(ClampBorder, 0f, -ClampBorder ); Vector3 lf = -new Vector3(-ClampBorder, 0f, ClampBorder ); Vector3 lb = -new Vector3(-ClampBorder, 0f, -ClampBorder ); c2.x = BoundsForClamp.min.x; Gizmos.DrawLine( c1 + rf , c2 + lf); c1 = BoundsForClamp.min; c1.y = tY; Gizmos.DrawLine( c1 + lb, c2 + lf); c2 = BoundsForClamp.max; c2.y = tY; c2.z = BoundsForClamp.min.z; Gizmos.DrawLine( c1 + lb, c2 + rb); c1 = BoundsForClamp.max; c1.y = tY; Gizmos.DrawLine( c1 + rf, c2 + rb); } #endif #endregion } #region Editor Class #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(PGG_MinimapDisplayController))] public class PGG_PixelMapDisplayHelperEditor : UnityEditor.Editor { public PGG_MinimapDisplayController Get { get { if (_get == null) _get = (PGG_MinimapDisplayController)target; return _get; } } private PGG_MinimapDisplayController _get; readonly string[] ignore = new string[] { "m_Script" }; readonly string[] ignoreClamp = new string[] { "m_Script", "BoundsForClamp" }; SerializedProperty sp_Handler; void OnEnable() { sp_Handler = serializedObject.FindProperty("Handler"); } public override void OnInspectorGUI() { serializedObject.Update(); if (Get.Handler == null) { EditorGUILayout.PropertyField(sp_Handler); GUILayout.Space(4); UnityEditor.EditorGUILayout.HelpBox("Minimap Handler is Required!", UnityEditor.MessageType.Info); serializedObject.ApplyModifiedProperties(); return; } DrawPropertiesExcluding(serializedObject, Get.ClampBorder > 0f ? ignore : ignoreClamp); serializedObject.ApplyModifiedProperties(); if (Get.ClampBorder < 0f) Get.ClampBorder = 0f; GUILayout.Space(4f); UnityEditor.EditorGUILayout.HelpBox("Handling minimap following target, minimap zoom and minimap rotation", UnityEditor.MessageType.Info); } } #endif #endregion }