Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / common / Utils.cs
  1. using Godot;
  2.  
  3. /// <summary>
  4. /// 常用函数工具类
  5. /// </summary>
  6. public static class Utils
  7. {
  8. /// <summary>
  9. /// 默认随机数对象
  10. /// </summary>
  11. public static SeedRandom Random { get; }
  12. static Utils()
  13. {
  14. Random = new SeedRandom();
  15. Debug.Log("随机种子为: ", Random.Seed);
  16. }
  17.  
  18. /// <summary>
  19. /// 根据两个点计算出矩形
  20. /// </summary>
  21. public static Rect2 CalcRect(float start1, float end1, float start2, float end2)
  22. {
  23. return new Rect2(
  24. Mathf.Min(start1, start2), Mathf.Min(end1, end2),
  25. Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2)
  26. );
  27. }
  28. /// <summary>
  29. /// 根据两个点计算出矩形
  30. /// </summary>
  31. public static Rect2I CalcRect(int start1, int end1, int start2, int end2)
  32. {
  33. return new Rect2I(
  34. Mathf.Min(start1, start2), Mathf.Min(end1, end2),
  35. Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2)
  36. );
  37. }
  38. /// <summary>
  39. /// 返回碰撞层 mask 是否会检测 layer
  40. /// </summary>
  41. public static bool CollisionMaskWithLayer(uint mask, uint layer)
  42. {
  43. return (mask & layer) != 0;
  44. }
  45.  
  46. /// <summary>
  47. /// 使用定的 canvasItem 绘制导航区域, 注意, 该函数只能在 draw 函数中调用
  48. /// </summary>
  49. public static void DrawNavigationPolygon(CanvasItem canvasItem, NavigationPolygonData[] polygonData, float width = 1)
  50. {
  51. for (var i = 0; i < polygonData.Length; i++)
  52. {
  53. var item = polygonData[i];
  54. var points = item.GetPoints();
  55. if (points.Length>= 2)
  56. {
  57. var array = new Vector2[points.Length + 1];
  58. for (var j = 0; j < points.Length; j++)
  59. {
  60. array[j] = points[j];
  61. }
  62.  
  63. array[array.Length - 1] = points[0];
  64. if (item.Type == NavigationPolygonType.In)
  65. {
  66. canvasItem.DrawPolyline(array, Colors.Orange, width);
  67. }
  68. else
  69. {
  70. canvasItem.DrawPolyline(array, Colors.Orange, width);
  71. }
  72. }
  73. }
  74. }
  75. /// <summary>
  76. /// 将一个任意角度转为0到360度
  77. /// </summary>
  78. public static float ConvertAngle(float angle)
  79. {
  80. angle %= 360; // 取余
  81.  
  82. if (angle < 0) // 如果角度为负数,转为正数
  83. {
  84. angle += 360;
  85. }
  86.  
  87. return angle;
  88. }
  89. /// <summary>
  90. /// 根据步长吸附值
  91. /// </summary>
  92. /// <param name="value">原数值</param>
  93. /// <param name="step">吸附步长</param>
  94. public static float Adsorption(float value, float step)
  95. {
  96. var f = Mathf.Round(value / step);
  97. return f * step;
  98. }
  99. /// <summary>
  100. /// 根据步长吸附值
  101. /// </summary>
  102. /// <param name="value">原数值</param>
  103. /// <param name="step">吸附步长</param>
  104. public static int Adsorption(float value, int step)
  105. {
  106. var f = Mathf.RoundToInt(value / step);
  107. return f * step;
  108. }
  109. /// <summary>
  110. /// 根据步长吸附值
  111. /// </summary>
  112. /// <param name="value">原数值</param>
  113. /// <param name="step">吸附步长</param>
  114. public static Vector2 Adsorption(Vector2 value, Vector2 step)
  115. {
  116. var x = Mathf.Round(value.X / step.X);
  117. var y = Mathf.Round(value.Y / step.Y);
  118. return new Vector2(x * step.X, y * step.Y);
  119. }
  120. /// <summary>
  121. /// 根据步长吸附值
  122. /// </summary>
  123. /// <param name="value">原数值</param>
  124. /// <param name="step">吸附步长</param>
  125. public static Vector2I Adsorption(Vector2 value, Vector2I step)
  126. {
  127. var x = Mathf.RoundToInt(value.X / step.X);
  128. var y = Mathf.RoundToInt(value.Y / step.Y);
  129. return new Vector2I(x * step.X, y * step.Y);
  130. }
  131.  
  132. /// <summary>
  133. /// 字符串首字母小写
  134. /// </summary>
  135. public static string FirstToLower(this string str)
  136. {
  137. return str.Substring(0, 1).ToLower() + str.Substring(1);
  138. }
  139. /// <summary>
  140. /// 字符串首字母大写
  141. /// </summary>
  142. public static string FirstToUpper(this string str)
  143. {
  144. return str.Substring(0, 1).ToUpper() + str.Substring(1);
  145. }
  146.  
  147. /// <summary>
  148. /// 将 Vector2 类型转为 Vector2I 类型
  149. /// </summary>
  150. public static Vector2I AsVector2I(this Vector2 vector2)
  151. {
  152. return new Vector2I((int)vector2.X, (int)vector2.Y);
  153. }
  154.  
  155. /// <summary>
  156. /// 返回指定坐标是否在UI节范围点内
  157. /// </summary>
  158. public static bool IsPositionOver(this Control control, Vector2 position)
  159. {
  160. var globalPosition = control.GlobalPosition;
  161. var size = control.Size * control.Scale;
  162. return position.X >= globalPosition.X && position.X <= (globalPosition.X + size.X) &&
  163. position.Y >= globalPosition.Y && position.Y <= (globalPosition.Y + size.Y);
  164. }
  165.  
  166. /// <summary>
  167. /// 判断点是否在区域内
  168. /// </summary>
  169. public static bool IsPositionInRect(Vector2 pos, Rect2 rect2)
  170. {
  171. return pos.X >= rect2.Position.X && pos.X <= rect2.Position.X + rect2.Size.X &&
  172. pos.Y >= rect2.Position.Y && pos.Y <= rect2.Position.Y + rect2.Size.Y;
  173. }
  174.  
  175. /// <summary>
  176. /// 返回区域起始值, 用于获取配置表范围配置数据
  177. /// </summary>
  178. public static int GetConfigRangeStart(int[] range)
  179. {
  180. return range[0];
  181. }
  182. /// <summary>
  183. /// 返回区域结束值, 用于获取配置表范围配置数据
  184. /// </summary>
  185. public static int GetConfigRangeEnd(int[] range)
  186. {
  187. if (range.Length > 1)
  188. {
  189. return range[1];
  190. }
  191.  
  192. return range[0];
  193. }
  194. /// <summary>
  195. /// 返回区域起始值, 用于获取配置表范围配置数据
  196. /// </summary>
  197. public static float GetConfigRangeStart(float[] range)
  198. {
  199. return range[0];
  200. }
  201. /// <summary>
  202. /// 返回区域结束值, 用于获取配置表范围配置数据
  203. /// </summary>
  204. public static float GetConfigRangeEnd(float[] range)
  205. {
  206. if (range.Length > 1)
  207. {
  208. return range[1];
  209. }
  210.  
  211. return range[0];
  212. }
  213.  
  214. /// <summary>
  215. /// 创建扇形多边形区域数据, 返回坐标点
  216. /// </summary>
  217. /// <param name="centerAngle">中心角度, 角度制</param>
  218. /// <param name="radius">扇形半径</param>
  219. /// <param name="range">扇形开口角度, 角度制</param>
  220. /// <param name="edgesCount">扇形弧度边的数量</param>
  221. /// <param name="offset">整体偏移坐标, 默认0</param>
  222. public static Vector2[] CreateSectorPolygon(float centerAngle, float radius, float range, uint edgesCount, Vector2? offset = null)
  223. {
  224. var point = new Vector2[edgesCount + 2];
  225. var edgesAngle = range / edgesCount;
  226. var startAngle = centerAngle - range * 0.5f;
  227. var temp = new Vector2(radius, 0);
  228.  
  229. for (var i = 0; i <= edgesCount; i++)
  230. {
  231. if (offset == null)
  232. {
  233. point[i] = temp.Rotated(Mathf.DegToRad(startAngle + edgesAngle * i));
  234. }
  235. else
  236. {
  237. point[i] = temp.Rotated(Mathf.DegToRad(startAngle + edgesAngle * i)) + offset.Value;
  238. }
  239. }
  240.  
  241. if (offset == null)
  242. {
  243. point[point.Length - 1] = Vector2.Zero;
  244. }
  245. else
  246. {
  247. point[point.Length - 1] = offset.Value;
  248. }
  249. return point;
  250. }
  251.  
  252. /// <summary>
  253. /// 将 point 位置限制在 anchor 的周围, 最大距离为 distance, 并返回新的位置
  254. /// </summary>
  255. public static Vector2 ConstrainDistance(Vector2 point, Vector2 anchor, float distance)
  256. {
  257. return (point - anchor).Normalized() * distance + anchor;
  258. }
  259. /// <summary>
  260. /// 返回一个点是否在 Polygon 内部
  261. /// </summary>
  262. /// <param name="polygon">多边形顶点</param>
  263. /// <param name="point">目标点</param>
  264. public static bool IsPointInPolygon(Vector2[] polygon, Vector2 point)
  265. {
  266. var isInside = false;
  267. for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
  268. {
  269. if ((polygon[i].Y > point.Y) != (polygon[j].Y > point.Y) &&
  270. point.X < (polygon[j].X - polygon[i].X) * (point.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) +
  271. polygon[i].X)
  272. {
  273. isInside = !isInside;
  274. }
  275. }
  276.  
  277. return isInside;
  278. }
  279. }