Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / common / Utils.cs
@小李xl 小李xl on 20 Feb 2024 16 KB 弓箭功能开发中
  1. using System.Collections.Generic;
  2. using Godot;
  3. using UI.TileSetEditorCombination;
  4.  
  5. /// <summary>
  6. /// 常用函数工具类
  7. /// </summary>
  8. public static class Utils
  9. {
  10. /// <summary>
  11. /// 默认随机数对象
  12. /// </summary>
  13. public static SeedRandom Random { get; private set; }
  14. /// <summary>
  15. /// 初始化随机种子
  16. /// </summary>
  17. public static void InitRandom()
  18. {
  19. Random = new SeedRandom();
  20. Debug.Log("随机种子为: ", Random.Seed);
  21. }
  22.  
  23. /// <summary>
  24. /// 根据两个点计算出矩形
  25. /// </summary>
  26. public static Rect2 CalcRect(float start1, float end1, float start2, float end2)
  27. {
  28. return new Rect2(
  29. Mathf.Min(start1, start2), Mathf.Min(end1, end2),
  30. Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2)
  31. );
  32. }
  33. /// <summary>
  34. /// 根据两个点计算出矩形
  35. /// </summary>
  36. public static Rect2I CalcRect(int start1, int end1, int start2, int end2)
  37. {
  38. return new Rect2I(
  39. Mathf.Min(start1, start2), Mathf.Min(end1, end2),
  40. Mathf.Abs(start1 - start2), Mathf.Abs(end1 - end2)
  41. );
  42. }
  43. /// <summary>
  44. /// 返回碰撞层 mask 是否会检测 layer
  45. /// </summary>
  46. public static bool CollisionMaskWithLayer(uint mask, uint layer)
  47. {
  48. return (mask & layer) != 0;
  49. }
  50. /// <summary>
  51. /// 将一个任意角度转为0到360度
  52. /// </summary>
  53. public static float ConvertAngle(float angle)
  54. {
  55. angle %= 360; // 取余
  56.  
  57. if (angle < 0) // 如果角度为负数,转为正数
  58. {
  59. angle += 360;
  60. }
  61.  
  62. return angle;
  63. }
  64. /// <summary>
  65. /// 根据步长吸附值
  66. /// </summary>
  67. /// <param name="value">原数值</param>
  68. /// <param name="step">吸附步长</param>
  69. public static float Adsorption(this float value, float step)
  70. {
  71. var f = Mathf.Round(value / step);
  72. return f * step;
  73. }
  74. /// <summary>
  75. /// 根据步长吸附值
  76. /// </summary>
  77. /// <param name="value">原数值</param>
  78. /// <param name="step">吸附步长</param>
  79. public static int Adsorption(this float value, int step)
  80. {
  81. var f = Mathf.RoundToInt(value / step);
  82. return f * step;
  83. }
  84. /// <summary>
  85. /// 根据步长吸附值
  86. /// </summary>
  87. /// <param name="value">原数值</param>
  88. /// <param name="step">吸附步长</param>
  89. public static Vector2 Adsorption(this Vector2 value, Vector2 step)
  90. {
  91. var x = Mathf.Round(value.X / step.X);
  92. var y = Mathf.Round(value.Y / step.Y);
  93. return new Vector2(x * step.X, y * step.Y);
  94. }
  95. /// <summary>
  96. /// 根据步长吸附值
  97. /// </summary>
  98. /// <param name="value">原数值</param>
  99. /// <param name="step">吸附步长</param>
  100. public static Vector2I Adsorption(this Vector2 value, Vector2I step)
  101. {
  102. var x = Mathf.RoundToInt(value.X / step.X);
  103. var y = Mathf.RoundToInt(value.Y / step.Y);
  104. return new Vector2I(x * step.X, y * step.Y);
  105. }
  106. /// <summary>
  107. /// 根据步长按照 Floor() 函数吸附值
  108. /// </summary>
  109. /// <param name="value">原数值</param>
  110. /// <param name="step">吸附步长</param>
  111. public static float FloorAdsorption(this float value, float step)
  112. {
  113. var f = Mathf.Floor(value / step);
  114. return f * step;
  115. }
  116. /// <summary>
  117. /// 根据步长按照 Floor() 函数吸附值
  118. /// </summary>
  119. /// <param name="value">原数值</param>
  120. /// <param name="step">吸附步长</param>
  121. public static int FloorAdsorption(this float value, int step)
  122. {
  123. var f = Mathf.FloorToInt(value / step);
  124. return f * step;
  125. }
  126.  
  127. /// <summary>
  128. /// 根据步长按照 Floor() 函数吸附值
  129. /// </summary>
  130. /// <param name="value">原数值</param>
  131. /// <param name="step">吸附步长</param>
  132. public static Vector2 FloorAdsorption(this Vector2 value, Vector2 step)
  133. {
  134. var x = Mathf.Floor(value.X / step.X);
  135. var y = Mathf.Floor(value.Y / step.Y);
  136. return new Vector2(x * step.X, y * step.Y);
  137. }
  138. /// <summary>
  139. /// 根据步长按照 Floor() 函数吸附值
  140. /// </summary>
  141. /// <param name="value">原数值</param>
  142. /// <param name="step">吸附步长</param>
  143. public static Vector2I FloorAdsorption(this Vector2 value, Vector2I step)
  144. {
  145. var x = Mathf.FloorToInt(value.X / step.X);
  146. var y = Mathf.FloorToInt(value.Y / step.Y);
  147. return new Vector2I(x * step.X, y * step.Y);
  148. }
  149.  
  150. /// <summary>
  151. /// 字符串首字母小写
  152. /// </summary>
  153. public static string FirstToLower(this string str)
  154. {
  155. return str.Substring(0, 1).ToLower() + str.Substring(1);
  156. }
  157. /// <summary>
  158. /// 字符串首字母大写
  159. /// </summary>
  160. public static string FirstToUpper(this string str)
  161. {
  162. return str.Substring(0, 1).ToUpper() + str.Substring(1);
  163. }
  164.  
  165. /// <summary>
  166. /// 将 Vector2 类型转为 Vector2I 类型
  167. /// </summary>
  168. public static Vector2I AsVector2I(this Vector2 vector2)
  169. {
  170. return new Vector2I((int)vector2.X, (int)vector2.Y);
  171. }
  172.  
  173. /// <summary>
  174. /// 判断点是否在区域内
  175. /// </summary>
  176. public static bool IsPositionInRect(Vector2 pos, Rect2 rect2)
  177. {
  178. return pos.X >= rect2.Position.X && pos.X <= rect2.Position.X + rect2.Size.X &&
  179. pos.Y >= rect2.Position.Y && pos.Y <= rect2.Position.Y + rect2.Size.Y;
  180. }
  181.  
  182. /// <summary>
  183. /// 返回区域起始值, 用于获取配置表范围配置数据
  184. /// </summary>
  185. public static int GetConfigRangeStart(int[] range)
  186. {
  187. return range[0];
  188. }
  189. /// <summary>
  190. /// 返回区域结束值, 用于获取配置表范围配置数据
  191. /// </summary>
  192. public static int GetConfigRangeEnd(int[] range)
  193. {
  194. if (range.Length > 1)
  195. {
  196. return range[1];
  197. }
  198.  
  199. return range[0];
  200. }
  201. /// <summary>
  202. /// 返回区域起始值, 用于获取配置表范围配置数据
  203. /// </summary>
  204. public static float GetConfigRangeStart(float[] range)
  205. {
  206. return range[0];
  207. }
  208. /// <summary>
  209. /// 返回区域结束值, 用于获取配置表范围配置数据
  210. /// </summary>
  211. public static float GetConfigRangeEnd(float[] range)
  212. {
  213. if (range.Length > 1)
  214. {
  215. return range[1];
  216. }
  217.  
  218. return range[0];
  219. }
  220.  
  221. /// <summary>
  222. /// 创建扇形多边形区域数据, 返回坐标点
  223. /// </summary>
  224. /// <param name="centerAngle">中心角度, 角度制</param>
  225. /// <param name="radius">扇形半径</param>
  226. /// <param name="range">扇形开口角度, 角度制</param>
  227. /// <param name="edgesCount">扇形弧度边的数量</param>
  228. /// <param name="offset">整体偏移坐标, 默认0</param>
  229. public static Vector2[] CreateSectorPolygon(float centerAngle, float radius, float range, uint edgesCount, Vector2? offset = null)
  230. {
  231. var point = new Vector2[edgesCount + 2];
  232. var edgesAngle = range / edgesCount;
  233. var startAngle = centerAngle - range * 0.5f;
  234. var temp = new Vector2(radius, 0);
  235.  
  236. for (var i = 0; i <= edgesCount; i++)
  237. {
  238. if (offset == null)
  239. {
  240. point[i] = temp.Rotated(Mathf.DegToRad(startAngle + edgesAngle * i));
  241. }
  242. else
  243. {
  244. point[i] = temp.Rotated(Mathf.DegToRad(startAngle + edgesAngle * i)) + offset.Value;
  245. }
  246. }
  247.  
  248. if (offset == null)
  249. {
  250. point[point.Length - 1] = Vector2.Zero;
  251. }
  252. else
  253. {
  254. point[point.Length - 1] = offset.Value;
  255. }
  256. return point;
  257. }
  258.  
  259. /// <summary>
  260. /// 将 point 位置限制在 anchor 的周围, 最大距离为 distance, 并返回新的位置
  261. /// </summary>
  262. public static Vector2 ConstrainDistance(Vector2 point, Vector2 anchor, float distance)
  263. {
  264. return (point - anchor).Normalized() * distance + anchor;
  265. }
  266. /// <summary>
  267. /// 返回一个点是否在 Polygon 内部
  268. /// </summary>
  269. /// <param name="polygon">多边形顶点</param>
  270. /// <param name="point">目标点</param>
  271. public static bool IsPointInPolygon(Vector2[] polygon, Vector2 point)
  272. {
  273. var isInside = false;
  274. for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++)
  275. {
  276. if ((polygon[i].Y > point.Y) != (polygon[j].Y > point.Y) &&
  277. point.X < (polygon[j].X - polygon[i].X) * (point.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) +
  278. polygon[i].X)
  279. {
  280. isInside = !isInside;
  281. }
  282. }
  283.  
  284. return isInside;
  285. }
  286. /// <summary>
  287. /// 返回一个点是否在 Polygon 内部
  288. /// </summary>
  289. /// <param name="polygon">多边形顶点</param>
  290. /// <param name="point">目标点</param>
  291. public static bool IsPointInPolygon(List<Vector2> polygon, Vector2 point)
  292. {
  293. var isInside = false;
  294. for (int i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
  295. {
  296. if ((polygon[i].Y > point.Y) != (polygon[j].Y > point.Y) &&
  297. point.X < (polygon[j].X - polygon[i].X) * (point.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) +
  298. polygon[i].X)
  299. {
  300. isInside = !isInside;
  301. }
  302. }
  303.  
  304. return isInside;
  305. }
  306.  
  307. /// <summary>
  308. /// 根据法线翻转向量
  309. /// </summary>
  310. public static Vector2 ReflectByNormal(Vector2 vector, Vector2 normal)
  311. {
  312. return vector.Reflect(normal.Rotated(Mathf.Pi * 0.5f));
  313. }
  314. /// <summary>
  315. /// 根据法线翻转角度, 弧度制
  316. /// </summary>
  317. public static float ReflectByNormal(float rotation, Vector2 normal)
  318. {
  319. return ReflectByNormal(Vector2.FromAngle(rotation), normal).Angle();
  320. }
  321.  
  322. /// <summary>
  323. /// 计算Vector2点所占用的区域
  324. /// </summary>
  325. public static Rect2I CalcRect(IEnumerable<Vector2I> cells)
  326. {
  327. //单位: 像素
  328. var canvasXStart = int.MaxValue;
  329. var canvasYStart = int.MaxValue;
  330. var canvasXEnd = int.MinValue;
  331. var canvasYEnd = int.MinValue;
  332.  
  333. foreach (var pos in cells)
  334. {
  335. canvasXStart = Mathf.Min(pos.X, canvasXStart);
  336. canvasYStart = Mathf.Min(pos.Y, canvasYStart);
  337. canvasXEnd = Mathf.Max(pos.X + 1, canvasXEnd);
  338. canvasYEnd = Mathf.Max(pos.Y + 1, canvasYEnd);
  339. }
  340.  
  341. return new Rect2I(
  342. canvasXStart,
  343. canvasYStart,
  344. canvasXEnd - canvasXStart,
  345. canvasYEnd - canvasYStart
  346. );
  347. }
  348. /// <summary>
  349. /// 计算TileSet Cell所占用的区域
  350. /// </summary>
  351. public static Rect2I CalcTileRect(IEnumerable<Vector2I> cells)
  352. {
  353. //单位: 像素
  354. var canvasXStart = int.MaxValue;
  355. var canvasYStart = int.MaxValue;
  356. var canvasXEnd = int.MinValue;
  357. var canvasYEnd = int.MinValue;
  358.  
  359. foreach (var pos in cells)
  360. {
  361. canvasXStart = Mathf.Min(pos.X, canvasXStart);
  362. canvasYStart = Mathf.Min(pos.Y, canvasYStart);
  363. canvasXEnd = Mathf.Max(pos.X + GameConfig.TileCellSize, canvasXEnd);
  364. canvasYEnd = Mathf.Max(pos.Y + GameConfig.TileCellSize, canvasYEnd);
  365. }
  366.  
  367. return new Rect2I(
  368. canvasXStart,
  369. canvasYStart,
  370. canvasXEnd - canvasXStart,
  371. canvasYEnd - canvasYStart
  372. );
  373. }
  374. /// <summary>
  375. /// 计算TileSet Cell所占用的区域
  376. /// </summary>
  377. public static Rect2I CalcTileRect(IEnumerable<SerializeVector2> cells)
  378. {
  379. //单位: 像素
  380. var canvasXStart = float.MaxValue;
  381. var canvasYStart = float.MaxValue;
  382. var canvasXEnd = float.MinValue;
  383. var canvasYEnd = float.MinValue;
  384.  
  385. foreach (var pos in cells)
  386. {
  387. canvasXStart = Mathf.Min(pos.X, canvasXStart);
  388. canvasYStart = Mathf.Min(pos.Y, canvasYStart);
  389. canvasXEnd = Mathf.Max(pos.X + GameConfig.TileCellSize, canvasXEnd);
  390. canvasYEnd = Mathf.Max(pos.Y + GameConfig.TileCellSize, canvasYEnd);
  391. }
  392.  
  393. return new Rect2I(
  394. (int)canvasXStart,
  395. (int)canvasYStart,
  396. (int)(canvasXEnd - canvasXStart),
  397. (int)(canvasYEnd - canvasYStart)
  398. );
  399. }
  400.  
  401. /// <summary>
  402. /// 根据鼠标位置执行单步放大逻辑
  403. /// </summary>
  404. public static bool DoMagnifyByMousePosition(Control control, float maxXScale)
  405. {
  406. var offset = control.GetLocalMousePosition();
  407. var prevScale = control.Scale;
  408. var newScale = prevScale * 1.1f;
  409. if (newScale.X <= maxXScale)
  410. {
  411. control.Scale = newScale;
  412. var position = control.Position - offset * 0.1f * prevScale;
  413. control.Position = position;
  414. return true;
  415. }
  416.  
  417. return false;
  418. }
  419. /// <summary>
  420. /// 根据鼠标位置执行单步放大逻辑
  421. /// </summary>
  422. public static bool DoMagnifyByMousePosition(Node2D node, float maxXScale)
  423. {
  424. var offset = node.GetLocalMousePosition();
  425. var prevScale = node.Scale;
  426. var newScale = prevScale * 1.1f;
  427. if (newScale.X <= maxXScale)
  428. {
  429. node.Scale = newScale;
  430. var position = node.Position - offset * 0.1f * prevScale;
  431. node.Position = position;
  432. return true;
  433. }
  434.  
  435. return false;
  436. }
  437.  
  438. /// <summary>
  439. /// 根据鼠标位置执行单步缩小逻辑
  440. /// </summary>
  441. public static bool DoShrinkByMousePosition(Control control, float minXScale)
  442. {
  443. var offset = control.GetLocalMousePosition();
  444. var prevScale = control.Scale;
  445. var newScale = prevScale / 1.1f;
  446. if (newScale.X >= minXScale)
  447. {
  448. control.Scale = newScale;
  449. var position = control.Position + offset * 0.1f * newScale;
  450. control.Position = position;
  451. return true;
  452. }
  453.  
  454. return false;
  455. }
  456. /// <summary>
  457. /// 根据鼠标位置执行单步缩小逻辑
  458. /// </summary>
  459. public static bool DoShrinkByMousePosition(Node2D node, float minXScale)
  460. {
  461. var offset = node.GetLocalMousePosition();
  462. var prevScale = node.Scale;
  463. var newScale = prevScale / 1.1f;
  464. if (newScale.X >= minXScale)
  465. {
  466. node.Scale = newScale;
  467. var position = node.Position + offset * 0.1f * newScale;
  468. node.Position = position;
  469. return true;
  470. }
  471.  
  472. return false;
  473. }
  474.  
  475. /// <summary>
  476. /// 聚焦Ui节点
  477. /// </summary>
  478. /// <param name="control">需要聚焦的节点</param>
  479. /// <param name="parentSize">父节点容器大小</param>
  480. /// <param name="selfSize">当前节点容器大小</param>
  481. public static void DoFocusNode(Control control, Vector2 parentSize, Vector2 selfSize)
  482. {
  483. control.Position = parentSize / 2 - selfSize * 0.5f * control.Scale;
  484. }
  485.  
  486. /// <summary>
  487. /// 返回鼠标所在的单元格位置, 相对于Ui节点左上角
  488. /// </summary>
  489. public static Vector2I GetMouseCellPosition(CanvasItem control)
  490. {
  491. var pos = control.GetLocalMousePosition() / GameConfig.TileCellSize;
  492. return pos.AsVector2I();
  493. }
  494.  
  495. /// <summary>
  496. /// 创建一个数组, 并填充该对象
  497. /// </summary>
  498. public static T[] MakeArray<T>(this T data, int len)
  499. {
  500. var arr = new T[len];
  501. for (var i = 0; i < len; i++)
  502. {
  503. arr[i] = data;
  504. }
  505. return arr;
  506. }
  507.  
  508. /// <summary>
  509. /// 根据金币数量获取金币对象id数组
  510. /// </summary>
  511. public static string[] GetGoldList(int gold)
  512. {
  513. var list = new List<string>();
  514. while (gold > 0)
  515. {
  516. if (gold >= 10)
  517. {
  518. list.Add(ActivityObject.Ids.Id_gold_10);
  519. gold -= 10;
  520. }
  521. else if (gold >= 5)
  522. {
  523. list.Add(ActivityObject.Ids.Id_gold_5);
  524. gold -= 5;
  525. }
  526. else
  527. {
  528. list.Add(ActivityObject.Ids.Id_gold_1);
  529. gold -= 1;
  530. }
  531. }
  532. return list.ToArray();
  533. }
  534. }