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