1
0

MapGridControl.xaml.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. using System.Numerics;
  2. using Robust.Client.AutoGenerated;
  3. using Robust.Client.Graphics;
  4. using Robust.Client.ResourceManagement;
  5. using Robust.Client.UserInterface;
  6. using Robust.Client.UserInterface.Controls;
  7. using Robust.Client.UserInterface.XAML;
  8. using Robust.Shared.Input;
  9. using Robust.Shared.Timing;
  10. namespace Content.Client.UserInterface.Controls;
  11. /// <summary>
  12. /// Handles generic grid-drawing data, with zoom and dragging.
  13. /// </summary>
  14. [GenerateTypedNameReferences]
  15. [Virtual]
  16. public partial class MapGridControl : LayoutContainer
  17. {
  18. [Dependency] protected readonly IEntityManager EntManager = default!;
  19. [Dependency] protected readonly IGameTiming Timing = default!;
  20. protected static readonly Color BackingColor = new Color(0.08f, 0.08f, 0.08f);
  21. private Font _largerFont;
  22. /* Dragging */
  23. protected virtual bool Draggable { get; } = false;
  24. /// <summary>
  25. /// Control offset from whatever is being tracked.
  26. /// </summary>
  27. public Vector2 Offset;
  28. /// <summary>
  29. /// If the control is being recentered what is the target offset to reach.
  30. /// </summary>
  31. public Vector2 TargetOffset;
  32. private bool _draggin;
  33. protected Vector2 StartDragPosition;
  34. protected bool Recentering;
  35. protected const float ScrollSensitivity = 8f;
  36. protected float RecenterMinimum = 0.05f;
  37. /// <summary>
  38. /// UI pixel radius.
  39. /// </summary>
  40. public const int UIDisplayRadius = 320;
  41. protected const int MinimapMargin = 4;
  42. protected float WorldMinRange;
  43. protected float WorldMaxRange;
  44. public float WorldRange;
  45. public Vector2 WorldRangeVector => new Vector2(WorldRange, WorldRange);
  46. /// <summary>
  47. /// We'll lerp between the radarrange and actual range
  48. /// </summary>
  49. protected float ActualRadarRange;
  50. protected float CornerRadarRange => MathF.Sqrt(ActualRadarRange * ActualRadarRange + ActualRadarRange * ActualRadarRange) * 1.1f;
  51. /// <summary>
  52. /// Controls the maximum distance that will display.
  53. /// </summary>
  54. public float MaxRadarRange { get; private set; } = 256f * 10f;
  55. public Vector2 MaxRadarRangeVector => new Vector2(MaxRadarRange, MaxRadarRange);
  56. protected Vector2 MidPointVector => new Vector2(MidPoint, MidPoint);
  57. protected int MidPoint => SizeFull / 2;
  58. protected int SizeFull => (int) ((UIDisplayRadius + MinimapMargin) * 2 * UIScale);
  59. protected int ScaledMinimapRadius => (int) (UIDisplayRadius * UIScale);
  60. protected float MinimapScale => WorldRange != 0 ? ScaledMinimapRadius / WorldRange : 0f;
  61. public event Action<float>? WorldRangeChanged;
  62. public MapGridControl() : this(32f, 32f, 32f) {}
  63. public MapGridControl(float minRange, float maxRange, float range)
  64. {
  65. RobustXamlLoader.Load(this);
  66. IoCManager.InjectDependencies(this);
  67. SetSize = new Vector2(SizeFull, SizeFull);
  68. RectClipContent = true;
  69. MouseFilter = MouseFilterMode.Stop;
  70. ActualRadarRange = WorldRange;
  71. WorldMinRange = minRange;
  72. WorldMaxRange = maxRange;
  73. WorldRange = range;
  74. ActualRadarRange = range;
  75. var cache = IoCManager.Resolve<IResourceCache>();
  76. _largerFont = new VectorFont(cache.GetResource<FontResource>("/EngineFonts/NotoSans/NotoSans-Regular.ttf"), 16);
  77. }
  78. public void ForceRecenter()
  79. {
  80. Recentering = true;
  81. }
  82. protected override void KeyBindDown(GUIBoundKeyEventArgs args)
  83. {
  84. base.KeyBindDown(args);
  85. if (!Draggable)
  86. return;
  87. if (args.Function == EngineKeyFunctions.Use)
  88. {
  89. StartDragPosition = args.PointerLocation.Position;
  90. _draggin = true;
  91. }
  92. }
  93. protected override void KeyBindUp(GUIBoundKeyEventArgs args)
  94. {
  95. if (!Draggable)
  96. return;
  97. if (args.Function == EngineKeyFunctions.Use)
  98. _draggin = false;
  99. }
  100. protected override void MouseMove(GUIMouseMoveEventArgs args)
  101. {
  102. base.MouseMove(args);
  103. if (!_draggin)
  104. return;
  105. Recentering = false;
  106. Offset -= new Vector2(args.Relative.X, -args.Relative.Y) / MidPoint * WorldRange;
  107. }
  108. protected override void MouseWheel(GUIMouseWheelEventArgs args)
  109. {
  110. base.MouseWheel(args);
  111. AddRadarRange(-args.Delta.Y * 1f / ScrollSensitivity * ActualRadarRange);
  112. }
  113. public void AddRadarRange(float value)
  114. {
  115. ActualRadarRange = Math.Clamp(ActualRadarRange + value, WorldMinRange, WorldMaxRange);
  116. }
  117. /// <summary>
  118. /// Converts map coordinates to the local control.
  119. /// </summary>
  120. protected Vector2 ScalePosition(Vector2 value)
  121. {
  122. return ScalePosition(value, MinimapScale, MidPointVector);
  123. }
  124. protected static Vector2 ScalePosition(Vector2 value, float minimapScale, Vector2 midpointVector)
  125. {
  126. return value * minimapScale + midpointVector;
  127. }
  128. /// <summary>
  129. /// Converts local coordinates on the control to map coordinates.
  130. /// </summary>
  131. protected Vector2 InverseMapPosition(Vector2 value)
  132. {
  133. var inversePos = (value - MidPointVector) / MinimapScale;
  134. inversePos = inversePos with { Y = -inversePos.Y };
  135. inversePos = Vector2.Transform(inversePos, Matrix3Helpers.CreateTransform(Offset, Angle.Zero));
  136. return inversePos;
  137. }
  138. /// <summary>
  139. /// Handles re-centering the control's offset.
  140. /// </summary>
  141. /// <returns></returns>
  142. public bool DrawRecenter()
  143. {
  144. // Map re-centering
  145. if (Recentering)
  146. {
  147. var frameTime = Timing.FrameTime;
  148. var diff = (TargetOffset - Offset) * (float) frameTime.TotalSeconds;
  149. if (Offset.LengthSquared() < RecenterMinimum)
  150. {
  151. Offset = TargetOffset;
  152. Recentering = false;
  153. }
  154. else
  155. {
  156. Offset += diff * 5f;
  157. return false;
  158. }
  159. }
  160. return Offset == TargetOffset;
  161. }
  162. protected void DrawBacking(DrawingHandleScreen handle)
  163. {
  164. var backing = BackingColor;
  165. handle.DrawRect(PixelSizeBox, backing);
  166. }
  167. protected void DrawNoSignal(DrawingHandleScreen handle)
  168. {
  169. var greyColor = Color.FromHex("#474F52");
  170. // Draw funny lines
  171. var lineCount = 4f;
  172. for (var i = 0; i < lineCount; i++)
  173. {
  174. var angle = Angle.FromDegrees(45 + i * 360f / lineCount);
  175. var distance = Width / 2f;
  176. var start = MidPointVector + angle.RotateVec(new Vector2(0f, 2.5f * distance / 4f));
  177. var end = MidPointVector + angle.RotateVec(new Vector2(0f, 4f * distance / 4f));
  178. handle.DrawLine(start, end, greyColor);
  179. }
  180. var signalText = Loc.GetString("shuttle-console-no-signal");
  181. var dimensions = handle.GetDimensions(_largerFont, signalText, 1f);
  182. var position = MidPointVector - dimensions / 2f;
  183. handle.DrawString(_largerFont, position, Loc.GetString("shuttle-console-no-signal"), greyColor);
  184. }
  185. protected override void Draw(DrawingHandleScreen handle)
  186. {
  187. base.Draw(handle);
  188. if (!ActualRadarRange.Equals(WorldRange))
  189. {
  190. var diff = ActualRadarRange - WorldRange;
  191. const float lerpRate = 10f;
  192. WorldRange += (float) Math.Clamp(diff, -lerpRate * MathF.Abs(diff) * Timing.FrameTime.TotalSeconds, lerpRate * MathF.Abs(diff) * Timing.FrameTime.TotalSeconds);
  193. WorldRangeChanged?.Invoke(WorldRange);
  194. }
  195. }
  196. }